diff -uprN -x *.o ../src/.cvsignore ./.cvsignore
--- ../src/.cvsignore	Tue Oct 28 23:16:17 1997
+++ ./.cvsignore	Wed Dec 31 18:00:00 1969
@@ -1,3 +0,0 @@
-conf.h
-.accepted
-Makefile
diff -uprN -x *.o ../src/Makefile ./Makefile
--- ../src/Makefile	Mon Dec 29 21:57:42 1997
+++ ./Makefile	Mon Dec 29 21:36:24 1997
@@ -93,13 +93,13 @@ ref:
 # gcc -MM)
 
 act.comm.o: act.comm.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h \
-  handler.h db.h screen.h
+  handler.h db.h screen.h boards.h
 	$(CC) -c $(CFLAGS) act.comm.c
 act.informative.o: act.informative.c conf.h sysdep.h structs.h utils.h comm.h \
-  interpreter.h handler.h db.h spells.h screen.h
+  interpreter.h handler.h db.h spells.h screen.h boards.h
 	$(CC) -c $(CFLAGS) act.informative.c
 act.item.o: act.item.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h \
-  handler.h db.h spells.h
+  handler.h db.h spells.h boards.h
 	$(CC) -c $(CFLAGS) act.item.c
 act.movement.o: act.movement.c conf.h sysdep.h structs.h utils.h comm.h \
   interpreter.h handler.h db.h spells.h house.h
@@ -134,7 +134,7 @@ config.o: config.c conf.h sysdep.h struc
 constants.o: constants.c conf.h sysdep.h structs.h
 	$(CC) -c $(CFLAGS) constants.c
 db.o: db.c conf.h sysdep.h structs.h utils.h db.h comm.h handler.h spells.h mail.h \
-  interpreter.h house.h
+  interpreter.h house.h boards.h
 	$(CC) -c $(CFLAGS) db.c
 fight.o: fight.c conf.h sysdep.h structs.h utils.h comm.h handler.h interpreter.h \
   db.h spells.h screen.h
@@ -163,7 +163,7 @@ mobact.o: mobact.c conf.h sysdep.h struc
   handler.h spells.h
 	$(CC) -c $(CFLAGS) mobact.c
 modify.o: modify.c conf.h sysdep.h structs.h utils.h interpreter.h handler.h db.h \
-  comm.h spells.h mail.h boards.h olc.h
+  comm.h spells.h mail.h boards.h olc.h 
 	$(CC) -c $(CFLAGS) modify.c
 objsave.o: objsave.c conf.h sysdep.h structs.h comm.h handler.h db.h \
   interpreter.h utils.h spells.h
@@ -198,7 +198,7 @@ redit.o: redit.c conf.h sysdep.h structs
   db.c olc.h
 	$(CC) -c $(CFLAGS) redit.c
 oedit.o: oedit.c conf.h sysdep.h structs.h utils.h comm.h boards.h spells.h \
-  db.h olc.h shop.h
+  db.h olc.h shop.h 
 	$(CC) -c $(CFLAGS) oedit.c
 zedit.o: zedit.c conf.h sysdep.h structs.h utils.h comm.h db.h olc.h
 	$(CC) -c $(CFLAGS) zedit.c 
diff -uprN -x *.o ../src/act.comm.c ./act.comm.c
--- ../src/act.comm.c	Mon Dec 29 21:57:42 1997
+++ ./act.comm.c	Mon Dec 29 21:36:24 1997
@@ -19,11 +19,13 @@
 #include "handler.h"
 #include "db.h"
 #include "screen.h"
+#include "boards.h"
 
 /* extern variables */
 extern struct room_data *world;
 extern struct descriptor_data *descriptor_list;
 extern struct char_data *character_list;
