/
LIB3/
LIB3/D/ADMIN/
LIB3/D/ADMIN/OBJ/
LIB3/D/ADMIN/ROOM/W/
LIB3/D/HOME/
LIB3/D/HOME/CITY/ARENA/
LIB3/D/HOME/CITY/ITEMS/
LIB3/D/HOME/CITY/POSTOFFI/
LIB3/DOC/
LIB3/GLOBAL/SPECIAL/
LIB3/GLOBAL/VIRTUAL/
LIB3/NET/
LIB3/NET/CONFIG/
LIB3/NET/DAEMON/CHARS/
LIB3/NET/GOPHER/
LIB3/NET/INHERIT/
LIB3/NET/OBJ/
LIB3/NET/SAVE/
LIB3/NET/VIRTUAL/
LIB3/OBJ/B_DAY/
LIB3/OBJ/HANDLERS/TERM_TYP/
LIB3/PLAYERS/B/
LIB3/PLAYERS/N/
LIB3/ROOM/
LIB3/SAVE/
LIB3/SAVE/BOARDS/
LIB3/SAVE/ENVIRON/
LIB3/SAVE/POST/
LIB3/STD/COMMANDS/SHADOWS/
LIB3/STD/CREATOR/
LIB3/STD/DOM/
LIB3/STD/EFFECTS/
LIB3/STD/EFFECTS/HEALING/
LIB3/STD/EFFECTS/OTHER/
LIB3/STD/EFFECTS/POISONS/
LIB3/STD/ENVIRON/
LIB3/STD/GUILDS/
LIB3/STD/LIQUIDS/
LIB3/STD/ROOM/
LIB3/STD/TRIGGER/SHADOW/
LIB3/W/
LIB3/W/BANNOR/
LIB3/W/NEWSTYLE/
#include "mail.h"
inherit "/obj/misc/board";

/* Modified by Nivek, 5/1/94, removing the 'mark current as read'
 * thing, which was causing many to miss a number of notes.  The
 * 'skip' command does the same thing.
 * Also added some more feedback to the 'new' command, and fixed some
 * minor spacing things in 'next' and 'prev'.
 * Me again, 5/8/94, adding a 'board' command with no args, which
 * tells which board you're holding, and how many new notes there
 * are.
 */

#include "board.h"

void    setup()
{
    ::setup();
    action_pri = 3;
    reset_drop();
    set_get();
}				/* setup() */

int     help( string str )
{
    if( str != "board" )
	return 0;
    write( 
	      "%^YELLOW%^Commands for this board are:%^RESET%^\n" +
	      "read <note number>          - Read a note.\n" +
	      "post <subject>              - Post a new note\n" +
	      "boards                      - List all boards.\n" +
	      "store <note number> <file>  - Save note to file.\n" +
	      "eat <note number>           - Remove an note.\n" +
	      "reply <note number>         - Send mail to the poster.\n" +
	      "followup <note number>      - Post a followup note\n" +
	      "summary [all]               - List boards with new notes.\n" +
	      "next                        - Goto next board.\n" +
	      "prev                        - Goto prev board.\n" +
	      "new                         - Goto next board with new notes.\n" +
	      "board <board name>          - Goto named board.\n" +
	      "skip                        - Mark all notes as read.\n" +
	      "%^YELLOW%^Board configuration commands:%^RESET%^\n" +
	      "timeout <time>              - Set note experation time.\n" +
	      "minimum <num>               - Min number to leave active.\n" +
	      "maximum <num>               - Max notes before auto experation.\n" +
	      "archive <name|none>         - Archive file name.\n" +
	      "security                    - List who can access this board.\n" +
	      "add <name>                  - Add someone to the access list.\n" +
	      "remove <name>               - Remove someone from the access list.\n" +
	      "arts                        - Give file names of notes.\n" +
	      "killfile <board name>     - Set your kill file for this board.\n" );
    return 1;
}

/*
 * Need to redefine this to add all the extra bits and wombles to it.
 */
