#include <mail.h> #include <board.h>; inherit OBJECT_OBJ; #define DEBUG_ME string board_name; // Variables used to temporarily save data re a post to transfer to other uses // eg in 'close' archive it then transfer to closed board and mail it private string post_body, post_rec, post_sub, post_time; private int post_num; private string post_to; mapping being_written; int action_pri; class info_written { string subject; int note_num; } int do_read_next(); int do_read_new(); int do_read(int num); int do_close(int num); int do_close(string str); int do_followup(int num); int do_reply(int num); int do_eat(int num); int do_post(string str); void setup() { set_name("board"); set_short("bulletin board"); add_adjective("bulletin"); set_main_plural("boards"); reset_get(); add_property("there", "mounted on one wall"); add_property("survive fire", 1); board_name = "general"; being_written = ([ ]); action_pri = 0; } /* setup() */ string query_plural() { mixed *stuff; stuff = (mixed *)BOARD_H->get_subjects(board_name); switch (sizeof(stuff)) { case 0: return pluralize(::short(0))+" [ Empty ]"; case 1: return pluralize(::short(0))+" [ 1 note ]"; } return pluralize(::short(0))+" [ "+sizeof(stuff)+" notes ]"; } /* query_plural() */ string short(int dark) { mixed *stuff; stuff = (mixed *)BOARD_H->get_subjects(board_name); switch (sizeof(stuff)) { case 0: return ::short(dark)+" [ Empty ]"; case 1: return ::short(dark)+" [ 1 note ]"; default: return ::short(dark)+" [ "+sizeof(stuff)+" notes ]"; } } /* short() */ string the_date(int i) { return ctime(i)[4..9]; } /* the_date() */ int do_subjects() { int i, size; mixed *stuff; string ret; mapping news_rc; stuff = (mixed *)BOARD_H->get_subjects(board_name); if (!sizeof(stuff)) { add_failed_mess("The board is completely empty.\n"); return 0; } news_rc = BOARD_H->query_newsrc(this_player()->query_name()); if (!news_rc) { news_rc = ([ ]); } ret = ""; size = sizeof(stuff); for (i=0; i < size; i++) { if (news_rc[board_name] < stuff[i][B_TIME]) { ret += sprintf("N %2d: %-=*s\n", i+1, (int)TP->query_cols()-6, stuff[i][B_SUBJECT]+" ("+ stuff[i][B_NAME]+" "+the_date(stuff[i][B_TIME])+")"); } else { ret += sprintf(" %2d: %-=*s\n", i+1, (int)TP->query_cols()-6, stuff[i][B_SUBJECT]+" ("+ stuff[i][B_NAME]+" "+the_date(stuff[i][B_TIME])+")"); } } TP->set_finish_func(0); TP->more_string(ret); return 1; } /* subjects() */ string long(string str, int dark) { int i,newones, size; mixed *stuff; string ret; mapping news_rc; stuff = (mixed *)BOARD_H->get_subjects(board_name); ret = "A bulletin board ("+board_name+").\n"; ret += sprintf("%#-*s\n\n", TP->query_cols(), "read [note number]\nsubjects\n"+ (TP->query_property("guest")?"": "post <subject>\neat <note number>\n"+ "reply <note number>\nfollowup <note number>\n")); if (!sizeof(stuff)) return ret+"The board is completely empty.\n"; news_rc = BOARD_H->query_newsrc(TP->query_name()); if (!news_rc) news_rc = ([ ]); newones = 0; size = sizeof(stuff); for (i = 0; i < size; i++) if (news_rc[board_name] < stuff[i][B_TIME]) { ret += sprintf("N %2d: %-=*s\n", i+1, (int)TP->query_cols()-6, stuff[i][B_SUBJECT]+" ("+ stuff[i][B_NAME]+" "+the_date(stuff[i][B_TIME])+")"); newones +=1; } else if (news_rc[board_name] < stuff[i][B_TIME]+(2*24*60*60)) ret += sprintf(" %2d: %-=*s\n", i+1, (int)TP->query_cols()-6, stuff[i][B_SUBJECT]+" ("+ stuff[i][B_NAME]+" "+the_date(stuff[i][B_TIME])+")"); if (!newones) ret += "\nNo new messages\n"; return ret; } /* long() */ void add_commands() { add_command("read", "[new]", (: do_read_new :)); add_command("r", "[new]", (: do_read_new :)); add_command("read", "<number>", (: do_read($4[0]) :)); add_command("r", "<number>", (: do_read($4[0]) :)); add_command("read", "next", (: do_read_next :)); if( !TP->query_property("guest") ) { add_command("post", "<string>", (: do_post($4[0]) :)); add_command("note", "<string>", (: do_post($4[0]) :)); add_command("eat", "<number>", (: do_eat($4[0]) :)); add_command("followup", "<number>", (: do_followup($4[0]) :)); add_command("reply", "<number>", (: do_reply($4[0]) :)); } if( creatorp(TP) ) add_command("close", "<number>", (: do_close($4[0]) :)); add_command("subjects", ""); } /* add_commands() */ void init() { if( TP && !present("board master", TP ) ) add_commands(); } /* init() */ string query_post_to() { return post_to; } void set_post_to(string val) { post_to = val; } int do_close(int num){ int i; int m; class info_written bing; mixed stuff = BOARD_H->get_subjects(board_name); string body; string s, pname = this_player() -> query_name(); string close_to; // num = args[0]; body = BOARD_H->get_message(board_name, num-1); TP->add_succeeded_mess(TO,""); if (num < 1 || num > sizeof(stuff)) return notify_fail("No note of that number.\n"); if (sscanf(stuff[num - 1][B_SUBJECT], "Re:#%d %s", i, s) != 2) being_written[pname] = "Re:#1 "+ stuff[num - 1][B_SUBJECT]; else being_written[pname] = "Re:#"+ (i + 1) +" "+ s; if (body) { // Truncate any signature. if ((m = strsrch(body, "\n\n--\n", 0)) != -1) body = body[0..m]; // Comment the post out. body = "> "+ replace(body, "\n", "\n> ") +"\n\n"; } else { write("Unable to find a body for post "+ query_num(num) + ".\n"); return 1; } if(!close_to = BOARD_H->query_close(board_name)) { write("Unable to find a board to close to.\n"); return 1; } // Post copy to 'close board', amending as desired set_post_to(close_to); post_body = body; post_num=num; post_rec = stuff[num-1][B_NAME]; post_sub = "Re : " + stuff[num-1][B_SUBJECT]; post_time = ctime(stuff[num-1][B_TIME]); bing = new(class info_written); bing->subject = "Re: "+ stuff[num - 1][B_SUBJECT]; bing->note_num = stuff[num - 1][B_NUM]; being_written[(string)this_player()->query_name()] = bing; write(body); write("\nIs this the note you want to close (Y/N)?"); input_to("do_close1"); return 1; } /* do_close() */ int do_close1(string str){ if(!str || str ==""){ write("\nIs this the note you want to close(Y/N)?"); input_to("close1"); return 1; } if(lower_case(str)!="y"){ write("\nOkay close cancelled.\n"); post_body = 0; post_rec = 0; post_sub = 0; post_time = 0; post_num=0; return 1; } write("\n-----------------------------------\n"); write("TRANSFERRING COPY TO 'CLOSED' BOARD\n"); write("ADD COMMENTS AS APPROPRIATE\n\n"); write("-----------------------------------\n\n"); this_player() -> do_edit(post_body + sprintf("\nRaised by %s %s\n", post_rec, post_time) + sprintf("\nClosed by %s %s\n", TP->query_cap_name(), ctime(time())), "end_of_close" ); // archive original copy BOARD_H->zap_message(board_name, post_num-1); return 1; } /* do_close1() */ void end_of_close(string str) { string body; TO->end_of_thing(str); body = post_body + sprintf("\nFixed by %s %s\n", TP->query_cap_name(), ctime(time())); post_body = body; // mail copy to original bug reporter, saying 'fixed' write("\n----------------------------\n"); write("MAILING COPY TO ORIGINATOR\n"); write("ADD COMMENTS AS APPROPRIATE\n"); write("----------------------------\n"); this_player() -> do_edit(body,"end_of_mail_close" ); } /* end_of_close() */ void end_of_mail_close(string str){ if(!str) str = post_body; MAIL_H->do_mail_message(post_rec, TP->query_name() , post_sub, 0, str); post_body = 0; post_rec = 0; post_sub = 0; post_time = 0; post_num=0; } /* mail_close() */ void mark_mine(mixed *stuff, mapping news_rc) { int i; string their_name; i = sizeof(stuff)-1; their_name = this_player()->query_name(); while (i > 0 && stuff[i][B_TIME] > news_rc[board_name]) i--; while ((i+1) < sizeof(stuff) && lower_case(stuff[i+1][B_NAME]) == their_name) i++; if (i >= sizeof(stuff)) { news_rc[board_name] = stuff[sizeof(stuff)-1][B_TIME]; return; } if (news_rc[board_name] > stuff[i][B_TIME]) return; news_rc[board_name] = stuff[i][B_TIME]; } /* mark_mine() */ int do_read_next() { mapping news_rc; mixed *stuff; string their_name, sub, next_sub; int num, last_time; news_rc = BOARD_H->query_newsrc(this_player()->query_name()); if (undefinedp(news_rc["last board"]) || news_rc["last board"] != board_name) { add_failed_mess("You have not read a note on this board yet!\n"); return 0; } stuff = BOARD_H->get_subjects(board_name); num = sizeof(stuff); their_name = this_player()->query_name(); write("last time: " + ctime(news_rc["last time"]) + "\n"); last_time = news_rc["last time"]; while (num && stuff[num - 1][B_TIME] > last_time) { num--; } sub = news_rc["last sub"]; sscanf(sub, "Re:#%*d %s", sub); for (++num; num <= sizeof(stuff); num++) { next_sub = stuff[num - 1][B_SUBJECT]; sscanf(next_sub, "Re:#%*d %s", next_sub); if (next_sub == sub) { return do_read(num); } } add_failed_mess("No further notes in the thread \"" + sub + "\".\n"); return 0; } /* do_read_next() */ int do_read_new() { int num; string their_name; mapping news_rc; mixed *stuff; news_rc = BOARD_H->query_newsrc(this_player()->query_name()); if (!news_rc) { news_rc = ([ ]); } stuff = (mixed *)BOARD_H->get_subjects(board_name); num = sizeof(stuff); their_name = (string)this_player()->query_name(); while(num && (stuff[num - 1][B_TIME] > news_rc[board_name])) { num--; } while ((num < sizeof(stuff)) && (lower_case(stuff[num][B_NAME]) == their_name)) { num++; } if (num == sizeof(stuff)) { add_failed_mess("No unread messages.\n"); return 0; } num++; return do_read(num); } /* do_read_new() */ int do_read(int num) { mapping news_rc; mixed *stuff; news_rc = BOARD_H->query_newsrc(this_player()->query_name()); if (!news_rc) { news_rc = ([ ]); } stuff = (mixed *)BOARD_H->get_subjects(board_name); if (num < 0) { num = sizeof(stuff) + num + 1; } if (num < 1 || (num > sizeof(stuff))) { add_failed_mess("No note of that number.\n"); return 0; } num--; news_rc["last board"] = board_name; news_rc["last time"] = stuff[num][B_TIME]; news_rc["last sub"] = stuff[num][B_SUBJECT]; if (news_rc[board_name] < stuff[num][B_TIME]) { news_rc[board_name] = stuff[num][B_TIME]; } BOARD_H->set_newsrc(this_player()->query_name(), news_rc); this_player()->more_string(sprintf("%s\nNote #%d by %s posted at %s%s\nTitle: " "\"%s\"\n\n%s", "%^BOLD%^", (num + 1), stuff[num][B_NAME], ctime(stuff[num][B_TIME]), "%^RESET%^", stuff[num] [B_SUBJECT][0..(int)this_player()-> query_cols() - 10], (string)BOARD_H-> get_message(board_name, num)), "[Note "+ (num + 1) +"]"); //add_succeeded_mess(({ "", "$N $V a note.\n" }), ({ })); add_succeeded_mess("", ({ })); return 1; } /* do_read() */ int do_post(string str) { class info_written bing; if (board_name=="announcements" && !creatorp(TP)) { add_failed_mess("Sorry. You can't post messages here. " "It's for announcements " "from the creators only. If you have a comment or flame, try " "the 'flame' board or the 'frog' board. Bing\n"); return 0; } if (!str) { return 0; } /* * ok shove the editing stuff in here. Lets make it function string_edit * sound froggy? */ /* string_edit(""); body = string_edit_res; */ if (!BOARD_H->test_can_write(board_name, this_object(), this_player()->query_name())) { add_failed_mess("You cannot write to this board.\n"); return 0; } bing = new(class info_written); bing->subject = str; bing->note_num = 0; being_written[this_player()->query_name()] = bing; this_player()->do_edit(0, "end_of_thing"); add_succeeded_mess(({ "", "$N looks like $r is " "contemplating a note.\n" }), ({ }) ); return 1; } /* do_post() */ void end_of_thing(string body) { class info_written bing; if(!post_to) post_to = board_name; if (body && body != "" && being_written[this_player()->query_name()]) { if(board_name != "announcements") body = sprintf( "%-=78s", body ) + this_player()->append_signature(); bing = (class info_written)being_written[ this_player()->query_name() ]; if ( !BOARD_H->add_message( post_to, capitalize( (string)this_player()->query_name() ), bing->subject, body, bing->note_num ) ) { printf( "Error writing message.\n" ); } else { printf("Message posted.\n"); } } else { printf( "No message posted.\n" ); } map_delete(being_written, this_player()->query_name()); post_to = 0; return ; } /* end_of_thing() */ int do_eat(int num) { object *users; if( !BOARD_H->delete_message( board_name, num - 1 ) ) { add_failed_mess("Failed to eat note.\n"); return 0; } printf("You viciously tear off and eat note %d.\n", num ); say( (string)TP->one_short()+" viciously tears off and eats note "+ num +".\n"); users = filter( users(), (: BOARD_H->test_can_read( board_name, TO, $1->query_name() ) :) ); event( users, "inform", (string)TP->query_cap_name() + " eats a note off "+ board_name, "message", TP ); return 1; } /* eat() */ int do_followup(int num) { int i; mixed stuff; string s; class info_written bing; stuff = (mixed *)BOARD_H->get_subjects(board_name); if (num < 1 || num > sizeof(stuff)) { add_failed_mess("No note of that number.\n", ({ })); return 0; } /* * If there is a reply type, means we do something other than * post to this board. */ if (!stuff[num - 1][B_REPLY_TYPE] && !BOARD_H->test_can_write( board_name, TO, TP->query_name() ) ) { add_failed_mess("You cannot followup to this board.\n", ({ })); return 0; } bing = new(class info_written); if (sscanf(stuff[num - 1][B_SUBJECT], "Re:#%d %s", i, s) != 2) { bing->subject = "Re:#1 "+ stuff[num - 1][B_SUBJECT]; } else { bing->subject = "Re:#"+ ( i + 1 ) +" "+ s; } bing->note_num = stuff[num - 1][B_NUM]; being_written[(string)this_player()->query_name()] = bing; printf("Include original post? (y/[n]) "); input_to("include_post", 0, num - 1, stuff[num - 1]); add_succeeded_mess(({ "", "$N looks like $r is " "contemplating a note.\n" }), ({ }) ); return 1; } /* do_followup() */ void include_post(string str, int num, mixed *stuff) { if (!str || str == "" || lower_case(str)[0] != 'y') { printf("No.\n"); this_player()->do_edit(0, "end_of_thing"); return; } if (this_player()->query_name() == "macchirton") { printf("No including notes for pointless and repeated abuse.\n"); this_player()->do_edit(0, "end_of_thing"); return; } this_player()-> do_edit("On " + ctime(stuff[B_TIME]) + ", " + stuff[B_NAME] + " wrote:\n> " + replace_string(BOARD_H->get_message(board_name, num), "\n", "\n> ") + "\n", "end_of_thing"); } /* include_post() */ int do_reply(int num) { mixed stuff; stuff = (mixed *)BOARD_H->get_subjects(board_name); if (num < 1 || num > sizeof(stuff)) { add_failed_mess("No note of that number.\n", ({ })); return 0; } MAIL_TRACK->mail(stuff[num-1][B_NAME], stuff[num-1][B_SUBJECT]); add_succeeded_mess(({ "", "$N looks like $r is " "contemplating a note.\n" }), ({ }) ); return 1; } /* reply() */ void set_board_name(string str) { board_name = str; } void set_datafile(string str) { board_name = str; } int query_new_messages() { mixed *notes; mapping news_rc; news_rc = BOARD_H->query_newsrc(this_player()->query_name()); if (!news_rc) news_rc = ([ ]); notes = (mixed *)BOARD_H->get_subjects(board_name); if (!sizeof(notes)) return 0; return (notes[sizeof(notes)-1][B_TIME] > news_rc[board_name]); } /* query_new_messages() */