#include <ed.h>
#include <post.h>
inherit "/std/object";
mapping *box_info;
mapping my_groups;
static int current;
static mapping mud_groups, tmp_post;
static string owner;
static int just_sending, fwd_flag;
static int *delete;
void headers(int x);
void do_mail(string str);
void get_to(string str);
void add_group(string str);
void remove_group(string str);
void do_groups(string str);
void do_help(string str);
void do_save(string cmd, string str);
void do_reply(string cmd, string arg);
void do_forward(string cmd, string arg);
void do_quit(string cmd);
void verify_quit(string str);
void really_quit(string str);
void handle_delete(string cmd, string arg);
void do_header(string str);
void read_mail(int x);
void get_cc(string str);
string letter_head(mapping this_letter, int ansi);
string get_header_time(int x);
void create() {
::create();
set_name("carrier pigeon");
set_aliases(({ "pigeon","dead pigeon","carrier pigeon","box", "post box", POST_ID }) );
set_short("A dead carrier pigeon");
set_long("You mail with this.\n");
fwd_flag = -1;
box_info = ({});
my_groups = ([]);
mud_groups = ([]);
tmp_post = ([]);
}
void init() {
int i;
if(this_player() != environment(this_object())) {
call_out("dest_me",0,0);
if(this_object()) destruct(this_object());
return;
}
box_info = ({});
my_groups = ([]);
mud_groups = (mapping)POSTAL_D->query_mud_groups();
owner = (string)this_player()->query_name();
restore_object(DIR_POSTAL+"/"+owner);
if(!(i=sizeof(box_info))) {
current = 0;
return;
}
current = -1;
for(i=0; i<sizeof(box_info) && current == -1; i++)
if(!box_info[i]["read"]) current = i;
delete = allocate(sizeof(box_info));
}
void start_mail(string str) {
if(str && str != "") {
str = (string)this_player()->expand_nickname(str);
just_sending = 1;
do_mail(str);
return;
}
write("Imaginary Intermud Postal Service (IIPS) 1.0 for the Discworld Mudlib\n");
write("Descartes of Borg 1993 (type \"?\" for help)\n");
write("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
if(this_player()->getenv("MAIL_NO_HEADERS")) do_mail(0);
else headers(0);
}
void do_mail(string str) {
if(str) get_to(str);
else {
write(POST_PROMPT);
input_to("postal_cmd");
}
}
void postal_cmd(string str) {
string cmd, arg;
string *args;
int x, i;
if(!str || str == "") {
for(current=-1,i=0,x=sizeof(box_info); i<x && current==-1; i++)
if(!box_info[i]["read"]) current = i;
cmd = (current+1)+"";
}
else cmd = str;
if(sscanf(cmd, "%d", x)) {
if(x>0 && x<=sizeof(box_info)) {
read_mail(current = x-1);
return;
}
else {
write("Invalid letter number (\"?\" for help)\n");
do_mail(0);
return;
}
}
cmd = (args = explode(str, " "))[0][0..0];
if(sizeof(args) > 1) arg = implode(args[1..sizeof(args)-1], " ");
else arg = "";
arg = (string)this_player()->expand_nickname(arg);
switch(cmd) {
case "a": add_group(arg); break;
case "x": remove_group(arg); break;
case "g": do_groups(arg); return;
case "?": do_help(arg); return;
case "s": case "S":
if(!wizardp(this_player()))
write("Save option only available to immortals.\n");
else do_save(cmd, arg);
break;
case "R": case "r": do_reply(cmd, arg); return;
case "F": case "f": do_forward(cmd, arg); return;
case "Q": case "q": do_quit(cmd); return;
case "m": get_to(arg); return;
case "d": case "u": handle_delete(cmd, arg); break;
case "h": do_header(arg); return;
default:
write("Invalid postal command (\"?\" for help)\n");
}
do_mail(0);
}
void do_groups(string str) {
if(!str || str == "") {
write("Personal and "+mud_name()+" groups for the IIPS:\n");
this_player()->set_finish_func("do_mail", this_object());
this_player()->more_string(format_page(keys(mud_groups)+keys(my_groups),
4));
return;
}
if(!mud_groups[str] && !my_groups[str]) {
write("Group "+str+" does not exist.\n");
}
else if(mud_groups[str]) {
write("Members of the "+mud_name()+" IIPS group "+str+":\n");
write(format_page(mud_groups[str], 4));
}
else {
write("Members of your personal IIPS group "+str+":\n");
write(format_page(my_groups[str], 4));
}
do_mail(0);
}
void add_group(string str) {
string *members;
string grp, a, b;
int i;
if(!str || str == "") {
write("No group specified.\n");
return;
}
grp = (members=explode(lower_case(str), " "))[0];
i = sizeof(members -= ({ grp }));
if(member_array(grp, members) != -1) {
write("You cannot define a group as a member of itself.\n");
return;
}
if(mud_groups[grp]) {
write(mud_name()+" has already defined a group called "+grp+".\n");
return;
}
if(user_exists(grp)) {
write("A player by the name "+grp+" already exists.\n");
return;
}
if(!my_groups[grp]) my_groups[grp] = ({});
my_groups = (mapping)POSTAL_D->add_group(owner, grp, members);
write("Group "+grp+" added to.\n");
}
void remove_group(string str) {
string *members;
string grp;
if(!str || str == "") {
write("No group specified.\n");
return;
}
grp = (members = explode(str, " "))[0];
if(!my_groups[grp]) {
write("No such group "+grp+".\n");
return;
}
if(!sizeof((members = members-({grp})))) members = my_groups[grp];
my_groups = (mapping)POSTAL_D->remove_group(owner, grp, members);
write("Members removed from group "+grp+".\n");
}
void do_help(string str) {
if(!str) str = "";
switch(str) {
case "r": case "R":
write("Commands r and R\n");
write("Syntax: <r (#) (all)>\n");
write(" <R (#) (all)>\n\n");
write(wrap("Allows you to reply to the author of the "
"current letter or of the letter specified. If you "
"specify \"all\" as a parameter, the reply goes to the author "
"of the letter as well as all people originally addessed. "
"The \"R\" command differs from the \"r\" command in that "
"the \"R\" command includes the original text in your reply."));
break;
case "f": case "F":
write("Commands f and F\n");
write("Syntax: <f (#) ([list])\n <F (#) ([list])\n\n");
write(wrap("Forwards a copy of the current letter or of "
"the letter specified to the recipient list. "
"The \"F\" command allows you to add text."));
break;
case "q": case "Q":
write("Commands q and Q\n");
write("Syntax: <q>\n <Q>\n");
write(wrap("Quits out of the mailer. The \"Q\" command"
"quits without making any changes to the mail (nothing "
"is deleted). \"q\" deleteds letters marked for delteion"));
break;
case "a":
write("Command a\nSyntax: <a [group] [list]>\n\n");
write(wrap("Adds a list of players to an individualized "
"mailer group. If no such group exists, one is created."));
break;
case "x":
write("Command x\nSyntax: <x [group] [list]>\n\n");
write(wrap("Deletes a list of players from your mailer group "
"of choice. If no player list is given, the whole "
"groups is deleted."));
break;
case "g":
write("Command g\nSyntax: <g ([group])>\n\n");
write(wrap("Lists mud and personal groups for the IIPS mailer. "
"If no group is specified, all group names are listed. Otherwise the "
"members of the group named are listed."));
break;
case "s": case "S":
write("Commands s and S\nSyntax: <s (#) [filename]>\n");
write(" <S (#) [filename]>\n\n");
write(wrap("Only available to immortals. Saves the post specified "
"or the current post to the file filename in the wizards mail save "
"directory."));
break;
case "u":
write("Command u\nSyntax: <u (#)>\n\n");
write(wrap("Undeletes a letter marked for deletion."));
break;
case "d":
write("Command d\nSyntax: <d (#)>\n\n");
write(wrap("Marks a letter for deletion upon quitting mail."));
case "h":
write("Command h\nSyntax: <h (#)>\n\n");
write(wrap("Lists the headers for all letters, or letters "
"beginning at the letter number specified."));
break;
case "m":
write("Command m\nSyntax: <m [list]>\n\n");
write(wrap("Allows you to create a letter and send it to "
"the list of players and groups you specify. You will "
"be prompted at the end of creating the mail for a list "
"of players or groups who should get carbon copies."));
break;
default:
this_player()->set_finish_func("do_mail", this_object());
this_player()->more_string(read_file(wizardp(this_player()) ?
POST_IMMORTAL_HELP : POST_USER_HELP));
return;
}
do_mail(0);
}
void do_save(string cmd, string str) {
string tmp, where;
int i, x;
if(!str || !(i=strlen(str))) {
write("You must specify the name of a file to save to.\n");
return;
}
if(sscanf(str, "%d %s", x, where) != 2) where = str;
else {
i = strlen(where);
current = x-1;
}
if(current < 0 || current >= sizeof(box_info)) {
write("Invalid letter number (\"?\" for help).\n");
return;
}
while(i--)
if(lower_case(where)[i] < 'a' || lower_case(where)[i] > 'z') {
write("You may only use alphabetic characters.\n");
return;
}
tmp = "/w/"+owner+"/"+where;
if(file_size(tmp) > -1) x = 1;
else x = 0;
write_file(tmp, (string)LETTER_D->get_message(box_info[current]["id"]));
if(!x) write("Letter written to new file: "+tmp+".\n");
else write("Letter appended to file: "+str+".\n");
if(cmd == "S") delete[current] = 1;
return;
}
void do_header(string str) {
int x;
if(!str || str == "") headers(0);
else {
x = atoi(str);
if(x > 0 && x<=sizeof(box_info)) headers(x-1);
else {
write("Invalid letter number (\"?\" for help).\n");
do_mail(0);
}
}
}
void headers(int x) {
string lines;
int i;
if(!(i=sizeof(box_info))) {
write("No letters are currently in your post box.\n");
current = 0;
do_mail(0);
return;
}
for(lines = ""; x<i; x++) {
lines += (x+1)+" "+(box_info[x]["read"] ? " " :
"(new)")+(x==current ? ">" : (delete[x] ? "*" : " "))+
arrange_string(capitalize(box_info[x]["from"]), 16)+" "+
arrange_string(get_header_time(box_info[x]["date"]), 12)+
box_info[x]["subject"]+"\n";
}
this_player()->set_finish_func("do_mail", this_object());
this_player()->more_string(lines);
}
string get_header_time(int x) {
string a, b, c, d;
if(sscanf(ctime(x), "%s %s %s %s", a, b, c, d) != 4)
sscanf(ctime(x), "%s %s %s %s", a, b, c, d);
return a+" "+b+" "+c;
}
void old_handle_delete(string cmd,string arg)
{
if(arg && arg != "") current = atoi(arg)-1;
if(current < 0 || current >= sizeof(box_info)) {
write("Invalid letter number (\"?\" for help).\n");
return;
}
if(cmd == "u" && !delete[current]) {
write("Letter "+(current+1)+" is not marked for deletion.\n");
return;
}
if(cmd == "d" && delete[current]) {
write("Letter "+(current+1)+" is already marked for deletion.\n");
return;
}
if(cmd == "u") {
delete[current] = 0;
write("Letter "+(current+1)+" is no longer marked for deletion.\n");
return;
}
delete[current] = 1;
write("Letter "+(current+1)+" is now marked for deletion.\n");
return;
}
void handle_delete(string cmd, string arg) {
string *list;
int i;
int start,end;
if(!arg || arg == "") old_handle_delete(cmd,arg);
list = explode(arg,",");
switch(sizeof(list))
{
case 0:
write("Invalid letter number \"?\" for help.\n");
break;
case 1:
old_handle_delete(cmd,arg);
break;
case 2:
start = atoi(list[0]);
end = atoi(list[1]);
if(start >=0 && end > start)
for(i = start; i <=end; i++) old_handle_delete(cmd,sprintf("%d",i));
break;
default:
for(i = 0; i < sizeof(list); i++)
{
old_handle_delete(cmd,list[i]);
}
break;
}
}
void do_quit(string str) {
if(!this_player()->getenv("MAIL_DELETE_PROMPT") || str == "Q")
really_quit(str);
else if(member_array(1, delete) == -1) really_quit(str);
else {
write("Delete all marked letters? (y/n) ");
input_to("verify_quit");
}
}
void verify_quit(string str) {
if(!str || str == "" || lower_case(str[0..0]) == "y") really_quit("q");
else if(lower_case(str[0..0]) == "n") {
write("Files will remain undeleted.\n");
really_quit("Q");
}
else {
write("Invalid input.\nDelete all marked letters? (y/n) ");
input_to("verify_quit");
}
}
void really_quit(string str) {
int i, x;
if(str == "Q") {
write("No letters deleted or marked as read.\n");
dest_me();
if(this_object()) destruct(this_object());
return;
}
i = sizeof(box_info);
while(i--) {
if(delete[i]) {
x++;
POSTAL_D->remove_post(owner, box_info[i]["id"]);
}
}
POSTAL_D->flush_files();
write(x+" letters deleted.\n");
dest_me();
if(this_object()) destruct(this_object());
}
void get_to(string str) {
if(!str || str == "") {
write("No users or groups named.\n");
do_mail(0);
return;
}
tmp_post = ([]);
// Fix by Aragorn
str = replace_string(str,"@@","");
tmp_post["to"] = explode(str, " ");
tmp_post["from"] = (string)this_player()->query_name();
tmp_post["date"] = time();
write("Subject: ");
input_to("get_subject");
}
void get_subject(string str) {
string tmp_str;
int i, max;
if(!str || str == "") str = "[No subject]";
str = replace_string(str,"@@","");
tmp_post["subject"] = str;
write(letter_head(tmp_post, (int)this_player()->query_ansi()));
this_player()->do_edit(0, "get_text", this_object());
}
void abort() {
if(just_sending) {
dest_me();
if(this_object()) destruct(this_object());
return;
}
do_mail(0);
}
void get_text(string str) {
if(!str) {
abort();
return;
}
if(fwd_flag != -1) {
str += "\n-----\n"+
"Original message sent by "+capitalize(box_info[fwd_flag]["from"])+
" to "+capitalize(owner)+" on "+ctime(box_info[fwd_flag]["date"])+
":\n-----\n"+(string)LETTER_D->get_message(box_info[fwd_flag]["id"]);
fwd_flag = -1;
}
// Fix by Aragorn
str = replace_string(str, "@@","");
tmp_post["message"] = str+"\n";
tmp_post["message"] += (string)POSTAL_D->read_sig(owner);
if(!this_player()->getenv("MAIL_NO_CC")) {
write("Cc: ");
input_to("get_cc");
return;
}
get_cc("");
}
void get_cc(string str) {
string dead;
string *who, *diff, *orig;
if(!tmp_post["cc"]) tmp_post["cc"] = ({});
// Fix by Aragorn
if (str) str = replace_string(str,"@@","");
if(str && str != "") tmp_post["cc"] += explode(lower_case(str), " ");
orig = uniq_array(tmp_post["to"]+tmp_post["cc"]);
diff = orig - (who=(string *)POSTAL_D->post_mail(tmp_post));
if(sizeof(who))
write("Mail sent successfully to:\n"+format_page(who, 3)+"\n");
else {
if(wizardp(this_player())) dead = "/w/"+owner+"/dead.letter";
else dead = DIR_TMP+"/post/"+owner+".dead";
write("No recipients found. Appending to "+dead+".\n");
write_file(dead, tmp_post["message"]+"\n");
}
MAIL_S->flush_mail_queue();
POSTAL_D->flush_files();
if(just_sending) {
dest_me();
if(this_object()) destruct(this_object());
return;
}
do_mail(0);
}
void do_reply(string cmd, string arg) {
string *tmp;
string recep;
int x, i;
if(arg && arg != "") {
if(sscanf(arg, "%d %s", x, recep) != 2) {
if(!sscanf(arg, "%d", x)) recep = arg;
else {
recep = "";
current = x-1;
}
}
else current = x-1;
}
else recep = "";
if(current < 0 || current >= sizeof(box_info)) {
write("Invalid letter number (\"?\" for help).\n");
do_mail(0);
return;
}
else if(recep != "" && recep != "all" && recep != "to") {
write("Invalid reply parameter: "+recep+" (\"?\" for help).\n");
do_mail(0);
return;
}
tmp_post["from"] = (string)this_player()->query_name();
if(recep == "") {
tmp_post["to"] = ({ box_info[current]["from"] });
tmp_post["cc"] = ({});
}
else if(recep == "to") {
tmp_post["to"] = ({box_info[current]["from"] })+box_info[current]["to"];
tmp_post["cc"] = ({});
}
else {
tmp_post["to"] = ({box_info[current]["from"] })+box_info[current]["to"];
tmp_post["cc"] = box_info[current]["cc"];
}
tmp_post["date"] = time();
if(strlen(box_info[current]["subject"]) < 4 ||
box_info[current]["subject"][0..3] != "RE: ")
tmp_post["subject"] = "RE: "+box_info[current]["subject"];
else tmp_post["subject"] = box_info[current]["subject"];
write(letter_head(tmp_post, (int)this_player()->query_ansi()));
this_player()->do_edit( (cmd == "R" ?
"On "+ctime(box_info[current]["date"])+", "+
capitalize(box_info[current]["from"])+" wrote:\n>\n>"+
replace_string((string)LETTER_D->get_message(box_info[current]["id"]),
"\n", "\n> ")+"\n" : 0), "get_text", this_object());
}
void do_forward(string cmd, string arg) {
string recep;
int x, i;
if(!arg || arg == "") {
write("Recepient for forward missing (\"?\" for help).\n");
do_mail(0);
return;
}
if(sscanf(arg, "%d %s", x, recep) == 2) {
current = x-1;
tmp_post["to"] = explode(lower_case(recep), " ");
}
else tmp_post["to"] = explode(lower_case(arg), " ");
if(current < 0 || current >= sizeof(box_info)) {
write("Invalid letter number (\"?\" for help).\n");
do_mail(0);
return;
}
tmp_post["from"] = (string)this_player()->query_name();
tmp_post["date"] = time();
if(strlen(box_info[current]["subject"]) < 10 ||
box_info[current]["subject"][0..9] != "(forward) ")
tmp_post["subject"] = "(forward) "+box_info[current]["subject"];
else tmp_post["subject"] = box_info[current]["subject"];
tmp_post["cc"] = ({});
write(letter_head(tmp_post, (int)this_player()->query_ansi()));
if(cmd == "F") {
fwd_flag = current;
this_player()->do_edit(0, "get_text", this_object());
}
else {
get_text("\n-----\nOriginal letter sent by "+capitalize(box_info[current]["from"])+" to "+capitalize(owner)+" "+ctime(box_info[current]["date"])+":\n"+
"-----
"+(string)LETTER_D->get_message(box_info[current]["id"])+"\n");
}
}
void read_mail(int x) {
string borg;
borg = "Letter "+(x+1)+(delete[x] ? "[DELETED]:\n" : ":\n");
borg += letter_head(box_info[x], (int)this_player()->query_ansi());
borg += "\n"+(string)LETTER_D->get_message(box_info[x]["id"])+"\n";
POSTAL_D->mark_read(owner, box_info[x]["id"]);
box_info[x]["read"] = 1;
this_player()->set_finish_func("do_mail", this_object());
this_player()->more_string(borg);
}
string letter_head(mapping this_letter, int ansi) {
int i, max;
string ret;
ret = ctime(this_letter["date"])+" from ";
ret += "%^GREEN%^"+capitalize(this_letter["from"])+"%^RESET%^\n";
ret += "To: ";
for(i=0, max = sizeof(this_letter["to"]); i<max; i++)
ret += capitalize(this_letter["to"][i])+" ";
if(!sizeof(this_letter["cc"])) ret = wrap(ret);
else {
ret = wrap(ret)+"Cc: ";
for(i=0, max = sizeof(this_letter["cc"]); i<max; i++)
ret += capitalize(this_letter["cc"][i])+" ";
ret = wrap(ret);
}
ret += "Subject: %^GREEN%^"+this_letter["subject"]+"%^RESET%^\n";
return ret;
}
int valid_shadow() { return 1; }
int drop () { return 1; }
int get() { return 0; }