string long( string str, int dark )
{
    int     i, irp;
    mixed  *stuff;
    string  ret, help;
    mapping news_rc;

    help = "Use 'help board' for instructions.\n";
    stuff = (mixed *)BOARD_HAND->get_subjects( board_name );
    ret = "A bulletin board (" + board_name + ").\n";
    irp = (int)BOARD_HAND->query_minimum( board_name );
    if( irp )
	ret += "Minimum number of messages left by auto magic deletion is " + irp +
	    ".\n";
    irp = (int)BOARD_HAND->query_maximum( board_name );
    if( irp )
	ret += "Maximum number of messages on this board is " + irp + ".\n";
    irp = (int)BOARD_HAND->query_timeout( board_name );
    if( irp )
	ret += "Messages will automaticaly time out in " + irp + " days.\n";
    irp = (int)BOARD_HAND->query_archive( board_name );
    if( irp )
	ret += "Deleted messages are archived in " + irp + ".\n";
    ret += help;
    if( !sizeof( stuff ) )
	return ret + "The board is completely empty.\n";
    news_rc = (mapping)this_player()->query_property( NEWS_RC );
    if( !news_rc )
	news_rc = ([ ]);
    for( i = 0; i < sizeof( stuff ); i++ )
	if( news_rc[ board_name ] < stuff[ i ][ B_TIME ] )
	    ret += sprintf( "N %2d: %-=*s\n", i + 1, ( int ) this_player()->query_cols() - 6,
			    stuff[ i ][ B_SUBJECT ] + " (" +
			    capitalize( stuff[ i ][ B_NAME ] ) + " " + the_date( stuff[ i ][ B_TIME ] ) + ")" );

	else
	    ret += sprintf( "  %2d: %-=*s\n", i + 1, ( int ) this_player()->query_cols() - 6,
			    stuff[ i ][ B_SUBJECT ] + " (" +
			    capitalize( stuff[ i ][ B_NAME ] ) + " " + the_date( stuff[ i ][ B_TIME ] ) + ")" );

    return ret;
}				/* long() */

void    init()
{
    ::init();
    add_action( "save_note", "store", action_pri );
    add_action( "next", "next", action_pri );
    add_action( "prev", "prev", action_pri );
    add_action( "new", "new", action_pri );
    add_action( "board", "b*oard", action_pri );
    add_action( "list_boards", "boards", action_pri );
    add_action( "kfile", "killfile", action_pri );
    add_action( "do_security", "security", action_pri );
    add_action( "do_add", "add" );
    add_action( "do_remove", "remove" );
    add_action( "do_timeout", "timeout" );
    add_action( "do_minimum", "minimum" );
    add_action( "do_maximum", "maximum" );
    add_action( "do_archive", "archive" );
    add_action( "do_summary", "summary" );
    add_action( "do_skip", "skip" );
    add_action( "do_art_nos", "arts" );
    add_action( "help", "help", 1 );
}				/* init() */

int     save_note( string arg )
{
    int     which;
    string  file;
    mixed * stuff;

    if( !arg || (sscanf( arg, "%d %s", which, file ) != 2) )
    {
	notify_fail( "Syntax: store <note number> <file name>\n" );
	return 0;
    }
    stuff = (mixed *)BOARD_HAND->get_subjects( board_name );
    if( which < 1 || which > sizeof( stuff ) )
    {
	notify_fail( "Invalid note number.\n" );
	return 0;
    }
    which--;			/* 1..n */
    file += ".note";
    if( !MASTER_OB->valid_write( file, this_player()->query_name() ) )
    {
	notify_fail( "The master object appears and prevents you.\n" );
	return 0;
    }
    seteuid( "Root" );
    write_file( file, stuff[ which ][ B_SUBJECT ] + "\n\n" +
		BOARD_HAND->get_message( board_name, which ) );
    write( "Ok.\n" );
    return 1;
}				/* save_note() */

void    set_board_name( string str )
{
    board_name = str;
}
void    set_datafile( string str )
{
    board_name = str;
}

int     next()
{
    int     i;
    string *boards;

    boards = (string *)BOARD_HAND->list_of_boards();
    if( (i = member_array( board_name, boards )) == -1 )
	i = 0;
    else
	i = (i + 1) % sizeof( boards );
    board_name = boards[ i ];
    write( "Gone to board: " + board_name + ".\n" );
    return 1;
}				/* next() */