+extern struct index_data *obj_index;
 
 ACMD(do_say)
 {
@@ -204,61 +206,80 @@ ACMD(do_spec_comm)
 
 ACMD(do_write)
 {
-  struct obj_data *paper = 0, *pen = 0;
+  struct obj_data *paper = 0, *pen = 0, *obj;
   char *papername, *penname;
 
-  papername = buf1;
-  penname = buf2;
+  /* before we do anything, lets see if there's a board involved. */
+  for (obj = ch->carrying; obj;obj=obj->next_content) {
+    if(GET_OBJ_TYPE(obj) == ITEM_BOARD) {
+      break;
+    }
+  }
+  if(!obj) {
 
-  two_arguments(argument, papername, penname);
+    for (obj = world[ch->in_room].contents; obj;obj=obj->next_content) {
+      if(GET_OBJ_TYPE(obj) == ITEM_BOARD) {
+        break;
+      }
+    }
+  }
+  if(obj) {                /* then there IS a board! */
+    Board_write_message(GET_OBJ_VNUM(obj),ch,argument);
+  }
+  else {
+    papername = buf1;
+    penname = buf2;
 
-  if (!ch->desc)
-    return;
+    two_arguments(argument, papername, penname);
 
-  if (!*papername) {		/* nothing was delivered */
-    send_to_char("Write?  With what?  ON what?  What are you trying to do?!?\r\n", ch);
-    return;
-  }
-  if (*penname) {		/* there were two arguments */
-    if (!(paper = get_obj_in_list_vis(ch, papername, ch->carrying))) {
-      sprintf(buf, "You have no %s.\r\n", papername);
-      send_to_char(buf, ch);
-      return;
-    }
-    if (!(pen = get_obj_in_list_vis(ch, penname, ch->carrying))) {
-      sprintf(buf, "You have no %s.\r\n", penname);
-      send_to_char(buf, ch);
+    if (!ch->desc)
       return;
-    }
-  } else {		/* there was one arg.. let's see what we can find */
-    if (!(paper = get_obj_in_list_vis(ch, papername, ch->carrying))) {
-      sprintf(buf, "There is no %s in your inventory.\r\n", papername);
-      send_to_char(buf, ch);
-      return;
-    }
-    if (GET_OBJ_TYPE(paper) == ITEM_PEN) {	/* oops, a pen.. */
-      pen = paper;
-      paper = 0;
-    } else if (GET_OBJ_TYPE(paper) != ITEM_NOTE) {
-      send_to_char("That thing has nothing to do with writing.\r\n", ch);
+
+    if (!*papername) {		/* nothing was delivered */
+      send_to_char("Write?  With what?  ON what?  What are you trying to do?!?\r\n", ch);
       return;
     }
-    /* One object was found.. now for the other one. */
-    if (!GET_EQ(ch, WEAR_HOLD)) {
-      sprintf(buf, "You can't write with %s %s alone.\r\n", AN(papername),
+    if (*penname) {		/* there were two arguments */
+      if (!(paper = get_obj_in_list_vis(ch, papername, ch->carrying))) {
+        sprintf(buf, "You have no %s.\r\n", papername);
+        send_to_char(buf, ch);
+        return;
+      }
+      if (!(pen = get_obj_in_list_vis(ch, penname, ch->carrying))) {
+        sprintf(buf, "You have no %s.\r\n", penname);
+        send_to_char(buf, ch);
+        return;
+      }
+    } else {		/* there was one arg.. let's see what we can find */
+      if (!(paper = get_obj_in_list_vis(ch, papername, ch->carrying))) {
+        sprintf(buf, "There is no %s in your inventory.\r\n", papername);
+        send_to_char(buf, ch);
+        return;
+      }
+      if (GET_OBJ_TYPE(paper) == ITEM_PEN) {	/* oops, a pen.. */
+        pen = paper;
+        paper = 0; 
+      } else if (GET_OBJ_TYPE(paper) != ITEM_NOTE) {
+        send_to_char("That thing has nothing to do with writing.\r\n", ch);
+        return;
+      }
+      /* One object was found.. now for the other one. */
+      if (!GET_EQ(ch, WEAR_HOLD)) {
+        sprintf(buf, "You can't write with %s %s alone.\r\n", AN(papername),
 	      papername);
-      send_to_char(buf, ch);
-      return;
-    }
-    if (!CAN_SEE_OBJ(ch, GET_EQ(ch, WEAR_HOLD))) {
-      send_to_char("The stuff in your hand is invisible!  Yeech!!\r\n", ch);
-      return;
-    }
-    if (pen)
-      paper = GET_EQ(ch, WEAR_HOLD);
-    else
-      pen = GET_EQ(ch, WEAR_HOLD);
-  }
+        send_to_char(buf, ch);
+        return;
+      }
+      if (!CAN_SEE_OBJ(ch, GET_EQ(ch, WEAR_HOLD))) {
+        send_to_char("The stuff in your hand is invisible!  Yeech!!\r\n", ch);
+        return;
+      }
+      if (pen)
+        paper = GET_EQ(ch, WEAR_HOLD);
+      else
+        pen = GET_EQ(ch, WEAR_HOLD);
+  
+  } 
 
 
   /* ok.. now let's see what kind of stuff we've found */
@@ -291,6 +312,7 @@ ACMD(do_write)
     ch->desc->str = &paper->action_description;
     ch->desc->max_str = MAX_NOTE_LENGTH;
   }
+ }
 }
 
 
diff -uprN -x *.o ../src/act.informative.c ./act.informative.c
--- ../src/act.informative.c	Tue Oct 28 23:16:21 1997
+++ ./act.informative.c	Mon Dec 29 21:36:24 1997
@@ -19,6 +19,7 @@
 #include "db.h"
 #include "spells.h"
 #include "screen.h"
+#include "boards.h"
 
 /* extern variables */
 extern struct room_data *world;
@@ -26,6 +27,7 @@ extern struct descriptor_data *descripto
 extern struct char_data *character_list;
 extern struct obj_data *object_list;
 extern struct command_info cmd_info[];
+extern struct index_data *obj_index;
 
 extern char *credits;
 extern char *news;
@@ -71,6 +73,8 @@ void show_obj_to_char(struct obj_data * 
       } else
 	act("It's blank.", FALSE, ch, 0, 0, TO_CHAR);
       return;
+    } else if (GET_OBJ_TYPE(object) == ITEM_BOARD) {
+              Board_show_board(GET_OBJ_VNUM(object), ch);
     } else if (GET_OBJ_TYPE(object) != ITEM_DRINKCON) {
       strcpy(buf, "You see nothing special..");
     } else			/* ITEM_TYPE == ITEM_DRINKCON||FOUNTAIN */
@@ -489,12 +493,13 @@ char *find_exdesc(char *word, struct ext
  * matches the target.  First, see if there is another char in the room
  * with the name.  Then check local objs for exdescs.
  */
-void look_at_target(struct char_data * ch, char *arg)
+void look_at_target(struct char_data * ch, char *arg, int read)
 {
-  int bits, found = 0, j;
+  int bits, found = 0, j, msg=1;
   struct char_data *found_char = NULL;
   struct obj_data *obj = NULL, *found_obj = NULL;
   char *desc;
+  char number[MAX_STRING_LENGTH];
 
   if (!ch->desc)
     return;
@@ -503,6 +508,45 @@ void look_at_target(struct char_data * c
     send_to_char("Look at what?\r\n", ch);
     return;
   }
+  if (read) {
+    for (obj = ch->carrying; obj;obj=obj->next_content) {
+      if(GET_OBJ_TYPE(obj) == ITEM_BOARD) {
+        found=1;
+        break;
+      }
+    }
+    if(!obj) {
+
+      for (obj = world[ch->in_room].contents; obj;obj=obj->next_content) {
+        if(GET_OBJ_TYPE(obj) == ITEM_BOARD) {
+          found=1;
+          break;
+        }
+      }
+    }
+    if (obj) {
+      arg = one_argument(arg, number);
+      if (!*number)
+        send_to_char("Read what?\r\n",ch);
+      if (isname(number, "board bulletin")) {
+        Board_show_board(GET_OBJ_VNUM(obj), ch);
+      }
+       /* Okay, here i'm faced with the fact that the person could be
+	entering in something like 'read 5' or 'read 4.mail' .. so, whats the
+	difference between the two?  Well, there's a period in the second,
+	so, we'll just stick with that basic difference */
+      else if ((!isdigit(*number) || (!(msg = atoi(number)))) ||
+		(strchr(number,'.'))) {
+        sprintf(arg,"%s %s", number,arg);
+        look_at_target(ch, arg, 0);
+      }
+      else {
+        Board_display_msg(GET_OBJ_VNUM(obj), ch, msg);
+      }
+    }
+  }
+  else {
+
   bits = generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP |
 		      FIND_CHAR_ROOM, ch, &found_char, &found_obj);
 
@@ -525,14 +569,17 @@ void look_at_target(struct char_data * c
   for (j = 0; j < NUM_WEARS && !found; j++)
     if (GET_EQ(ch, j) && CAN_SEE_OBJ(ch, GET_EQ(ch, j)))
       if ((desc = find_exdesc(arg, GET_EQ(ch, j)->ex_description)) != NULL) {
-	send_to_char(desc, ch);
+	  send_to_char(desc,ch);
 	found = 1;
       }
   /* Does the argument match an extra desc in the char's inventory? */
   for (obj = ch->carrying; obj && !found; obj = obj->next_content) {
     if (CAN_SEE_OBJ(ch, obj))
 	if ((desc = find_exdesc(arg, obj->ex_description)) != NULL) {
-	send_to_char(desc, ch);
+        if(GET_OBJ_TYPE(obj) == ITEM_BOARD) {
+          Board_show_board(GET_OBJ_VNUM(obj), ch);
+        } else
+  	  send_to_char(desc, ch);
 	found = 1;
       }
   }
@@ -541,7 +588,10 @@ void look_at_target(struct char_data * c
   for (obj = world[ch->in_room].contents; obj && !found; obj = obj->next_content)
     if (CAN_SEE_OBJ(ch, obj))
 	if ((desc = find_exdesc(arg, obj->ex_description)) != NULL) {
-	send_to_char(desc, ch);
+        if(GET_OBJ_TYPE(obj) == ITEM_BOARD) {
+          Board_show_board(GET_OBJ_VNUM(obj), ch);
+        } else
+	  send_to_char(desc, ch);
 	found = 1;
       }
   if (bits) {			/* If an object was found back in
@@ -552,6 +602,7 @@ void look_at_target(struct char_data * c
       show_obj_to_char(found_obj, ch, 6);	/* Find hum, glow etc */
   } else if (!found)
     send_to_char("You do not see that here.\r\n", ch);
+ }
 }
 
 
@@ -577,7 +628,7 @@ ACMD(do_look)
       if (!*arg)
 	send_to_char("Read what?\r\n", ch);
       else
-	look_at_target(ch, arg);
+	look_at_target(ch, arg,1);
       return;
     }
     if (!*arg)			/* "look" alone, without an argument at all */
@@ -588,9 +639,9 @@ ACMD(do_look)
     else if ((look_type = search_block(arg, dirs, FALSE)) >= 0)
       look_in_direction(ch, look_type);
     else if (is_abbrev(arg, "at"))
-      look_at_target(ch, arg2);
+      look_at_target(ch, arg2,0);
     else
-      look_at_target(ch, arg);
+      look_at_target(ch, arg,0);
   }
 }
 
@@ -608,7 +659,7 @@ ACMD(do_examine)
     send_to_char("Examine what?\r\n", ch);
     return;
   }
-  look_at_target(ch, arg);
+  look_at_target(ch, arg,0);
 
   bits = generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_CHAR_ROOM |
 		      FIND_OBJ_EQUIP, ch, &tmp_char, &tmp_object);
diff -uprN -x *.o ../src/act.item.c ./act.item.c
--- ../src/act.item.c	Tue Oct 28 23:16:21 1997
+++ ./act.item.c	Mon Dec 29 21:36:24 1997
@@ -19,13 +19,14 @@
 #include "handler.h"
 #include "db.h"
 #include "spells.h"
+#include "boards.h"
 
 /* extern variables */
 extern struct str_app_type str_app[];
 extern struct room_data *world;
 extern char *drinks[];
 extern int drink_aff[][3];
-
+extern struct index_data *obj_index;
 
 void perform_put(struct char_data * ch, struct obj_data * obj,
 		      struct obj_data * cont)
@@ -1306,7 +1307,7 @@ void perform_remove(struct char_data * c
 ACMD(do_remove)
 {
   struct obj_data *obj;
-  int i, dotmode, found;
+  int i, dotmode, found=0, msg;
 
   one_argument(argument, arg);
 
@@ -1314,6 +1315,31 @@ ACMD(do_remove)
     send_to_char("Remove what?\r\n", ch);
     return;
   }
+                 /* lemme check for a board FIRST */
+    for (obj = ch->carrying; obj;obj=obj->next_content) {
+      if(GET_OBJ_TYPE(obj) == ITEM_BOARD) {
+        found=1;
+        break;
+      }
+    }
+    if(!obj) {
+      for (obj = world[ch->in_room].contents; obj;obj=obj->next_content) {
+        if(GET_OBJ_TYPE(obj) == ITEM_BOARD) {
+          found=1;
+          break;
+        }
+      }
+    }
+
+  if (found) {
+    if (!isdigit(*arg) || (!(msg = atoi(arg)))) {
+      found=0;
+    }
+    else {
+      Board_remove_msg(GET_OBJ_VNUM(obj),ch, msg);
+    }
+  }
+  if (!found) {
   dotmode = find_all_dots(arg);
 
   if (dotmode == FIND_ALL) {
@@ -1348,4 +1374,5 @@ ACMD(do_remove)
     } else
       perform_remove(ch, i);
   }
+ }
 }
diff -uprN -x *.o ../src/act.wizard.c ./act.wizard.c
--- ../src/act.wizard.c	Mon Dec 29 21:57:42 1997
+++ ./act.wizard.c	Mon Dec 29 21:36:24 1997
@@ -555,6 +555,11 @@ void do_stat_object(struct char_data * c
   case ITEM_MONEY:
     sprintf(buf, "Coins: %d", GET_OBJ_VAL(j, 0));
     break;
+  case ITEM_BOARD:
+    sprintf(buf,"Read: [%d]  Write: [%d]  Remove: [%d]",
+            GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 1),
+            GET_OBJ_VAL(j, 2));
+    break;
   default:
     sprintf(buf, "Values 0-3: [%d] [%d] [%d] [%d]",
 	    GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 1),
