/* /lib/bboard.c * /lib/bboard.c * from Nightmare 3.3 * the Dead Souls bulletin board system * created by Descartes of Borg 940920 */ #include <lib.h> #include <daemons.h> #include "include/bboard.h" inherit LIB_ITEM; static private string __BoardID; static private string *__EditOK; static string globalstr, globalfile; void create() { item::create(); SetNoClean(1); SetPreventGet("You cannot get that!"); SetPreventPut("You cannot put that in there!"); SetPreventDrop("Drop a bulletin board?"); __EditOK = ({}); } void init() { item::init(); add_action("cmd_post", "post"); add_action("cmd_read", "read"); add_action("cmd_followup_and_respond", ({ "followup", "respond "})); add_action("cmd_remove", "remove"); add_action("cmd_edit", "edit"); if(!creatorp(this_player())) return; } static private int valid_edit(string author) { string who; who = (string)this_player()->GetKeyName(); if(who == author) return 1; if(archp(this_player())) return 1; if(member_array(who, __EditOK) != -1) return 1; return (int)master()->valid_apply(({})); } int cmd_post(string str) { string file; if(!str) return notify_fail("You must specify a subject.\n"); if(file_exists(file = DIR_TMP+"/"+(string)this_player()->GetKeyName())) { message("system", "You have an abandoned post waiting.",this_player()); message("system", " e)dit it, or start n)ew", this_player()); message("prompt", "\nCommand (default 'n'): ", this_player()); input_to("begin_post", str, file, (: continue_post :)); } else begin_post("n", str, file, (: continue_post :)); return 1; } static void begin_post(string cmd, string subj, string file, function f) { if(cmd == "" || !cmd) cmd = "n"; else cmd = cmd[0..0]; if(cmd != "n" && cmd != "e") { message("system", "Invalid bulletin board command.", this_player()); return; } if(cmd == "n" && file_exists(file)) rm(file); (*f)(subj, file); } void continue_post(string subj, string file) { this_player()->eventEdit(file, (: end_post, subj, 0 :)); } void end_post(string subj, string mail) { string file, msg; file = DIR_TMP "/" + (string)this_player()->GetKeyName(); if(!(msg = read_file(file))) { message("system", "No file read!", this_player()); if(file_exists(file)) rm(file); return; } else rm(file); if( !mail ) BBOARD_D->add_post(query_board_id(), (string)this_player()->GetCapName(), subj, msg); message("system", "Message posted!", this_player()); } int cmd_read(string str) { string junk; mapping *posts; int x, i, maxi; if(str){ if(str == "board" || sscanf(str,"board %s",junk) ) { write("To read the first post, type: read 1"); write("To read the second one: read 2"); write("And so on."); return 1; } maxi = sizeof(posts = (mapping *)BBOARD_D->query_posts(query_board_id())); if(!str) { for(i=0, x = -1; i<maxi; i++) if(member_array((string)this_player()->GetKeyName(), posts[i]["read"]) == -1) { x = i; break; } if(x == -1) return notify_fail("No unread posts.\n"); } else if(!(x = to_int(str))) return notify_fail("Read what?\n"); else x--; if(x < 0 || x >= sizeof(posts)) return notify_fail("Invalid post number.\n"); str = "Post #%^YELLOW%^" + (x+1) + "%^RESET%^ by %^YELLOW%^" + posts[x]["author"] + "%^RESET%^\nSubject: %^CYAN%^" + posts[x]["subject"] + "%^RESET%^\n\n"; str += posts[x]["post"]; BBOARD_D->mark_read(query_board_id(),x,(string)this_player()->GetKeyName()); this_player()->eventPage(explode(str, "\n"), "system"); return 1; } } int cmd_followup_and_respond(string str) { mapping post; function f; string file, verb; int x; if(!str) return notify_fail(capitalize(verb=query_verb())+" which post?\n"); if((x=to_int(str)) < 1 || x>(int)BBOARD_D->query_number_posts(query_board_id())) return notify_fail("Invalid post number.\n"); x--; post = (mapping)BBOARD_D->query_post(query_board_id(), x); if((verb = query_verb()) == "respond") f = (: continue_mail, post :); else f = (: continue_followup, post :); str = post["subject"]; if(!str) str = "Re: "+possessive_noun(post["author"])+" post"; else if(strlen(str) <= 4 || str[0..3] != "Re: ") str = "Re: "+str; if(file_exists(file = DIR_TMP+"/"+(string)this_player()->GetKeyName())) { message("system", "You have an abandoned post waiting.",this_player()); message("system", " e)dit it, or start n)ew", this_player()); message("prompt", "\nCommand (default 'n'): ", this_player()); input_to("begin_post", str, file, f); } else begin_post("n", str, file, f); return 1; } void continue_followup(mapping post, string subj, string file) { message("prompt", "\nInclude original text (default 'n'): ",this_player()); input_to("check_include_text", subj, file, post, 0); } void continue_mail(mapping post, string subj, string file) { message("prompt", "\nInclude original text (default 'n'): ",this_player()); input_to("check_include_text", subj, file, post, 1); } static void check_include_text(string ans, string subj, string file, mapping post, int mail) { string msg; if(ans == "" || !ans) ans = "n"; else ans = ans[0..0]; if(ans == "y") { msg = post["author"] + " once wrote...\n>"; msg += implode(explode(post["post"], "\n"), "\n> ")+"\n"; globalstr = msg; globalfile = file; unguarded( (: write_file(globalfile, globalstr) :) ); } this_player()->eventEdit(file, (: end_post, subj, (mail ? post : 0) :)); } int cmd_remove(string str) { mapping post; int x; if((x = to_int(str)) < 1 || x > (int)BBOARD_D->query_number_posts(query_board_id())) return notify_fail("Invalid post number.\n"); post = (mapping)BBOARD_D->query_post(query_board_id(), x-1); if(!valid_edit(convert_name(post["author"]))) return notify_fail("You do not have permission to remove that!\n"); BBOARD_D->remove_post(query_board_id(), x-1); message("system", "Post "+x+" removed.", this_player()); return 1; } int cmd_edit(string str) { mapping post; string file; int x; if((x = to_int(str)) < 1 || x > (int)BBOARD_D->query_number_posts(query_board_id())) return notify_fail("Invalid post number.\n"); post = (mapping)BBOARD_D->query_post(query_board_id(), x-1); if(!valid_edit(convert_name(post["author"]))) return notify_fail("You do not have permission to edit that post!\n"); file = DIR_TMP+"/"+(string)this_player()->GetKeyName()+".bb"; if(file_exists(file)) rm(file); globalstr = post["post"]; globalfile = file; unguarded( (: write_file(globalfile, globalstr) :) ); this_player()->edit(file, (: end_edit, post["subject"], x-1 :) ); return 1; } void end_edit(string subj, int num) { string file, msg; file = DIR_TMP "/" + (string)this_player()->GetKeyName(); if(!(msg = read_file(file))) { message("system", "No file read!", this_player()); return; } else rm(file); BBOARD_D->remove_post(query_board_id(), num); BBOARD_D->add_post(query_board_id(), (string)this_player()->GetCapName(), subj, msg); message("system", "Message posted!", this_player()); } string GetExternalDesc() { mapping *posts; string msg; int i, maxi; msg = item::GetExternalDesc(); maxi = sizeof(posts = (mapping *)BBOARD_D->query_posts(query_board_id())); msg += "\n"; if(!maxi) msg += "There are currently no posts.\n"; else for(i=0; i < maxi; i++) { int lu; if(!this_player()) lu = 1; else if(member_array((string)this_player()->GetKeyName(), posts[i]["read"]) == -1) lu = 0; else lu = 1; msg += sprintf("[%:-3d] %s %:-17s \"%:-27s %s\n", (i+1), (lu ? " " : "(new)"), posts[i]["author"]+":", posts[i]["subject"]+"\"", query_board_time(posts[i]["time"])); } return msg; } void set_board_id(string str) { __BoardID = str; } string query_board_id() { return __BoardID; } string query_board_time(int x) { string date, day, mon, year, hour, ret; if(sscanf(ctime(x), "%s %s %s %s %s", day, mon, date, hour, year) !=5) sscanf(ctime(x), "%s %s %s %s %s", day, mon, date, hour, year); sscanf(hour, "%s:%s:%*s", hour, ret); return(hour+ret+" "+day+" "+date+" "+mon); }