/* /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 tmpdir; static private string __BoardID; static private string *__EditOK; static string gstr, gfile, gdude; string Location; void create(){ string path; item::create(); SetNoClean(1); SetId( ({ "board", "message board" }) ); SetLong("A board for reading and posting messages. To read the "+ "first message: read 1\nTo post a message: post <message title>\n"); SetPreventGet("You cannot get that!"); SetPreventPut("You cannot put that in there!"); SetPreventDrop("Drop a bulletin board?"); SetNoCondition(1); SetRead( (: GetLong :) ); __EditOK = ({}); path = base_name(this_object()); if(!strsrch(path, "/secure/")) tmpdir = DIR_SECURE_TMP; else tmpdir = DIR_TMP; } void RegisterLocation(){ object env = environment(); if(!env) Location = 0; else Location = base_name(env); BBOARD_D->RegisterLocation(query_board_id(), Location); } 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"); RegisterLocation(); } static private int valid_edit(string author){ string who = this_player()->GetKeyName(); if(who == author) return 1; if(archp(this_player())) return 1; return 0; } int cmd_post(string str){ string file; if(!str) return notify_fail("You must specify a subject.\n"); if(file_exists(file = tmpdir + "/" + 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 { write("When finished writing, enter a single period on a blank line, then "); write("at the colon prompt (:) type a lower-case x and return.\n"); write("Like this:\n.\nx\n"); 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; object env = room_environment(this_player()); file = tmpdir + "/" + 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(), this_player()->GetCapName(), subj, msg); message("system", "Message posted!", this_player()); tell_room(env, this_player()->GetName()+" posts on the board.", ({ this_player() })); } int cmd_read(string str){ string junk; mapping *posts; int x, i, maxi; object env = room_environment(this_player()); 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 = BBOARD_D->query_posts(query_board_id())); if(!str){ for(i=0, x = -1; i<maxi; i++) if(member_array(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"]; tell_room(env, this_player()->GetName()+" reads the board.", ({ this_player() })); BBOARD_D->mark_read(query_board_id(),x,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>BBOARD_D->query_number_posts(query_board_id())) return notify_fail("Invalid post number.\n"); x--; post = 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 = tmpdir + "/" + 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"; write_file(file, msg); } this_player()->eventEdit(file, (: end_post, subj, (mail ? post : 0) :)); } int cmd_remove(string str){ mapping post; int x; object env = room_environment(this_player()); if((x = to_int(str)) < 1 || x > BBOARD_D->query_number_posts(query_board_id())) return notify_fail("Invalid post number.\n"); post = BBOARD_D->query_post(query_board_id(), x-1); if(!valid_edit(convert_name(post["author"]))){ write("You do not have permission to remove that!\n"); return 1; } BBOARD_D->remove_post(query_board_id(), x-1); message("system", "Post "+x+" removed.", this_player()); tell_room(env, this_player()->GetName()+" removes a post from the board.", ({ this_player() })); return 1; } int cmd_edit(string str){ mapping post; string file; int x; if((x = to_int(str)) < 1 || x > BBOARD_D->query_number_posts(query_board_id())) return notify_fail("Invalid post number.\n"); post = BBOARD_D->query_post(query_board_id(), x-1); if(!valid_edit(convert_name(post["author"]))){ write("You do not have permission to edit that post!\n"); return 1; } file = tmpdir + "/" + this_player()->GetKeyName() + ".bb"; gstr = post["post"]; gfile = file; unguarded( (: write_file(gfile, gstr, 1) :) ); this_player()->edit(file, (: end_edit, post["subject"], x-1 :) ); return 1; } void end_edit(string subj, int num){ string file, msg; file = tmpdir + "/" + 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(), 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 = 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(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); }