int     prev()
{
    int     i;
    string *boards;

    boards = (string *)BOARD_HAND->list_of_boards();
    if( (i = member_array( board_name, boards )) == -1 )
	i = 0;
    else
	i = (i - 1 + sizeof( boards )) % sizeof( boards );
    board_name = boards[ i ];
    write( "Gone to board: " + board_name + ".\n" );
    return 1;
}				/* prev() */

int     kfile( string arg )
{
    this_player()->add_property( "news_kill_" + lower_case( arg ), 1 );
    return 1;
}				/* kfile() */

int     new()
{
    int     i;
    string *boards;
    mixed * stuff;
    mixed   otherstuff;
    mapping news_rc;

    boards = (string *)BOARD_HAND->list_of_boards();
/* start from the begining and search for one with new notes. */
    news_rc = (mapping)this_player()->query_property( NEWS_RC );

    for( i = 0; i < sizeof( boards ); i++ )
    {
	if( !this_player()->query_property( "news_kill_" + boards[ i ] ) )
	{
	    stuff = (mixed *)BOARD_HAND->get_subjects( boards[ i ] );
	    if( !sizeof( stuff ) )
		continue;
            if ( find_new( boards[ i ] ) )
	    {
		board_name = boards[ i ];
		write( "The " + board_name + " board has new messages.\n" );
		return 1;
	    }
	}
    }
    notify_fail( "No boards with new messages.\n" );
    return 0;
}				/* new() */

int     board( string str )
{
    int     i;
    string *boards;

    if( !str )
    {
        i = sizeof( (mixed *)BOARD_HAND->get_subjects( board_name )
                  );
        write( "You are switched to the " + board_name 
               + " board, with " +
               (
                 ( find_new( board_name ) )?
                 ( i - find_new( board_name ) + 1 )
                 : "no"
               )
               + " new messages.\n" );
        return 1;
    }
    boards = (string *)BOARD_HAND->list_of_boards();
    if( (i = member_array( str, boards )) == -1 )
    {
	notify_fail( "The board " + str + " does not exist sorry.\n" );
	return 0;
    }
    write( "Board changed to " + str + ", which " +
           ( ( find_new( str ) )? "has" : "does not have" )
           + " new messages.\n" );
    board_name = str;
    return 1;
}				/* board() */

int     list_boards()
{
    write( "The current boards are '" +
	   implode( (string *)BOARD_HAND->list_of_boards(), "', '" ) + "'.\n" );
    return 1;
}				/* boards() */

int     do_security()
{
    write( "The current people in this boards security array are :\n" +
	   implode( (string *)BOARD_HAND->query_security( board_name ), ", " ) + "\n" );
    return 1;
}				/* do_security() */

int     do_add( string name )
{
    if( this_player() != this_player( 1 ) ||
	    !interactive( previous_object() ) )
	return 0;
    notify_fail( "Syntax: " + query_verb() + " <name>\n" );
    return( int ) BOARD_HAND->add_allowed( board_name, name );
}				/* do_add() */

int     do_remove( string name )
{
    if( this_player() != this_player( 1 ) ||
	    !interactive( previous_object() ) )
	return 0;
    notify_fail( "Syntax: " + query_verb() + " <name>\n" );
    return( int ) BOARD_HAND->remove_allowed( board_name, name );
}				/* do_remove() */

int     do_timeout( string name )
{
    int     i;

    if( this_player() != this_player( 1 ) ||
	    !interactive( previous_object() ) )
	return 0;
    notify_fail( "Syntax: " + query_verb() + " <name>\n" );
    if( !name || sscanf( name, "%d", i ) != 1 )
	return 0;
    return( int ) BOARD_HAND->set_timeout( board_name, i );
}				/* do_timeout() */

int     do_minimum( string name )
{
    int     i;

    if( this_player() != this_player( 1 ) ||
	    !interactive( previous_object() ) )
	return 0;
    notify_fail( "Syntax: " + query_verb() + " <name>\n" );
    if( !name || sscanf( name, "%d", i ) != 1 )
	return 0;
    return( int ) BOARD_HAND->set_minimum( board_name, i );
}				/* do_minimum() */

