/*
DaleMUD v2.0 Released 2/1994
See license.doc for distribution terms. DaleMUD is based on DIKUMUD
*/
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "protos.h"
#define MAX_MSGS 99 /* Max number of messages. */
#define MAX_MESSAGE_LENGTH 2048 /* that should be enough */
#define NUM_BOARDS 3
struct message {
char *date;
char *title;
char *author;
char *text;
};
struct board {
struct message msg[MAX_MSGS+1];
int number;
};
static struct board_lock_struct {
struct char_data *locked_for;
bool lock;
} board_lock[NUM_BOARDS];
int min_read_level[] = { 0, 51, 1};
int min_write_level[] = { 1, 51, 1};
int min_remove_level[] = { 51, 51, 51};
struct board boards[NUM_BOARDS];
struct board *curr_board;
struct message *curr_msg;
extern struct char_data *character_list;
/* This sets the minimum level needed to read/write/look at these boards
mainly included to enable the creation of a "wizard-only" board */
char save_file[NUM_BOARDS][20] = {
"mortal.board" , "wiz.board", "skexie.board" };
/* These are the binary files in which to save/load messages */
void board_write_msg(struct char_data *ch, char *arg, int bnum);
int board_display_msg(struct char_data *ch, char *arg, int bnum);
int board_remove_msg(struct char_data *ch, char *arg, int bnum);
void board_save_board();
void board_load_board();
int board_show_board(struct char_data *ch, char *arg, int bnum);
/* board.c version 1.2 - Jun 1991 by Twilight.
1.2 changes:
c Added a board and message structure
took out all pointers in an effort to insure integrity in memory.
Added differentiation between minimum read levels and minimum write/remove
levels.
1.1 changes:
Major repairs-- now allows multiple boards define at compile-time. Set the
constants NUM_BOARDS and add the new V-Numbers to the if/then structure directly
below. Also you must attach the board.c procedure in spec_assign.c as usual.
Log message removals and restrict them to level 15 and above.
Fixed act message resulting from message removal
Removed unused procedure "fix_long_desc"
Added a message to inform others in room of a read in progress
Added minimum level check for each board
(defined in array min_board_level[NUM_BOARDS]
*/
int board(struct char_data *ch, int cmd, char *arg, struct obj_data *obj, int type)
{
static int has_loaded = 0;
char buf[80];
int bnum = -1;
int obj_num;
if (type != PULSE_COMMAND)
return(FALSE);
if (!ch->desc)
return(0); /* By MS or all NPC's will be trapped at the board */
if (!has_loaded)
{
board_load_board();
has_loaded = 1;
}
if (!cmd)
return(FALSE);
/* Identify which board we're dealing with */
obj_num = (obj->item_number);
if (obj_num == (real_object(3099))) bnum = 0;
else if (obj_num == (real_object(3098))) bnum = 1;
else if (obj_num == (real_object(3097))) bnum = 2;
switch (cmd) {
case 15: /* look */
return(board_show_board(ch, arg, bnum));
case 149: /* write */
board_write_msg(ch, arg, bnum);
return 1;
case 63: /* read */
return(board_display_msg(ch, arg, bnum));
case 66: /* remove */
return(board_remove_msg(ch, arg, bnum));
default:
return 0;
}
}
void board_write_msg(struct char_data *ch, char *arg, int bnum) {
int highmessage;
char buf[MAX_STRING_LENGTH];
long ct; /* clock time */
char *tmstr;
extern struct time_info_data time_info;
extern char *month_name[];
if ( bnum == -1 ) {
log("Board special procedure called for non-board object.\r\n");
send_to_char("This board is not in operation at this time.\n\r", ch);
return;
}
curr_board = &boards[bnum];
if (GetMaxLevel(ch) < min_write_level[bnum]) {
send_to_char("You pick up a quill to write, but realize you're not powerful enough\n\r",ch);
send_to_char("to submit intelligent material to THIS board.\n\r",ch);
return;
}
if ( (curr_board->number) > (MAX_MSGS - 1) ) {
send_to_char("The board is full already.\n\r", ch);
return;
}
/* Check for locks, return if lock is found on this board */
if (board_check_locks(bnum, ch))
return;
/* skip blanks */
for(; isspace(*arg); arg++);
if (!*arg) {
send_to_char("The board has now been saved permanently to disk.\n\rTo write a new message, use WRITE followed by a title.\n\r", ch);
return;
}
/* Now we're committed to writing a message. Let's lock the board. */
board_lock[bnum].lock = 1;
board_lock[bnum].locked_for = ch;
/* Lock set */
highmessage = boards[bnum].number;
curr_msg = &curr_board->msg[++highmessage];
if (!(strcmp("Topic",arg))) {
curr_msg = &curr_board->msg[0];
if (curr_msg->title)
free(curr_msg->title);
if (curr_msg->text)
free(curr_msg->text);
if (curr_msg->author)
free(curr_msg->author);
if (curr_msg->date)
free(curr_msg->date);
(boards[bnum].number)--;
}
curr_msg->title = (char *)malloc(strlen(arg)+1);
strcpy(curr_msg->title, arg);
curr_msg->author = (char *)malloc(strlen(GET_NAME(ch))+1);
strcpy(curr_msg->author, GET_NAME(ch));
ct = time(0);
tmstr = (char *)asctime(localtime(&ct));
*(tmstr + strlen(tmstr) - 1) = '\0';
sprintf(buf,"%.10s",tmstr);
curr_msg->date = (char *)malloc(strlen(buf)+1);
strcpy(curr_msg->date, buf);
send_to_char("Write your message. Terminate with a @.\n\r\n\r", ch);
act("$n starts to write a message.", TRUE, ch, 0, 0, TO_ROOM);
/* Take care of free-ing and zeroing if the message text is already
allocated previously */
if (curr_msg->text)
free (curr_msg->text);
curr_msg->text = 0;
/* Initiate the string_add procedures from comm.c */
ch->desc->str = &curr_msg->text;
ch->desc->max_str = MAX_MESSAGE_LENGTH;
boards[bnum].number +=1;
if (boards[bnum].number < 0)
boards[bnum].number = 0;
}
int board_remove_msg(struct char_data *ch, char *arg, int bnum) {
/* This should now be fixed so that low level chars can remove armor and such. */
int ind, tmessage;
char buf[256], number[MAX_INPUT_LENGTH];
one_argument(arg, number);
if (!*number || !isdigit(*number))
return(0);
if (!(tmessage = atoi(number))) return(0);
if ( bnum == -1 ) {
log("Board special procedure called for non-board object.\r\n");
send_to_char("This board is not in operation at this time.\n\r", ch);
return 1;
}
curr_board = &boards[bnum];
if (GetMaxLevel(ch) < min_remove_level[bnum]) {
send_to_char("You try and grab one of the notes of the board but get a nasty\n\r",ch);
send_to_char("shock. Maybe you'd better leave it alone.\n\r",ch);
return 1;
}
if (curr_board->number < 1) {
send_to_char("The board is empty!\n\r", ch);
return(1);
}
if (tmessage < 0 || tmessage > curr_board->number) {
send_to_char("That message exists only in your imagination.\n\r",
ch);
return(1);
}
/* Check for board locks, return if lock is found */
if (board_check_locks(bnum, ch))
return(1);
ind = tmessage;
if (curr_board->msg[ind].text)
free(curr_board->msg[ind].text);
if (curr_board->msg[ind].date)
free(curr_board->msg[ind].date);
if (curr_board->msg[ind].author)
free(curr_board->msg[ind].author);
if (curr_board->msg[ind].title)
free(curr_board->msg[ind].title);
for ( ; ind < (curr_board->number) ; ind++ )
curr_board->msg[ind] = curr_board->msg[ind+1];
/* You MUST do this, or the next message written after a remove will */
/* end up doing a free(curr_board->msg[ind].text) because it's not!! */
/* Causing strange shit to happen, because now the message has a */
/* To a memory location that doesn't exist, and if THAT message gets */
/* Removed, it will destroy what it's pointing to. THIS is the board */
/* Bug we've been looking for! -=>White Gold<=- */
curr_board->msg[curr_board->number].text = NULL;
curr_board->msg[curr_board->number].date = NULL;
curr_board->msg[curr_board->number].author = NULL;
curr_board->msg[curr_board->number].title = NULL;
curr_board->number--;
send_to_char("Message removed.\n\r", ch);
sprintf(buf, "%s just removed message %d.", ch->player.name, tmessage);
/* Removal message also repaired */
act(buf, FALSE, ch, 0, 0, TO_ROOM);
sprintf((buf+strlen(buf)-1)," from board %d.",bnum);
log(buf); /* Message removals now logged. */
board_save_board(bnum);
return(1);
}
char *fix_returns(char *text_string)
{
char *localbuf;
int point=0;
int point2 = 0;
if (!text_string) {
CREATE(localbuf,char,2);
strcpy(localbuf,"\n");
return(localbuf);
}
if (!(*text_string)) {
CREATE(localbuf,char,strlen("(NULL)")+1);
strcpy(localbuf,"(NULL)");
return(localbuf);
}
CREATE(localbuf,char,strlen(text_string));
while(*(text_string+point) != '\0')
if (*(text_string+point) != '\r') {
*(localbuf+point2) = *(text_string+point);
point2++;
point++;
}
else
point++;
*(localbuf + point2) = '\0'; /* You never made sure of null termination */
return(localbuf);
}
void board_save_board(bnum) {
FILE *the_file;
int ind;
char buf[256];
char *temp_add;
/* We're assuming the board number is valid since it was passed by
out own code */
curr_board = &boards[bnum];
the_file = fopen(save_file[bnum], "w");
if (!the_file) {
log("Unable to open/create savefile for bulletin board..\n\r");
return;
}
fprintf(the_file," %d ", curr_board->number);
for (ind = 0; ind <= curr_board->number; ind++) {
curr_msg = &curr_board->msg[ind];
fwrite_string(the_file,curr_msg->title);
fwrite_string(the_file,curr_msg->author);
fwrite_string(the_file,curr_msg->date);
fwrite_string(the_file,(temp_add = fix_returns(curr_msg->text)));
if (temp_add)
free(temp_add);
}
fclose(the_file);
return;
}
void board_load_board() {
FILE *the_file;
int ind;
int bnum;
char buf[256];
memset(boards, 0, sizeof(boards)); /* Zero out the array, make sure no */
/* Funky pointers are left in the */
/* Allocated space */
for ( bnum = 0 ; bnum < NUM_BOARDS ; bnum++ ) {
board_lock[bnum].lock = 0;
board_lock[bnum].locked_for = 0;
}
for (bnum = 0; bnum < NUM_BOARDS; bnum++) {
boards[bnum].number = -1;
the_file = fopen(save_file[bnum], "r");
if (!the_file) {
sprintf(buf,"Can't open message file for board %d.\n\r",bnum);
log(buf,0);
continue;
}
fscanf( the_file, " %d ", &boards[bnum].number);
if (boards[bnum].number < 0 || boards[bnum].number > MAX_MSGS ||
feof(the_file))
{ sprintf(buf,
"Board-message file corrupt, nonexistent, or empty(Bnum:%d).\n\r",
boards[bnum].number);
log(buf);
boards[bnum].number = -1;
fclose(the_file);
continue;
}
curr_board = &boards[bnum];
for (ind = 0; ind <= curr_board->number; ind++) {
curr_msg = &curr_board->msg[ind];
curr_msg->title = (char *)fread_string (the_file);
curr_msg->author = (char *)fread_string (the_file);
curr_msg->date = (char *)fread_string (the_file);
curr_msg->text = (char *)fread_string (the_file);
}
fclose(the_file);
}
}
int board_display_msg(struct char_data *ch, char *arg, int bnum)
{
char buf[512], number[MAX_INPUT_LENGTH], buffer[MAX_STRING_LENGTH];
int tmessage;
one_argument(arg, number);
if (!*number || !isdigit(*number))
return(0);
if (!(tmessage = atoi(number))) return(0);
curr_board = &boards[bnum];
if ((boards[bnum].number != -1) &&
(tmessage >= 0 && tmessage <= curr_board->number) &&
(GetMaxLevel(ch) < min_read_level[bnum]) &&
(strcmp(GET_NAME(ch), curr_board->msg[tmessage].author))) ;
else
if ( GetMaxLevel(ch) < min_read_level[bnum] ) {
send_to_char("You try and look at the messages on the board but you\n\r",
ch);
send_to_char("cannot comprehend their meaning.\n\r\n\r",ch);
act("$n tried to read the board, but looks bewildered.",TRUE,ch, 0, 0,
TO_ROOM);
return(1);
}
if (boards[bnum].number == -1) {
send_to_char("The board is empty!\n\r", ch);
return(1);
}
if (tmessage < 0 || tmessage > curr_board->number) {
send_to_char("That message exists only in your imagination.\n\r",ch);
return(1);
}
curr_msg = &curr_board->msg[tmessage];
sprintf(buffer, "Message %2d (%s): %-15s -- %s", tmessage, curr_msg->date, curr_msg->author, curr_msg->title );
sprintf(buffer + strlen(buffer), "\n\r----------\n\r%s", (curr_msg->text?curr_msg->text:"(null)"));
page_string(ch->desc, buffer, 1);
return(1);
/*
sprintf(buf, "$n reads message %d titled : %s.",tmessage, curr_msg->title);
act(buf, TRUE, ch, 0, 0, TO_ROOM);
*/
}
int board_show_board(struct char_data *ch, char *arg, int bnum)
{
int i;
char buf[MAX_STRING_LENGTH], tmp[MAX_INPUT_LENGTH];
one_argument(arg, tmp);
if (!*tmp || !isname(tmp, "board bulletin"))
return(0);
if ((GetMaxLevel(ch) < min_read_level[bnum]) && (bnum !=5))
/* Skip if board 5 (Reimb board) */
{
send_to_char("You try and look at the messages on the board but you\n\r",ch);
send_to_char("cannot comprehend their meaning.\n\r",ch);
act("$n tried to read the board, but looks bewildered.",TRUE,ch, 0, 0, TO_ROOM);
return(1);
}
curr_board = &boards[bnum];
act("$n studies the board.", TRUE, ch, 0, 0, TO_ROOM);
strcpy(buf,"This is a bulletin board. Usage: READ/REMOVE <messg #>, WRITE <header>\n\r");
if (boards[bnum].number == -1)
strcat(buf, "The board is empty.\n\r");
else {
sprintf(buf + strlen(buf), "There are %d messages on the board.\n\r",
curr_board->number);
sprintf(buf + strlen(buf), "\n\rBoard Topic:\n\r%s------------\n\r",curr_board->msg[0].text);
for ( i = 1 ; i <= curr_board->number ; i++ )
/* if (((GET_MAX_LEVEL(ch) < min_read_level[bnum]) &&
(strcmp(ch->name, curr_board->msg[i].author))) ||
(GET_MAX_LEVEL(ch) >= min_read_level[bnum])) */
sprintf(buf + strlen(buf), "%-2d : %-15s (%s) -- %s\n\r", i ,
curr_board->msg[i].author, curr_board->msg[i].date,
curr_board->msg[i].title);
}
page_string(ch->desc, buf, 1);
return(1);
}
/*
int fwrite_string (char *buf, FILE *fl)
{
return (fprintf(fl, "%s~\n", buf));
}
*/
int board_check_locks (int bnum, struct char_data *ch) {
char buf[MAX_INPUT_LENGTH];
struct char_data *tmp_char;
bool found = FALSE;
if (!board_lock[bnum].lock) return(0);
/* FIRST lets' see if this character is even in the game anymore! -WG-*/
for (tmp_char = character_list; tmp_char; tmp_char = tmp_char->next)
{
if (tmp_char == board_lock[bnum].locked_for)
{
found = TRUE;
break;
}
}
if (!found)
{
log("Board: board locked for a user not in game.");
board_lock[bnum].lock = 0;
board_lock[bnum].locked_for = NULL;
return(0);
}
/* Check for link-death of lock holder */
if (!board_lock[bnum].locked_for->desc) {
sprintf(buf,"You push %s aside and approach the board.\n\r",board_lock[bnum].locked_for->player.name);
send_to_char(buf, ch);
}
/* Else see if lock holder is still in write-string mode */
else if (board_lock[bnum].locked_for->desc->str) { /* Lock still holding */
sprintf(buf,"You try to approach the board but %s blocks your way.\n\r",board_lock[bnum].locked_for->player.name);
send_to_char(buf, ch);
return (1);
}
/* Otherwise, the lock has been lifted */
board_save_board(bnum);
board_lock[bnum].lock = 0;
board_lock[bnum].locked_for = 0;
return(0);
}