diff -uprN -x *.o ../src/boards.c ./boards.c
--- ../src/boards.c	Mon Dec 29 21:57:42 1997
+++ ./boards.c	Mon Dec 29 21:36:24 1997
@@ -1,53 +1,8 @@
-/* ************************************************************************
-*   File: boards.c                                      Part of CircleMUD *
-*  Usage: handling of multiple bulletin boards                            *
-*                                                                         *
-*  All rights reserved.  See license.doc for complete information.        *
-*                                                                         *
-*  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
-*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
-************************************************************************ */
-
-
-/* FEATURES & INSTALLATION INSTRUCTIONS ***********************************
-
-This board code has many improvements over the infamously buggy standard
-Diku board code.  Features include:
-
-- Arbitrary number of boards handled by one set of generalized routines.
-  Adding a new board is as easy as adding another entry to an array.
-- Safe removal of messages while other messages are being written.
-- Does not allow messages to be removed by someone of a level less than
-  the poster's level.
-
-
-TO ADD A NEW BOARD, simply follow our easy 4-step program:
-
-1 - Create a new board object in the object files
-
-2 - Increase the NUM_OF_BOARDS constant in board.h
-
-3 - Add a new line to the board_info array below.  The fields, in order, are:
-
-	Board's virtual number.
-	Min level one must be to look at this board or read messages on it.
-	Min level one must be to post a message to the board.
-	Min level one must be to remove other people's messages from this
-		board (but you can always remove your own message).
-	Filename of this board, in quotes.
-	Last field must always be 0.
-
-4 - In spec_assign.c, find the section which assigns the special procedure
-    gen_board to the other bulletin boards, and add your new one in a
-    similar fashion.
-
-*/
-
+#include <dirent.h>
 
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
 #include "utils.h"
 #include "comm.h"
@@ -56,462 +11,664 @@ TO ADD A NEW BOARD, simply follow our ea
 #include "interpreter.h"
 #include "handler.h"
 
-extern struct room_data *world;
+struct board_info_type *board_info;
 extern struct descriptor_data *descriptor_list;
 