int     do_maximum( string name )
{
    int     i;

    if( this_player() != this_player( 1 ) ||
	    !interactive( previous_object() ) )
	return 0;
    notify_fail( "Syntax: " + query_verb() + " <name>\n" );
    if( !name || (sscanf( name, "%d", i ) != 1) )
	return 0;
    printf( "here\n" );
    return( int ) BOARD_HAND->set_maximum( board_name, i );
}				/* do_maximum() */

int     do_archive( string name )
{
    if( this_player() != this_player( 1 ) ||
	    !interactive( previous_object() ) )
	return 0;
    if( !name )
	return 0;
    if( name != "none" )
	return( int ) BOARD_HAND->set_archive( board_name, name );
    return( int ) BOARD_HAND->set_archive( board_name );
}				/* do_archive() */

move( object dest, string s1, string s2 )
{
    int     ret;

    if( !objectp( dest ) )
	return ::move( dest, s1, s2 );
    if( interactive( dest ) )
    {
	ret =::move( dest, s1, s2 );
	if( ret )
	    return ret;
	seteuid( geteuid( dest ) );
	return 0;
    }
    return ::move( dest, s1, s2 );
}				/* move() */

mixed   query_static_auto_load()
{
    return board_name;
}				/* query_static_auto_load() */

void    init_static_arg( mixed board )
{
    if( stringp( board ) )
	board_name = board;
}				/* init_static_auto_load() */

/* Much of the following code is ugly.  This is entirely my fault.
 * After adding find_new(), I found that I had to change this
 * function as well, and I did it in a sloppy, piecewise manner,
 * and I'm tired and lazy and I haven't slept in a long time and
 * my back hurts and I have a load of stuff to move upstairs from
 * the garage, etc., etc.
 *    Nivek
 */
int     do_summary( string str )
{
    int     i, no, amt;
    string *boards;
    mapping news_rc;
    mixed * stuff;

    boards = (string *)BOARD_HAND->list_of_boards();
/* start from the begining and search for one with new notes. */
    news_rc = (mapping)this_player()->query_property( NEWS_RC );
    if ( !news_rc )  news_rc = ([ ]);
    for( i = 0; i < sizeof( boards ); i++ )
    {
	if( !this_player()->query_property( "news_kill_" + boards[ i ] ) )
	{
	    stuff = (mixed *)BOARD_HAND->get_subjects( boards[ i ] );
	    if( !sizeof( stuff ) )
		continue;
            amt = find_new( boards[ i ] );
            if ( amt )  amt -= 2;
            else
                amt = sizeof( stuff ) - 1;
	    if( amt != sizeof( stuff ) - 1 )
	    {
		write( "The " + boards[ i ] + " board has " + (sizeof( stuff ) - amt - 1) +
		       " new messages.\n" );
		no++;
	    }
	    else
		if( str == "all" )
		{
		    write( "The " + boards[ i ] + " board has no new messages.\n" );
		    no++;
		}
	}
    }
    notify_fail( "No boards with new messages.\n" );
    return no;
}				/* do_summary() */

/* Skip does the same as a new, but marks the board as read. */
int     do_skip()
{
    mapping news_rc;
    mixed * otherstuff;

    news_rc = (mapping)this_player()->query_property( NEWS_RC );
    otherstuff = (mixed *)BOARD_HAND->get_subjects( board_name );
    if( sizeof( otherstuff ) )
    {
	news_rc[ board_name ] = otherstuff[ sizeof( otherstuff ) - 1 ][ B_TIME ];
	this_player()->add_property( NEWS_RC, news_rc );
    }
    write( "Marked all of " + board_name + " as read.\n" );
    if( !new() )
    {
	write( "No new messages.\n" );
    }
    return 1;
}				/* do_skip() */

int     do_art_nos()
{
    int     i;
    mixed * otherstuff;

    otherstuff = (mixed *)BOARD_HAND->get_subjects( board_name );
    for( i = 0; i < sizeof( otherstuff ); i++ )
	printf( "%2d# %-20s %d\n", i, otherstuff[ i ][ B_NAME ], otherstuff[ i ][ B_NUM ] );
    return 1;
}				/* do_art_nos() */