-int Board_display_msg(int board_type, struct char_data * ch, char *arg);
-int Board_show_board(int board_type, struct char_data * ch, char *arg);
-int Board_remove_msg(int board_type, struct char_data * ch, char *arg);
-void Board_save_board(int board_type);
-void Board_load_board(int board_type);
-void Board_reset_board(int board_num);
-void Board_write_message(int board_type, struct char_data * ch, char *arg);
-
-/*
-format:	vnum, read lvl, write lvl, remove lvl, filename, 0 at end
-Be sure to also change NUM_OF_BOARDS in board.h
-*/
-struct board_info_type board_info[NUM_OF_BOARDS] = {
-  {3099, 0, 0, LVL_GOD, "etc/board.mort", 0},
-  {3098, LVL_IMMORT, LVL_IMMORT, LVL_GRGOD, "etc/board.immort", 0},
-  {3097, LVL_IMMORT, LVL_FREEZE, LVL_IMPL, "etc/board.freeze", 0},
-  {3096, 0, 0, LVL_IMMORT, "etc/board.social", 0},
-};
-
-
-char *msg_storage[INDEX_SIZE];
-int msg_storage_taken[INDEX_SIZE];
-int num_of_msgs[NUM_OF_BOARDS];
-int ACMD_READ, ACMD_LOOK, ACMD_EXAMINE, ACMD_WRITE, ACMD_REMOVE;
-struct board_msginfo msg_index[NUM_OF_BOARDS][MAX_BOARD_MESSAGES];
-
-
-int find_slot(void)
-{
-  int i;
+void Board_init_boards(void) {
+           int n,o, board_vnum;
+           struct dirent **namelist;
+
+           n = scandir(BOARD_DIRECTORY, &namelist, 0, alphasort);
+           if (n < 0) {
+              log("Funny, no board files found.\n");
+ 	      return;
+           }
+
+           for (o=0; o != n; o++) {
+             if(strcmp("..",namelist[o]->d_name) && 
+		    		strcmp(".",namelist[o]->d_name)) {
+             sscanf(namelist[o]->d_name,"%d", &board_vnum);
+	     create_new_board(board_vnum);
+             }
+          }
+
+ /* just before we close, lets look at boards huh? */
+
+     look_at_boards(); 
+       }
+
+struct board_info_type * create_new_board(int board_vnum) {
+           extern struct board_info_type *board_info;
+           struct board_msg_info *bmsg;
+
+           int boards=0, t_messages=0, error=0, t[4], mnum, poster,timestamp,sflag;
+           char buf[512];
+           FILE *fl;
+           struct board_info_type *temp_board=NULL, *old_board;
+           struct obj_data *obj;
+           struct board_memory_type *memboard, *list;
+
+           sprintf(buf,"%s/%d",BOARD_DIRECTORY,board_vnum);
+
+           if(!(fl = fopen(buf, "r"))) {
+
+/* this is for boards which exist as an object, but don't have a file yet */
+                /* Ie, new boards */
+
+               if(!(fl = fopen(buf,"w"))) {
+                 log("Hm. Error while creating new board file");
+               }
+               else {
+	     
+                 obj = read_object(real_object(board_vnum), REAL);
+
+                 CREATE(temp_board, struct board_info_type, 1);
+  	         READ_LVL(temp_board)=GET_OBJ_VAL(obj, 0);
+  	         WRITE_LVL(temp_board)=GET_OBJ_VAL(obj, 1);
+                 REMOVE_LVL(temp_board)=GET_OBJ_VAL(obj, 2);
+                 BOARD_VNUM(temp_board)=board_vnum;
+	         BOARD_MNUM(temp_board)=0;
+                 BOARD_NEXT(temp_board)=NULL;
+                 BOARD_MESSAGES(temp_board)=NULL;
+                 extract_obj(obj);
+                 fprintf(fl,"Board File\n%d %d %d %d\n",READ_LVL(temp_board),
+     WRITE_LVL(temp_board), REMOVE_LVL(temp_board), BOARD_MNUM(temp_board));
+                 fclose(fl);
+            
+	        old_board=board_info;
+                board_info=temp_board;
+                BOARD_NEXT(temp_board)=old_board;
+                return temp_board;
+
+               }
+           }
+           else {
+             get_line(fl,buf);
+             if((strcasecmp("Board File", buf))) {
+             }
+             else {
+               boards++;
+               CREATE(temp_board, struct board_info_type, 1);
+               temp_board->vnum=board_vnum;
+               get_line(fl, buf); 
+               if (sscanf(buf,"%d", t) != 1) {
+                 error=1;
+               }
+               if (!(real_object(board_vnum))) {
+                 sprintf(buf, "Erasing non-existant board file: %d",
+								board_vnum);
+                 log(buf);
+		 sprintf(buf,"%s/%d",BOARD_DIRECTORY,board_vnum);
+                 unlink(buf);
+                 if(temp_board) 
+  		   free(temp_board);
+                 return NULL;    /* realize why I do this yes? */
+               }
+               obj = read_object(real_object(board_vnum),REAL);
+
+                 READ_LVL(temp_board)=GET_OBJ_VAL(obj, 0);
+                 WRITE_LVL(temp_board)=GET_OBJ_VAL(obj, 1);
+                 REMOVE_LVL(temp_board)=GET_OBJ_VAL(obj, 2);	
+		 BOARD_MNUM(temp_board)=t[0];
+                 BOARD_NEXT(temp_board)=NULL;
+                 BOARD_MESSAGES(temp_board)=NULL;
+                 extract_obj(obj);
+
+               if (error) {
+                 sprintf(buf,"Parse error in board %d - attempting to continue\n",
+  		   BOARD_VNUM(temp_board));
+		 log(buf);
+               /* attempting board ressurection */
+
+               if(!(t[0] > 0 && t[0] < LVL_IMPL)) {
+                 READ_LVL(temp_board) = LVL_IMMORT;
+               }
+               if(!(t[1] > 0 && t[1] < LVL_IMPL)) {
+                       WRITE_LVL(temp_board) = LVL_IMMORT;
+               }
+               if(!(t[2] > 0 && t[2] < LVL_IMPL)) {
+                 REMOVE_LVL(temp_board) = LVL_IMPL;
+               }
+               if(!(t[3] > 0 && t[3] < LVL_IMPL)) {
+                /*  This is an indication of a very unfun board */
+                /* I guess if I ever optimize any of this raggedy code */
+		/* this will actually mean something. Right now, its nada */
+                       BOARD_MNUM(temp_board) = -1;       
+                   }
+		 }
+                 list=NULL; /* or BOARD_MEMORY(temp_board) but this should
+				be null anyway...*/
+	         while(get_line(fl,buf)) {
+                   /* this is the loop that reads the messages 
+			and also the message read info stuff */
+                   if (*buf == 'S') {
+	/* Note, we assume that all messages are read in before the hash
+					memory lists */
+                     sscanf(buf,"S %d %d %d ", &mnum, &poster, &timestamp);
+                     CREATE(memboard, struct board_memory_type, 1);
+                     MEMORY_READER(memboard)=poster;
+                     MEMORY_TIMESTAMP(memboard)=timestamp;
+
+		     bmsg=BOARD_MESSAGES(temp_board);
+		     sflag=0;
+			/* check and see if memory is still valid */
+
+		     while(bmsg && !sflag) {
+
+ 		       if(MESG_TIMESTAMP(bmsg) ==MEMORY_TIMESTAMP(memboard)
+			&& (mnum == ((MESG_TIMESTAMP(bmsg)%301 +
+				MESG_POSTER(bmsg)%301)%301))) {
+			   sflag=1;
+			  /* probably ought to put a flag saying that
+			     memory should be deleted because the reader
+			     no longer exists on the mud, but it will
+			     figure it out in a few iterations. Let it be 
+			     happy, and let me be lazy */
+		       }
+		       bmsg=MESG_NEXT(bmsg);
+                     }
+	             if(sflag) {
+                       if(BOARD_MEMORY(temp_board,mnum)) {
+                         list=BOARD_MEMORY(temp_board,mnum);
+                         BOARD_MEMORY(temp_board,mnum)=memboard;
+                         MEMORY_NEXT(memboard)=list;
+                       }
+                       else {
+                         BOARD_MEMORY(temp_board,mnum)=memboard;
+                         MEMORY_NEXT(memboard)=NULL;
+                       }
+                    } else {
+		/* memory no longer in use */
+			free(memboard);
+	             }
+                   } else if (*buf == '#') {
+                     t_messages++;
+                     parse_message(fl, temp_board);
+                   }
+                 }
+                BOARD_MNUM(temp_board)=t_messages;
+
+/* add it to the list. */
+
+                old_board=board_info;
+		board_info=temp_board;
+                BOARD_NEXT(temp_board)=old_board;
+
+               }
+           fclose(fl);
+             }
+  /* hold on. Lets think about this:
+        Board messages are added in the folowing way - 1,2,3,4,5...etc
+        However, when they're read in, its fifo, 5,4,3,2,1, so between
+        each reboot, the existing order is reversed.  hm. */
+
+  reverse_message_order(temp_board);
 
-  for (i = 0; i < INDEX_SIZE; i++)
-    if (!msg_storage_taken[i]) {
-      msg_storage_taken[i] = 1;
-      return i;
-    }
-  return -1;
+  return temp_board;
 }
 
+void reverse_message_order(struct board_info_type *t_board) {
+  struct board_msg_info *old,*new,*store;
 
-/* search the room ch is standing in to find which board he's looking at */
-int find_board(struct char_data * ch)
-{
-  struct obj_data *obj;
-  int i;
-
-  for (obj = world[ch->in_room].contents; obj; obj = obj->next_content)
-    for (i = 0; i < NUM_OF_BOARDS; i++)
-      if (BOARD_RNUM(i) == GET_OBJ_RNUM(obj))
-	return i;
-
-  return -1;
-}
-
-
-void init_boards(void)
-{
-  int i, j, fatal_error = 0;
-  char buf[256];
-
-  for (i = 0; i < INDEX_SIZE; i++) {
-    msg_storage[i] = 0;
-    msg_storage_taken[i] = 0;
-  }
-
-  for (i = 0; i < NUM_OF_BOARDS; i++) {
-    if ((BOARD_RNUM(i) = real_object(BOARD_VNUM(i))) == -1) {
-      sprintf(buf, "SYSERR: Fatal board error: board vnum %d does not exist!",
-	      BOARD_VNUM(i));
-      log(buf);
-      fatal_error = 1;
-    }
-    num_of_msgs[i] = 0;
-    for (j = 0; j < MAX_BOARD_MESSAGES; j++) {
-      memset((char *) &(msg_index[i][j]), 0, sizeof(struct board_msginfo));
-      msg_index[i][j].slot_num = -1;
-    }
-    Board_load_board(i);
+  old=BOARD_MESSAGES(t_board);
+  if(!old || !MESG_NEXT(old)) {
+    return;
   }
 
-  ACMD_READ = find_command("read");
-  ACMD_WRITE = find_command("write");
-  ACMD_REMOVE = find_command("remove");
-  ACMD_LOOK = find_command("look");
-  ACMD_EXAMINE = find_command("examine");
+  store=new=NULL;
 
-  if (fatal_error)
-    exit(1);
-}
+  /* yes, there's a better way for doing this, but I think I had some
+     problems with second thoughts after accidently deleting stuff */
 
-
-SPECIAL(gen_board)
-{
-  int board_type;
-  static int loaded = 0;
-
-  if (!loaded) {
-    init_boards();
-    loaded = 1;
-  }
-  if (!ch->desc)
-    return 0;
-
-  if (cmd != ACMD_WRITE && cmd != ACMD_LOOK && cmd != ACMD_EXAMINE &&
-      cmd != ACMD_READ && cmd != ACMD_REMOVE)
-    return 0;
-
-  if ((board_type = find_board(ch)) == -1) {
-    log("SYSERR:  degenerate board!  (what the hell...)");
-    return 0;
-  }
-  if (cmd == ACMD_WRITE) {
-    Board_write_message(board_type, ch, argument);
-    return 1;
-  } else if (cmd == ACMD_LOOK || cmd == ACMD_EXAMINE)
-    return (Board_show_board(board_type, ch, argument));
-  else if (cmd == ACMD_READ)
-    return (Board_display_msg(board_type, ch, argument));
-  else if (cmd == ACMD_REMOVE)
-    return (Board_remove_msg(board_type, ch, argument));
-  else
-    return 0;
-}
-
-
-void Board_write_message(int board_type, struct char_data * ch, char *arg)
-{
+  while(old) {
+    store=new;
+    CREATE(new, struct board_msg_info, 1);
+    MESG_POSTER(new)=MESG_POSTER(old);
+    MESG_TIMESTAMP(new)=MESG_TIMESTAMP(old);
+    MESG_SUBJECT(new)=MESG_SUBJECT(old);
+    MESG_DATA(new)=MESG_DATA(old);
+    MESG_NEXT(new)=store;
+
+    store=old;
+    old=MESG_NEXT(old);
+    free(store);
+  }
+  BOARD_MESSAGES(t_board)=new;
+
+}
+
+void parse_message( FILE *fl, struct board_info_type *t_board) {
+  struct board_msg_info *tmsg, *t2msg;
+  char subject[81];
+  char buf[8192];
+  
+  CREATE(tmsg, struct board_msg_info, 1);
+  
+  fscanf(fl, "%ld\n", &(MESG_POSTER(tmsg)));
+  fscanf(fl, "%ld\n", &(MESG_TIMESTAMP(tmsg)));
+
+  get_line(fl,subject);
+
+  MESG_SUBJECT(tmsg)=strdup(subject);
+  MESG_DATA(tmsg)=fread_string(fl,buf);
+  MESG_NEXT(tmsg)=NULL;
+
+  t2msg=BOARD_MESSAGES(t_board);
+  BOARD_MESSAGES(t_board)=tmsg;
+  MESG_NEXT(tmsg) = t2msg;
+
+}
+      
+void look_at_boards() {
+  int counter, messages=0;
+  struct board_info_type *tboard=board_info;
+  struct board_msg_info *msg;
+    
+  for(counter=0;tboard;counter++) {
+     msg=BOARD_MESSAGES(tboard);
+     while(msg) {
+       messages++;
+       msg=MESG_NEXT(msg);
+     }
+     tboard=BOARD_NEXT(tboard);
+  }
+
+  sprintf(buf,"There are %d boards located; %d messages",counter, messages);
+  log(buf);
+}
+
+int Board_show_board(int board_vnum, struct char_data *ch) {
+  struct board_info_type *thisboard=board_info;
+  struct board_msg_info *message;
   char *tmstr;
-  int len;
-  time_t ct;
-  char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
-
-  if (GET_LEVEL(ch) < WRITE_LVL(board_type)) {
-    send_to_char("You are not holy enough to write on this board.\r\n", ch);
-    return;
+  int msgcount=0,yesno=0;
+  char buf3[MAX_STRING_LENGTH];
+  char name[127];
+				/* board locate */
+  while(thisboard) {
+    if (BOARD_VNUM(thisboard) == board_vnum)
+      break;
+    thisboard=BOARD_NEXT(thisboard);
   }
-  if (num_of_msgs[board_type] >= MAX_BOARD_MESSAGES) {
-    send_to_char("The board is full.\r\n", ch);
-    return;
-  }
-  if ((NEW_MSG_INDEX(board_type).slot_num = find_slot()) == -1) {
-    send_to_char("The board is malfunctioning - sorry.\r\n", ch);
-    log("SYSERR: Board: failed to find empty slot on write.");
-    return;
-  }
-  /* skip blanks */
-  skip_spaces(&arg);
-  delete_doubledollar(arg);
-
-  /* JE 27 Oct 95 - Truncate headline at 80 chars if it's longer than that */
-  arg[81] = '\0';
+  if (!thisboard) {
 
-  if (!*arg) {
-    send_to_char("We must have a headline!\r\n", ch);
-    return;
+    sprintf(buf,"Creating new board - board #%d", board_vnum);
+    log(buf);
+    thisboard=create_new_board(board_vnum);
   }
-  ct = time(0);
-  tmstr = (char *) asctime(localtime(&ct));
-  *(tmstr + strlen(tmstr) - 1) = '\0';
 
-  sprintf(buf2, "(%s)", GET_NAME(ch));
-  sprintf(buf, "%6.10s %-12s :: %s", tmstr, buf2, arg);
-  len = strlen(buf) + 1;
-  if (!(NEW_MSG_INDEX(board_type).heading = (char *) malloc(sizeof(char) * len))) {
-    send_to_char("The board is malfunctioning - sorry.\r\n", ch);
-    return;
+  if (GET_LEVEL(ch) < READ_LVL(thisboard)) {
+    send_to_char("You try but fail to understand the holy words.\r\n",ch);
+    return 1;
   }
-  strcpy(NEW_MSG_INDEX(board_type).heading, buf);
-  NEW_MSG_INDEX(board_type).heading[len - 1] = '\0';
-  NEW_MSG_INDEX(board_type).level = GET_LEVEL(ch);
-
-  send_to_char("Write your message.  (/s saves /h for help)\r\n\r\n", ch);
-  act("$n starts to write a message.", TRUE, ch, 0, 0, TO_ROOM);
-
-  if (!IS_NPC(ch))
-    SET_BIT(PLR_FLAGS(ch), PLR_WRITING);
+  /* send the standard board boilerplate */
 
-  ch->desc->str = &(msg_storage[NEW_MSG_INDEX(board_type).slot_num]);
-  ch->desc->max_str = MAX_MESSAGE_LENGTH;
-  ch->desc->mail_to = board_type + BOARD_MAGIC;
-
-  num_of_msgs[board_type]++;
-}
-
-
-int Board_show_board(int board_type, struct char_data * ch, char *arg)
-{
-  int i;
-  char tmp[MAX_STRING_LENGTH], buf[MAX_STRING_LENGTH];
 
-  if (!ch->desc)
-    return 0;
-
-  one_argument(arg, tmp);
-
-  if (!*tmp || !isname(tmp, "board bulletin"))
-    return 0;
-
-  if (GET_LEVEL(ch) < READ_LVL(board_type)) {
-    send_to_char("You try but fail to understand the holy words.\r\n", ch);
+  sprintf(buf2,"This is a bulletin board.\r\n"
+     "Usage:READ/REMOVE <messg #>, WRITE<header>.\r\n");
+  if (!BOARD_MNUM(thisboard) || !BOARD_MESSAGES(thisboard)) {
+    strcat(buf2, "The board is empty.\r\n");
+    send_to_char(buf2,ch);
     return 1;
   }
-  act("$n studies the board.", TRUE, ch, 0, 0, TO_ROOM);
-
-  strcpy(buf,
-	 "This is a bulletin board.  Usage: READ/REMOVE <messg #>, WRITE <header>.\r\n"
-	 "You will need to look at the board to save your message.\r\n");
-  if (!num_of_msgs[board_type])
-    strcat(buf, "The board is empty.\r\n");
   else {
-    sprintf(buf + strlen(buf), "There are %d messages on the board.\r\n",
-	    num_of_msgs[board_type]);
-    for (i = 0; i < num_of_msgs[board_type]; i++) {
-/*    for (i = num_of_msgs[board_type] - 1; i >= 0; i--) { */
-      if (MSG_HEADING(board_type, i))
-	sprintf(buf + strlen(buf), "%-2d : %s\r\n", i + 1, MSG_HEADING(board_type, i));
-      else {
-	log("SYSERR: The board is fubar'd.");
-	send_to_char("Sorry, the board isn't working.\r\n", ch);
-	return 1;
-      }
-    }
-  }
-  page_string(ch->desc, buf, 1);
+     sprintf(buf2, "%sThere %s %d %s on the board.\r\n",
+	buf2
+        , (BOARD_MNUM(thisboard) == 1) ? "is" : "are",
+	BOARD_MNUM(thisboard),(BOARD_MNUM(thisboard) == 1) ? "message" :
+	"messages");
+   }
+  message=BOARD_MESSAGES(thisboard);
 
+  tmstr = (char *) asctime(localtime( &MESG_TIMESTAMP(message)));
+  *(tmstr + strlen(tmstr) - 1) = '\0';
+    
+    for (message=BOARD_MESSAGES(thisboard);message;message=MESG_NEXT(message)) {
+      yesno=mesglookup(message,ch,thisboard);
+
+      sprintf(name,"%s",get_name_by_id(MESG_POSTER(message)));
+    
+      sprintf(buf3,"(%s)",CAP(name));
+
+      if (MESG_SUBJECT(message) && yesno) {
+          sprintf(buf,"[x] (%2d) : %6.10s %-23s :: %s \r\n",
+          ++msgcount,
+          tmstr,
+          buf3,
+          MESG_SUBJECT(message) ? MESG_SUBJECT(message) : "No Subject");
+          strcat(buf2,buf);
+       }
+      else {
+          sprintf(buf,"[ ] (%2d) : %6.10s %-23s :: %s \r\n",
+          ++msgcount,
+          tmstr,
+          buf3,
+          MESG_SUBJECT(message) ? MESG_SUBJECT(message) : "No Subject");
+          strcat(buf2,buf);
+       }
+     }
+  page_string(ch->desc, buf2, 1);
   return 1;
 }
 
 
-int Board_display_msg(int board_type, struct char_data * ch, char *arg)
+int Board_display_msg(int board_vnum, struct char_data * ch, int arg)
 {
-  char number[MAX_STRING_LENGTH], buffer[MAX_STRING_LENGTH];
-  int msg, ind;
-
-  one_argument(arg, number);
-  if (!*number)
-    return 0;
-  if (isname(number, "board bulletin"))	/* so "read board" works */
-    return (Board_show_board(board_type, ch, arg));
-  if (!isdigit(*number) || (!(msg = atoi(number))))
-    return 0;
+  extern struct board_info_type *board_info; 
+  struct board_info_type *thisboard=board_info;
+  struct board_msg_info *message;
+  char *tmstr;
+  int msgcount,mem,sflag;
+  char name[127];
+  struct board_memory_type *mboard_type, *list;
+ 
+
+  /* guess we'll have to locate the board now in the list */
+
+  while(thisboard) {
+    if (BOARD_VNUM(thisboard) == board_vnum)
+      break;
+    thisboard=BOARD_NEXT(thisboard);
+  }
+
+  if (!thisboard) {
+    sprintf(buf,"Creating new board - board #%d", board_vnum);
+    log(buf);
+    thisboard=create_new_board(board_vnum);
+  } 
 
-  if (GET_LEVEL(ch) < READ_LVL(board_type)) {
+  if (GET_LEVEL(ch) < READ_LVL(thisboard)) {
     send_to_char("You try but fail to understand the holy words.\r\n", ch);
     return 1;
   }
-  if (!num_of_msgs[board_type]) {
+    
+  if (!BOARD_MESSAGES(thisboard)) {
     send_to_char("The board is empty!\r\n", ch);
-    return (1);
-  }
-  if (msg < 1 || msg > num_of_msgs[board_type]) {
-    send_to_char("That message exists only in your imagination.\r\n",
-		 ch);
-    return (1);
-  }
-  ind = msg - 1;
-  if (MSG_SLOTNUM(board_type, ind) < 0 ||
-      MSG_SLOTNUM(board_type, ind) >= INDEX_SIZE) {
-    send_to_char("Sorry, the board is not working.\r\n", ch);
-    log("SYSERR: Board is screwed up.");
     return 1;
   }
-  if (!(MSG_HEADING(board_type, ind))) {
-    send_to_char("That message appears to be screwed up.\r\n", ch);
+  /* now we locate the message.*/  
+  message=BOARD_MESSAGES(thisboard);
+  if (arg < 1) {
+    send_to_char("You must specify the (positive) number of the message to be read!\r\n",ch);
     return 1;
   }
-  if (!(msg_storage[MSG_SLOTNUM(board_type, ind)])) {
-    send_to_char("That message seems to be empty.\r\n", ch);
+  for(msgcount=arg;message && msgcount!=1;msgcount--) {
+    message=MESG_NEXT(message);
+  }
+  if(!message) {
+    send_to_char("That message exists only in your imagination.\r\n", ch);
     return 1;
   }
-  sprintf(buffer, "Message %d : %s\r\n\r\n%s\r\n", msg,
-	  MSG_HEADING(board_type, ind),
-	  msg_storage[MSG_SLOTNUM(board_type, ind)]);
+  /* Have message, lets add the fact that this player read the mesg */
+
+  mem = ((MESG_TIMESTAMP(message)%301 + MESG_POSTER(message)%301)%301);
 
-  page_string(ch->desc, buffer, 1);
+  /*make the new node */
+  CREATE(mboard_type, struct board_memory_type, 1);
+  MEMORY_READER(mboard_type)=GET_IDNUM(ch);
+  MEMORY_TIMESTAMP(mboard_type)=MESG_TIMESTAMP(message);
+  MEMORY_NEXT(mboard_type)=NULL;
+
+  /* Let's make sure that we don't already have this memory recorded */
+
+  list=BOARD_MEMORY(thisboard,mem);
+  sflag=1;
+  while(list && sflag) {
+    if (MEMORY_READER(list) == MEMORY_READER(mboard_type) &&
+	MEMORY_TIMESTAMP(list) == MEMORY_TIMESTAMP(mboard_type)) {
+     /* nope, slot, reader, and timestamp equal, so already saved */
+      sflag=0;
+    }
+    list=MEMORY_NEXT(list);
+  }
 
+  if(sflag) {
+    list=BOARD_MEMORY(thisboard,mem);
+    BOARD_MEMORY(thisboard,mem) = mboard_type;
+    MEMORY_NEXT(mboard_type)=list;
+  }
+  else {
+    if(mboard_type) 
+      free(mboard_type);
+  }
+       
+/* before we print out the message, we may as well restore a human
+				readable timestamp. */
+  tmstr = (char *) asctime(localtime(&MESG_TIMESTAMP(message)));
+  *(tmstr + strlen(tmstr) - 1) = '\0';
+  sprintf(name,"%s",get_name_by_id(MESG_POSTER(message)));
+  sprintf(buf,"Message %d : %6.10s (%s) :: %s\r\n\r\n%s\r\n",
+	  arg,
+          tmstr,
+          CAP(name),
+          MESG_SUBJECT(message) ? MESG_SUBJECT(message) : "No Subject",
+          MESG_DATA(message) ? MESG_DATA(message) : "Looks like this message is empty.");
+  page_string(ch->desc, buf, 1);
+  Board_save_board(BOARD_VNUM(thisboard));
   return 1;
-}
 
+}
 
-int Board_remove_msg(int board_type, struct char_data * ch, char *arg)
+int Board_remove_msg(int board_vnum, struct char_data * ch, int arg)
 {
-  int ind, msg, slot_num;
-  char number[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH];
+  extern struct board_info_type *board_info;
+  struct board_info_type *thisboard=board_info;
+  struct board_msg_info *message, *old_message;
   struct descriptor_data *d;
+  int msgcount;
 
-  one_argument(arg, number);
-
-  if (!*number || !isdigit(*number))
+  while(thisboard) {
+    if (BOARD_VNUM(thisboard) == board_vnum)
+      break;
+    thisboard=BOARD_NEXT(thisboard);
+  }
+  if (!thisboard) {
+    send_to_char("Error: Your board could not be found. Please report.\n",ch);
+    sprintf(buf,"Error in Board_remove_msg - board #%d", board_vnum);
+    log(buf);
     return 0;
-  if (!(msg = atoi(number)))
-    return (0);
-
-  if (!num_of_msgs[board_type]) {
-    send_to_char("The board is empty!\r\n", ch);
-    return 1;
-  }
-  if (msg < 1 || msg > num_of_msgs[board_type]) {
-    send_to_char("That message exists only in your imagination.\r\n", ch);
-    return 1;
   }
-  ind = msg - 1;
-  if (!MSG_HEADING(board_type, ind)) {
-    send_to_char("That message appears to be screwed up.\r\n", ch);
+  message=BOARD_MESSAGES(thisboard);
+  if (arg < 1) {
+     send_to_char("You must specify the (positive) number of the message to be read!\r\n",ch);
     return 1;
   }
-  sprintf(buf, "(%s)", GET_NAME(ch));
-  if (GET_LEVEL(ch) < REMOVE_LVL(board_type) &&
-      !(strstr(MSG_HEADING(board_type, ind), buf))) {
-    send_to_char("You are not holy enough to remove other people's messages.\r\n", ch);
-    return 1;
+  old_message=NULL;
+  for(msgcount=arg;message && msgcount!=1;msgcount--) {
+    old_message=message;
+    message=MESG_NEXT(message);
   }
-  if (GET_LEVEL(ch) < MSG_LEVEL(board_type, ind)) {
-    send_to_char("You can't remove a message holier than yourself.\r\n", ch);
+  if(!message) {
+    send_to_char("That message exists only in your imagination.\r\n", ch);
     return 1;
   }
-  slot_num = MSG_SLOTNUM(board_type, ind);
-  if (slot_num < 0 || slot_num >= INDEX_SIZE) {
-    log("SYSERR: The board is seriously screwed up.");
-    send_to_char("That message is majorly screwed up.\r\n", ch);
+  if(GET_IDNUM(ch) != MESG_POSTER(message) && 
+	GET_LEVEL(ch) < REMOVE_LVL(thisboard)) {
+    send_to_char("You are not holy enough to remove other peoples messages.\r\n",ch);
     return 1;
   }
-  for (d = descriptor_list; d; d = d->next)
-    if (!d->connected && d->str == &(msg_storage[slot_num])) {
+ 	/* perform check for mesg in creation */
+    for (d = descriptor_list; d; d = d->next)
+    if (!d->connected && d->str == &(MESG_DATA(message))) {
       send_to_char("At least wait until the author is finished before removing it!\r\n", ch);
       return 1;
     }
-  if (msg_storage[slot_num])
-    free(msg_storage[slot_num]);
-  msg_storage[slot_num] = 0;
-  msg_storage_taken[slot_num] = 0;
-  if (MSG_HEADING(board_type, ind))
-    free(MSG_HEADING(board_type, ind));
-
-  for (; ind < num_of_msgs[board_type] - 1; ind++) {
-    MSG_HEADING(board_type, ind) = MSG_HEADING(board_type, ind + 1);
-    MSG_SLOTNUM(board_type, ind) = MSG_SLOTNUM(board_type, ind + 1);
-    MSG_LEVEL(board_type, ind) = MSG_LEVEL(board_type, ind + 1);
+
+/* everything else is peachy, kill the message */
+  if(MESG_NEXT(message)) {
+    if(old_message) {
+      MESG_NEXT(old_message)=MESG_NEXT(message);
+    }
+    else {
+      BOARD_MESSAGES(thisboard)=MESG_NEXT(message);
+    }
   }
-  num_of_msgs[board_type]--;
+  else {
+    if (old_message) {
+      MESG_NEXT(old_message)=NULL;
+    }
+    else {
+      BOARD_MESSAGES(thisboard)=NULL;
+    }
+  }
+
+  free(message);
+  BOARD_MNUM(thisboard)=BOARD_MNUM(thisboard)-1;
+
   send_to_char("Message removed.\r\n", ch);
-  sprintf(buf, "$n just removed message %d.", msg);
+  sprintf(buf, "$n just removed message %d.", arg);
   act(buf, FALSE, ch, 0, 0, TO_ROOM);
-  Board_save_board(board_type);
-
+  Board_save_board(BOARD_VNUM(thisboard));
   return 1;
-}
 
+}
 
-void Board_save_board(int board_type)
-{
+int Board_save_board(int board_vnum) {
+  extern struct board_info_type *board_info;
+  struct board_info_type *thisboard=board_info;
+  struct board_msg_info *message;
+  struct board_memory_type *memboard;
+  struct obj_data *obj;
   FILE *fl;
-  int i;
-  char *tmp1 = 0, *tmp2 = 0;
+  int i=1,counter=0;
 
-  if (!num_of_msgs[board_type]) {
-    unlink(FILENAME(board_type));
-    return;
+  while(thisboard) {
+    if (BOARD_VNUM(thisboard) == board_vnum)
+      break;
+    thisboard=BOARD_NEXT(thisboard);
+  }
+  if(!thisboard) {
+    thisboard=create_new_board(board_vnum);
   }
-  if (!(fl = fopen(FILENAME(board_type), "wb"))) {
+
+  /* before we save to the file, lets make sure that our board is updated */
+
+  obj = read_object(real_object(board_vnum), REAL);
+  READ_LVL(thisboard)=GET_OBJ_VAL(obj, 0);
+  WRITE_LVL(thisboard)=GET_OBJ_VAL(obj, 1);
+  REMOVE_LVL(thisboard)=GET_OBJ_VAL(obj, 2);
+  extract_obj(obj);
+
+  sprintf(buf,"%s/%d",BOARD_DIRECTORY,board_vnum);
+
+  if (!(fl = fopen(buf, "wb"))) {
     perror("Error writing board");
-    return;
+    return 0;
   }
-  fwrite(&(num_of_msgs[board_type]), sizeof(int), 1, fl);
+   /* now we write out the basic stats of the board */
+
+  fprintf(fl,"Board File\n%d\n",BOARD_MNUM(thisboard));
 
-  for (i = 0; i < num_of_msgs[board_type]; i++) {
-    if ((tmp1 = MSG_HEADING(board_type, i)))
-      msg_index[board_type][i].heading_len = strlen(tmp1) + 1;
-    else
-      msg_index[board_type][i].heading_len = 0;
-
-    if (MSG_SLOTNUM(board_type, i) < 0 ||
-	MSG_SLOTNUM(board_type, i) >= INDEX_SIZE ||
-	(!(tmp2 = msg_storage[MSG_SLOTNUM(board_type, i)])))
-      msg_index[board_type][i].message_len = 0;
-    else
-      msg_index[board_type][i].message_len = strlen(tmp2) + 1;
-
-    fwrite(&(msg_index[board_type][i]), sizeof(struct board_msginfo), 1, fl);
-    if (tmp1)
-      fwrite(tmp1, sizeof(char), msg_index[board_type][i].heading_len, fl);
-    if (tmp2)
-      fwrite(tmp2, sizeof(char), msg_index[board_type][i].message_len, fl);
+  for(message=BOARD_MESSAGES(thisboard);message;message=MESG_NEXT(message))
+  {
+    fprintf(fl,"#%d\n"
+               "%ld\n"
+               "%ld\n"
+               "%s\n"
+               "%s~\n",
+               i, MESG_POSTER(message), MESG_TIMESTAMP(message),
+               MESG_SUBJECT(message), MESG_DATA(message));  
+    i++;
+  }
+  /* now write out the saved info.. */
+  for(counter=0;counter!=301;counter++) {
+    memboard=BOARD_MEMORY(thisboard,counter);
+    while(memboard) {
+      fprintf(fl,"S%d %d %d\n",counter, MEMORY_READER(memboard), 
+		MEMORY_TIMESTAMP(memboard));
+      memboard=MEMORY_NEXT(memboard);
+    }
   }
 
   fclose(fl);
+  return 1;
 }
 
-
-void Board_load_board(int board_type)
-{
-  FILE *fl;
-  int i, len1 = 0, len2 = 0;
-  char *tmp1 = NULL, *tmp2 = NULL;
-
-
-  if (!(fl = fopen(FILENAME(board_type), "rb"))) {
-    if (errno != ENOENT)
-      perror("Error reading board");
+void Board_write_message(int board_vnum, struct char_data *ch, char *arg){
+  struct board_info_type *thisboard=board_info;
+  struct board_msg_info *message,*old_message;
+
+                                /* board locate */
+  while(thisboard) {
+    if (BOARD_VNUM(thisboard) == board_vnum)
+      break;
+    thisboard=BOARD_NEXT(thisboard);
+  }
+  if (!thisboard) {
+    send_to_char("Error: Your board could not be found. Please report.\n",ch);
+    sprintf(buf,"Error in Board_display_msg - board #%d", board_vnum);
+    log(buf);
     return;
   }
-  fread(&(num_of_msgs[board_type]), sizeof(int), 1, fl);
-  if (num_of_msgs[board_type] < 1 || num_of_msgs[board_type] > MAX_BOARD_MESSAGES) {
-    log("SYSERR: Board file corrupt.  Resetting.");
-    Board_reset_board(board_type);
+
+  if (GET_LEVEL(ch) < WRITE_LVL(thisboard)) {
+    send_to_char("You are not holy enough to write on this board.\r\n",ch);
     return;
   }
-  for (i = 0; i < num_of_msgs[board_type]; i++) {
-    fread(&(msg_index[board_type][i]), sizeof(struct board_msginfo), 1, fl);
-    if (!(len1 = msg_index[board_type][i].heading_len)) {
-      log("SYSERR: Board file corrupt!  Resetting.");
-      Board_reset_board(board_type);
-      return;
-    }
-    if (!(tmp1 = (char *) malloc(sizeof(char) * len1))) {
-      log("SYSERR: Error - malloc failed for board header");
-      exit(1);
-    }
-    fread(tmp1, sizeof(char), len1, fl);
-    MSG_HEADING(board_type, i) = tmp1;
 
-    if ((len2 = msg_index[board_type][i].message_len)) {
-      if ((MSG_SLOTNUM(board_type, i) = find_slot()) == -1) {
-	log("SYSERR: Out of slots booting board!  Resetting...");
-	Board_reset_board(board_type);
-	return;
-      }
-      if (!(tmp2 = (char *) malloc(sizeof(char) * len2))) {
-	log("SYSERR: malloc failed for board text");
-	exit(1);
-      }
-      fread(tmp2, sizeof(char), len2, fl);
-      msg_storage[MSG_SLOTNUM(board_type, i)] = tmp2;
-    }
+  if(!*arg || !arg)
+    sprintf(arg,"No Subject");
+  
+  skip_spaces(&arg);
+  delete_doubledollar(arg);
+
+  arg[81] = '\0';
+  
+  CREATE(message, struct board_msg_info, 1);
+  MESG_POSTER(message)=GET_IDNUM(ch);
+  MESG_TIMESTAMP(message)=time(0);
+  MESG_SUBJECT(message) = strdup(arg);
+  MESG_NEXT(message)=NULL;
+  MESG_DATA(message)=NULL;
+  BOARD_MNUM(thisboard) = BOARD_MNUM(thisboard) + 1;
+
+  if (BOARD_MESSAGES(thisboard)) {
+    old_message=BOARD_MESSAGES(thisboard);
+    BOARD_MESSAGES(thisboard)=message;
+    MESG_NEXT(message)=old_message;
   }
+  else 
+    BOARD_MESSAGES(thisboard)=message;
+
+  send_to_char("Write your message.  (/s saves /h for help)\r\n\r\n", ch);
+  act("$n starts to write a message.", TRUE, ch, 0, 0, TO_ROOM);
+
+  if (!IS_NPC(ch))
+    SET_BIT(PLR_FLAGS(ch), PLR_WRITING);
+
+
+  ch->desc->str = &(MESG_DATA(message));
+  ch->desc->max_str = MAX_MESSAGE_LENGTH;
+  ch->desc->mail_to = board_vnum + BOARD_MAGIC;
+ 
+  return;
 
-  fclose(fl);
 }
 
+int mesglookup(struct board_msg_info *message,struct char_data *ch,
+		struct board_info_type *board) {
 
-void Board_reset_board(int board_type)
-{
-  int i;
+  int mem;
+  struct board_memory_type *mboard_type;
+
+  mem = ((MESG_TIMESTAMP(message)%301 + MESG_POSTER(message)%301)%301);
+
+  /* now, we check the mem slot. If its null, we return no, er.. 0..
+     if its full, we double check against the timestamp and reader - 
+     mislabled as poster, but who cares... if they're not true, we
+     go to the linked next slot, and repeat */
+  mboard_type=BOARD_MEMORY(board,mem);
+  while(mboard_type) {
 
-  for (i = 0; i < MAX_BOARD_MESSAGES; i++) {
-    if (MSG_HEADING(board_type, i))
-      free(MSG_HEADING(board_type, i));
-    if (msg_storage[MSG_SLOTNUM(board_type, i)])
-      free(msg_storage[MSG_SLOTNUM(board_type, i)]);
-    msg_storage_taken[MSG_SLOTNUM(board_type, i)] = 0;
-    memset((char *)&(msg_index[board_type][i]),0,sizeof(struct board_msginfo));
-    msg_index[board_type][i].slot_num = -1;
+    if(MEMORY_READER(mboard_type)==GET_IDNUM(ch) &&
+    	  MEMORY_TIMESTAMP(mboard_type)==MESG_TIMESTAMP(message)) {
+      return 1;
+    }
+    else {
+      mboard_type=MEMORY_NEXT(mboard_type);
+    }
   }
-  num_of_msgs[board_type] = 0;
-  unlink(FILENAME(board_type));
+  return 0;
 }
+
+
diff -uprN -x *.o ../src/boards.h ./boards.h
--- ../src/boards.h	Fri Apr 12 22:39:21 1996
+++ ./boards.h	Mon Dec 29 21:36:24 1997
@@ -1,54 +1,71 @@
-/* ************************************************************************
-*   File: boards.h                                      Part of CircleMUD *
-*  Usage: header file for bulletin boards                                 *
-*                                                                         *
-*  All rights reserved.  See license.doc for complete information.        *
-*                                                                         *
-*  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
-*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
-************************************************************************ */
-
-#define NUM_OF_BOARDS		4	/* change if needed! */
-#define MAX_BOARD_MESSAGES 	60      /* arbitrary -- change if needed */
 #define MAX_MESSAGE_LENGTH	4096	/* arbitrary -- change if needed */
 
-#define INDEX_SIZE	   ((NUM_OF_BOARDS*MAX_BOARD_MESSAGES) + 5)
-
+#define BOARD_DIRECTORY "etc/boards"
 #define BOARD_MAGIC	1048575	/* arbitrary number - see modify.c */
 
-struct board_msginfo {
-   int	slot_num;     /* pos of message in "master index" */
-   char	*heading;     /* pointer to message's heading */
-   int	level;        /* level of poster */
-   int	heading_len;  /* size of header (for file write) */
-   int	message_len;  /* size of message text (for file write) */
+struct board_msg_info {
+   long poster;       /* pointer to messages' poster's uid */
+   time_t timestamp;    /* time stamp */
+   char *subject; /* subject header */
+   char *data;   /* the actual post */
+   struct board_msg_info *next_message;   /* the next message! duh! */
+};
+
+/* sorry everyone, but inorder to allow for board memory, I had to make
+   this in the following nasty way.  Sorri. */
+
+struct board_memory_type {
+   int timestamp;
+   int reader;
+   struct board_memory_type *next;
 };
 
+
+
 struct board_info_type {
-   int	vnum;		/* vnum of this board */
-   int	read_lvl;	/* min level to read messages on this board */
-   int	write_lvl;	/* min level to write messages on this board */
-   int	remove_lvl;	/* min level to remove messages from this board */
-   char	filename[50];	/* file to save this board to */
-   int	rnum;		/* rnum of this board */
+   int  read_lvl;       /* min level to read messages on this board */
+   int  write_lvl;      /* min level to write messages on this board */
+   int  remove_lvl;     /* min level to remove messages from this board */
+   int  num_messages;           /* num messages of this board */
+   int  vnum;
+   struct board_info_type *next_board;
+   struct board_msg_info *messages;
+
+  /* why 301? why not?  It might not be the greatest, but if you really
+     know what a hash is, you'll realize that in this case, I didn't even
+     work on the algorithm, so it shouldn't make a bit of difference */
+
+   struct board_memory_type *memory[301];
 };
 
-#define BOARD_VNUM(i) (board_info[i].vnum)
-#define READ_LVL(i) (board_info[i].read_lvl)
-#define WRITE_LVL(i) (board_info[i].write_lvl)
-#define REMOVE_LVL(i) (board_info[i].remove_lvl)
-#define FILENAME(i) (board_info[i].filename)
-#define BOARD_RNUM(i) (board_info[i].rnum)
-
-#define NEW_MSG_INDEX(i) (msg_index[i][num_of_msgs[i]])
-#define MSG_HEADING(i, j) (msg_index[i][j].heading)
-#define MSG_SLOTNUM(i, j) (msg_index[i][j].slot_num)
-#define MSG_LEVEL(i, j) (msg_index[i][j].level)
-
-int	Board_display_msg(int board_type, struct char_data *ch, char *arg);
-int	Board_show_board(int board_type, struct char_data *ch, char *arg);
-int	Board_remove_msg(int board_type, struct char_data *ch, char *arg);
-void	Board_save_board(int board_type);
-void	Board_load_board(int board_type);
-void	Board_reset_board(int board_num);
-void	Board_write_message(int board_type, struct char_data *ch, char *arg);
+#define READ_LVL(i) (i->read_lvl)
+#define WRITE_LVL(i) (i->write_lvl)
+#define REMOVE_LVL(i) (i->remove_lvl)
+#define BOARD_MNUM(i) (i->num_messages)
+#define BOARD_VNUM(i) (i->vnum)
+#define BOARD_NEXT(i) (i->next_board)
+#define BOARD_MESSAGES(i) (i->messages)
+#define BOARD_MEMORY(i,j) (i->memory[j])
+
+#define MESG_POSTER(i) (i->poster)
+#define MESG_TIMESTAMP(i) (i->timestamp)
+#define MESG_SUBJECT(i) (i->subject)
+#define MESG_DATA(i) (i->data)
+#define MESG_NEXT(i) (i->next_message)
+
+#define MEMORY_TIMESTAMP(i) (i->timestamp)
+#define MEMORY_READER(i) (i->reader)
+#define MEMORY_NEXT(i) (i->next)
+
+void Board_init_boards(void);
+struct board_info_type * create_new_board(int board_vnum);
+void parse_message( FILE *fl, struct board_info_type *t_board);
+void look_at_boards(void);
+int Board_show_board(int board_vnum, struct char_data *ch);
+int Board_display_msg(int board_vnum, struct char_data * ch, int arg);
+int Board_remove_msg(int board_vnum, struct char_data * ch, int arg);
+int Board_save_board(int board_vnum);
+void Board_write_message(int board_vnum, struct char_data *ch, char *arg);
+void reverse_message_order(struct board_info_type *t_board);
+int mesglookup(struct board_msg_info *message,struct char_data *ch,
+		struct board_info_type *board);
diff -uprN -x *.o ../src/constants.c ./constants.c
--- ../src/constants.c	Mon Dec 29 21:57:42 1997
+++ ./constants.c	Mon Dec 29 21:36:24 1997
@@ -312,6 +312,7 @@ const char *item_types[] = {
   "PEN",
   "BOAT",
   "FOUNTAIN",
+  "BOARD",
   "\n"
 };
 
diff -uprN -x *.o ../src/db.c ./db.c
--- ../src/db.c	Tue Oct 28 23:16:24 1997
+++ ./db.c	Mon Dec 29 21:36:24 1997
@@ -23,6 +23,7 @@
 #include "mail.h"
 #include "interpreter.h"
 #include "house.h"
+#include "boards.h"
 
 /**************************************************************************
 *  declarations of most of the 'global' variables                         *
@@ -80,6 +81,7 @@ struct time_info_data time_info;/* the i
 struct weather_data weather_info;	/* the infomation about the weather */
 struct player_special_data dummy_mob;	/* dummy spec area for mobs	 */
 struct reset_q_type reset_q;	/* queue of zones to be reset	 */
+extern struct board_type_info *board_info;
 
 /* local functions */
 void setup_dir(FILE * fl, int room, int dir);
@@ -222,6 +224,9 @@ void boot_world(void)
 
   log("Renumbering zone table.");
   renum_zone_table();
+
+  log("Loading boards.");
+  Board_init_boards();
 
   if (!no_specials) {
     log("Loading shops.");
diff -uprN -x *.o ../src/interpreter.c ./interpreter.c
--- ../src/interpreter.c	Mon Dec 29 21:57:42 1997
+++ ./interpreter.c	Mon Dec 29 21:36:24 1997
@@ -24,7 +24,6 @@
 #include "screen.h"
 #include "olc.h"
 
-
 extern const struct title_type titles[NUM_CLASSES][LVL_IMPL + 1];
 extern char *motd;
 extern char *imotd;
diff -uprN -x *.o ../src/oedit.c ./oedit.c
--- ../src/oedit.c	Mon Dec 29 21:57:42 1997
+++ ./oedit.c	Mon Dec 29 21:36:24 1997
@@ -37,7 +37,7 @@ extern char *drinks[];
 extern char *apply_types[];
 extern char *container_bits[];
 extern char *spells[];
-extern struct board_info_type board_info[];
+extern struct board_info_type *board_info;
 extern struct descriptor_data *descriptor_list;
 
 /*------------------------------------------------------------------------*/
@@ -303,13 +303,6 @@ void oedit_save_internally(struct descri
 	}
 
     /*
-     * Renumber notice boards.
-     */
-    for (i = 0; i < NUM_OF_BOARDS; i++)
-      if (BOARD_RNUM(i) >= robj_num)
-	BOARD_RNUM(i) = BOARD_RNUM(i) + 1;
-
-    /*
      * Renumber shop produce.
      */
     for (shop = 0; shop < top_shop; shop++)
@@ -629,6 +622,9 @@ void oedit_disp_val1_menu(struct descrip
      * This is supposed to be language, but it's unused.
      */
     break;
+  case ITEM_BOARD:
+    send_to_char("Enter the minimum level to read this board: ",d->character);
+    break;
   default:
     oedit_disp_menu(d);
   }
@@ -668,6 +664,9 @@ void oedit_disp_val2_menu(struct descrip
   case ITEM_FOUNTAIN:
     send_to_char("Initial drink units : ", d->character);
     break;
+  case ITEM_BOARD:
+    send_to_char("Minimum level to write: ",d->character);
+    break;
   default:
     oedit_disp_menu(d);
   }
@@ -701,6 +700,9 @@ void oedit_disp_val3_menu(struct descrip
   case ITEM_FOUNTAIN:
     oedit_liquid_type(d);
     break;
+  case ITEM_BOARD:
+    send_to_char("Minimum level to remove messages: ",d->character);
+    break;
   default:
     oedit_disp_menu(d);
   }
@@ -726,6 +728,9 @@ void oedit_disp_val4_menu(struct descrip
   case ITEM_FOUNTAIN:
   case ITEM_FOOD:
     send_to_char("Poisoned (0 = not poison) : ", d->character);
+    break;
+  case ITEM_BOARD:
+    Board_save_board(GET_OBJ_VNUM(OLC_OBJ(d)));
     break;
   default:
     oedit_disp_menu(d);
diff -uprN -x *.o ../src/olc.h ./olc.h
--- ../src/olc.h	Mon Dec 29 21:57:42 1997
+++ ./olc.h	Mon Dec 29 21:36:24 1997
@@ -37,7 +37,7 @@
 #define NUM_AFF_FLAGS		22
 #define NUM_ATTACK_TYPES	15
 
-#define NUM_ITEM_TYPES		24
+#define NUM_ITEM_TYPES		25
 #define NUM_ITEM_FLAGS		17
 #define NUM_ITEM_WEARS 		15
 #define NUM_APPLIES		25
diff -uprN -x *.o ../src/spec_assign.c ./spec_assign.c
--- ../src/spec_assign.c	Fri Apr 12 22:39:22 1996
+++ ./spec_assign.c	Mon Dec 29 21:36:24 1997
@@ -273,12 +273,6 @@ void assign_mobiles(void)
 void assign_objects(void)
 {
   SPECIAL(bank);
-  SPECIAL(gen_board);
-
-  ASSIGNOBJ(3096, gen_board);	/* social board */
-  ASSIGNOBJ(3097, gen_board);	/* freeze board */
-  ASSIGNOBJ(3098, gen_board);	/* immortal board */
-  ASSIGNOBJ(3099, gen_board);	/* mortal board */
 
   ASSIGNOBJ(3034, bank);	/* atm */
   ASSIGNOBJ(3036, bank);	/* cashcard */
diff -uprN -x *.o ../src/structs.h ./structs.h
--- ../src/structs.h	Mon Dec 29 21:57:42 1997
+++ ./structs.h	Mon Dec 29 21:36:24 1997
@@ -283,7 +283,7 @@
 #define ITEM_PEN       21		/* Item is a pen		*/
 #define ITEM_BOAT      22		/* Item is a boat		*/
 #define ITEM_FOUNTAIN  23		/* Item is a fountain		*/
-
+#define ITEM_BOARD     24		/* Item is a board		*/
 
 /* Take/Wear flags: used by obj_data.obj_flags.wear_flags */
 #define ITEM_WEAR_TAKE		(1 << 0)  /* Item can be takes		*/
