inherit "std/object"; #include "mail.h" #include "inet.h" #define ILLEGAL write("Bad boy\n"); int new; mixed mail; /* ({ ({ from, to, subject, ccers, body }) }) */ static int *deleted, cur, just_mail; static string subject, cc, send_to, body, from, do_this_last; /* Prototypes */ int *expand_range(string str); int mail_message(string str, string bo); int reply_message(string str, string sub, string cc); void do_mail_message(string to, string from, string sub, string cc, string body, int send_inter, string only_to); /* Code */ void set_do_this_last(string s) { do_this_last = s; } string query_do_this_last() { return do_this_last; } void setup() { mail = ({ }); set_short("Mailer object"); set_long("A New Moon mailer object.\n"); reset_drop(); seteuid("mailer"); new = -1; } void show_headers(string str, int *range) { int i, offs, sz; string s; if (str) { restore_object("/save/post/"+str); from = str; if (new == -1) cur = sizeof(mail)-1; else cur = new; } if (!mail) mail = ({ }); if(!range) range = ({ }); sz = sizeof(mail); if (!sz) write("No messages.\n"); if(!sizeof(range)) { i = sz-20; if(i<0) i=0; if(i>cur) { i = cur+1; sz = i+20; } range = expand_range(sprintf("%d-%d", i, sz)); } sz = sizeof(range); if(sz) offs = range[0]-1; else offs = 0; sz += offs; if (!deleted) deleted = allocate(sizeof(mail)); for (i=offs;i<sz;i++) { if (i==cur) s = ">"; else s = " "; if (deleted[i]) s += "D "; else if (i>=new && new != -1) s += "N "; else s += " "; s += (i+1)+": "+mail[i][M_FROM]+" Sub: "; printf("%s%-=*s\n", s, (int)this_player()->query_cols()-strlen(s),mail[i][M_SUB]); } } /* show_headers() */ void status_line() { if (just_mail) return; if (!sizeof(mail)) write("[None] Mail (+ - R r m q x d h f s ?) : "); else write("[1-"+sizeof(mail)+"]("+(cur+1)+ ") Mail (+ - R r m q x d h f s ?) : "); } int read_mail(string str, string sub) { string temp; temp = (string)this_player()->query_name(); if (str) { restore_object("/save/post/"+temp); from = temp; just_mail = 1; if (!sub) mail_message(str, 0); else reply_message(str, sub, ""); return 1; } show_headers(temp, expand_range("")); MAIL_TRACK->add_mailer(this_object(), from); status_line(); input_to("read_loop"); return 1; } int load_me(string str) { if (file_name(previous_object())[0..strlen(MAILER)-1] != MAILER) { ILLEGAL return 0; } seteuid("mailer"); restore_object("/save/post/"+str); if (!mail) mail = ({ }); from = str; return 1; } void save_me() { if (from) save_object("/save/post/"+from); } string new_mail(string str) { mixed s; new = -1; restore_object("/save/post/"+str); if (new != -1) { if(s=(object)this_player()->query_guild_ob()) if(s=(string)s->query_new_messages()) return s; return "\nYou have NEW messages.\n"+ "Go to the Post Office to read them.\n\n"; } return ""; } string finger_mail(string str) { int i; new = -1; mail = ({ }); restore_object("/save/post/"+str); if (!mail || !(i = sizeof(mail)) ) return "No mail.\n"; if (new == -1) return ""+i+" mail messages.\n"; else return ""+i+" mail messages, "+ (i-new)+" of them unread.\n"; } void get_message(string from, string to, string subject, string cc, string body) { mail += ({ ({ time(), from, to, subject, cc, body }) }); if (new == -1) new = sizeof(mail)-1; if (deleted) deleted += ({ 0 }); save_me(); } static void local_mail(string from, string real_to, string to, string subject, string cc, string body, object new_mailer, int make_bounce) { object bing; string junk; if ( !(bing=(mixed)MAIL_TRACK->find_mailer(real_to)) ) if ("/secure/login"->test_user(real_to)) { bing = new_mailer; bing->load_me(real_to); } else { if (make_bounce) do_mail_message(from, "postmaster", "Error! User unknown", 0, "Original message included:\n"+ ">From : "+from+"\nTo : "+to+ "\nSubject : "+subject+"\nCc : "+ cc+"\n"+body, 1, 0); return; } bing->get_message(from, to, subject, cc, body); if (find_player(real_to) && sscanf(from, "%s@%s", junk, junk) == 2) { object ob; ob = clone_object(POST_FROG); ob->move_player("X", COMM_ROOM); ob->send_mail(real_to, from); } else if (this_player() && environment(this_player()) && (!(int)environment(this_player())->send_message(real_to)) ) { write("A post-office courier accepts your mail.\n"); say("A post office courier accpets a letter from "+ this_player()->query_cap_name()+".\n"); if( !find_player(real_to) ) return; tell_object(find_player(real_to), this_player()->query_cap_name()+ " has sent you some mail!\n"); } } /* local_mail() */ string check_local(string str) { string mud, name; if (sscanf(str, "%s@%s", name, mud) == 2) { if (mud == mud_name()) return name; return 0; } return str; } int check_address(string str) { if (sscanf(str, "%s@"+mud_name(), str) != 1 ) return (int)"/secure/login"->test_user(str) || (int)MAIL_TRACK->query_list(str); return 1; } /* --------============= OPTIMISED THIS FAR ==========------------ */ void send_message() { int i; object new_mailer, bing, ob; string *goto, *cc_e, *o_to; string local_name; o_to = goto = explode(replace(lower_case(send_to), " ", ","), ",") - ({ "" });; if (!goto) goto = ({ }); if (!cc) cc = ""; if (cc && cc != "" && cc != ",") goto += (cc_e = explode(replace(lower_case(cc), " ", ","), ",") - ({ "" })); else cc_e = ({ }); for (i=0;i<sizeof(goto);i++) { goto[i] = (string)this_player()->expand_nickname(goto[i]); /* ok expand mailing lists... */ if (MAIL_TRACK->query_list(goto[i])) { if (member_array(goto[i], cc_e) == -1) cc_e += ({ goto[i] }); goto += (mixed)MAIL_TRACK->query_members(goto[i]); goto = delete(goto,i,1); i--; } else if (member_array(goto[i], goto) != i) { /* Make sure it only sends to any one person once... */ goto = delete(goto, i, 1); i--; } } cc = implode(cc_e, ","); new_mailer = clone_object(MAILER); for (i=0;i<sizeof(goto);i++) { if (goto[i]) write("Sending to : "+goto[i]+"\n"); else { goto = delete(goto, i, 1); i--; } if (local_name = check_local(goto[i])) { local_mail(from, local_name, send_to, subject, cc, body, new_mailer, 0); goto = delete(goto, i, 1); i--; } } new_mailer->dest_me(); /* send any or all intermud mail... */ if (sizeof(goto)) OUT_MAIL->remote_mail(from, send_to, subject, cc, body, goto); } /* send_message() */ void do_mail_message(string to, string from, string subject, string cc, string body, int send_interfrog, string only_to) { string local_name; string *goto; int i; object new_mailer; if(file_name(previous_object())[0..11] != "/global/lord" && file_name(previous_object())[0..14] != "/global/creator" && file_name(previous_object())[0..18] != "/global/auto_mailer" && file_name(previous_object())[0..19] != "/net/daemon/out_mail" && file_name(previous_object())[0..18] != "/net/daemon/in_mail" && file_name(previous_object())[0..19] != "/obj/handlers/mailer") { write("Bad boy!\n"); return 0; } if((file_name(previous_object())[0..11] == "/global/lord" || file_name(previous_object())[0..14] == "/global/creator") && (from != (string)this_player()->query_name())) { write("Bad boy!\n"); return 0; } if (!only_to) { to = replace(to, " ", ","); goto = explode(to, ","); if (cc) { cc = replace(cc, " ", ","); goto += explode(to, ","); } } else { only_to = replace(only_to, " ", ","); goto = explode(only_to, ","); if (!goto || !sizeof(goto)) return ; } goto = goto - ({ "" }); /* * First of all, get rid of all duplicates... and expand mailing * lists... */ for (i=0;i<sizeof(goto);i++) { /* ok expand mailing lists... */ if (MAIL_TRACK->query_list(goto[i])) { goto += (mixed)MAIL_TRACK->query_members(goto[i]); goto = delete(goto,i,1); i--; } else if (member_array(goto[i], goto) != i) { /* Make sure it only sends to any one person once... */ goto = delete(goto, i, 1); i--; } } new_mailer = clone_object(MAILER); for (i=0;i<sizeof(goto);i++) { if ((local_name = check_local(goto[i]))) { /* Local mail... */ local_mail(from, local_name, to, subject, cc, body, new_mailer, 1); goto = delete(goto, i, 1); i--; } } new_mailer->dest_me(); /* Ok, now the interfrog mail */ if (send_interfrog && sizeof(goto)) OUT_MAIL->remote_mail(from, to, subject, cc, body, goto); } /* do_mail_message() */ string message_string(int i) { return "Sent at "+ctime(mail[i-1][M_TIME])+ "\nMessage #"+i+(deleted[i-1] ? (" (deleted)\n") : "\n")+ "From : "+mail[i-1][M_FROM]+"\nTo : "+mail[i-1][M_TO]+ "\nSubject : "+mail[i-1][M_SUB]+"\nCc : "+ mail[i-1][M_CC]+"\n"+mail[i-1][M_BODY]; } /* message_string() */ void read_message(int i) { write("\n\n"); this_player()->set_finish_func("finish_message"); this_player()->more_string(message_string(i)); } /* read_message() */ void finish_message() { status_line(); input_to("read_loop"); } /* finish_message() */ void delete_things() { int i; while (i<sizeof(mail)) { if (deleted[i]) { mail = delete(mail,i,1); deleted = delete(deleted,i,1); } else i++; } } int mail_message(string to, string bo) { int i; string *bing; to = (string)this_player()->expand_nickname(to); send_to = replace(to, " ", ","); send_to = (string)this_player()->expand_nickname(send_to); bing = explode(send_to, ",") - ({ "" }); for (i=0;i<sizeof(bing);i++) { bing[i] = (string)this_player()->expand_nickname(bing[i]); if (!check_address(bing[i])) { write(bing[i]+" does not exist.\n"); bing = delete(bing, i, 1); i--; } } if (!sizeof(bing)) { write("No one to mail to.\n"); status_line(); input_to("read_loop"); return 1; } send_to = implode(bing, ","); write("Subject : "); input_to("get_subject"); subject = 0; send_to = to; cc = ""; if (!bo) body = ""; else body = bo; } /* mail_message() */ int reply_message(string to, string sub, string rcc) { string s1; send_to = to; subject = sub; if (sscanf(sub,"Re: %s",s1)==1) subject = "Re(many): "+s1; else if (sscanf(sub,"Re(many): %s",s1)!=1) subject = "Re: "+sub; cc = rcc; body = ""; write("Press return for a subject of \""+subject+"\"\nSubject : "); input_to("get_subject"); return 1; } int get_subject(string str) { if (!str) str = ""; if (str == "" && !subject) { write("Aborted.\n"); status_line(); input_to("read_loop"); return 1; } if (str != "") subject = str; write("Enter your Cc's now. Terminate with a blank line.\nCc: "); input_to("get_cc"); return 1; } int finish_body(string str) { if (!str || str == "") { write("Aborted.\n"); if (just_mail) return 1; status_line(); input_to("read_loop"); return 1; } body = str + (string)this_player()->append_signature(); write("Ok.\n"); send_message(); write("Sent.\n"); if (just_mail) return 1; status_line(); input_to("read_loop"); return 1; } int do_forward(string to, string sub, string bo) { send_to = to; subject = sub; body = bo; cc = 0; send_message(); status_line(); input_to("read_loop"); return 1; } int get_cc(string str) { string *bits; int i; if (str == "" || !str || str == "**") { this_player()->do_edit(0, "finish_body"); return 1; } str = replace(str, " ", ","); bits = explode(str, ",") - ({ "" }); for (i=0;i<sizeof(bits);i++) { bits[i] = (string)this_player()->expand_nickname(bits[i]); if (!check_address(bits[i])) { write("Sorry "+bits[i]+" does not exist.\n"); bits = delete(bits, i--, 1); } } cc += ","+implode(bits,","); write("Cc: "); input_to("get_cc"); return 1; } /* get_cc() */ int read_loop(string str) { int num, i, *ms; string comm, s1, s2; if (just_mail) return 1; if (!cur) cur = 1; /* * ok this should (theoreticaly) do some clever things and get the * message number being reffered to out of the junk. But then again, * maybe not. */ if (str == "-") num = -1; else if (sscanf(str, "%d%s",num,str)!=2) { comm = ""; if (sscanf(str, "%s %d %s", s1, num, s2) == 3) str = s1 + " " + s2; } if (sscanf(str, "%s %s", comm, str) != 2) { comm = str; str = ""; } comm = extract(comm,0,0); switch (comm) { case "" : if (num > 0 && num <= sizeof(mail)) { read_message(num); cur = num; return 1; } else if (num==0) { if (++cur > sizeof(mail)) { write("Run out of messages\n"); cur = sizeof(mail); } else { read_message(cur); return 1; } } else { write("Sorry message number must be in the range "+1+ " to "+sizeof(mail)+"\n"); } break; case "+" : if (num == 0) cur++; else cur += num; if (cur > sizeof(mail) || cur < 1) { write("Gone too far.\n"); if (num > 0) cur = sizeof(mail); else cur = 1; } else read_message(cur); break; case "-" : if (num == 0) cur--; else cur -= num; if (cur > sizeof(mail) || cur < 1) { write("Gone too far.\n"); if (num>0) cur = 1; else cur = sizeof(mail); } break; case "x" : write ("Dont let them messages pile up.\n"); new = -1; save_me(); if (do_this_last) call_other(do_this_last[0], do_this_last[1], do_this_last[2]); else dest_me(); return 1; case "q" : delete_things(); new = -1; save_me(); write("Ok.\n"); if (do_this_last && do_this_last[0] && stringp(do_this_last[1])) call_other(do_this_last[0], do_this_last[1], do_this_last[2]); else dest_me(); return 1; case "d" : ms = expand_range(str); for (i=0;i<sizeof(ms);i++) { deleted[ms[i]-1] = !deleted[ms[i]-1]; if (deleted[ms[i]-1]) write("Deleted message "+ms[i]+".\n"); else write("Undeleted message "+ms[i]+".\n"); } break; case "m" : mail_message(str,""); /* no cc at this point ;) */ return 0; break; case "r" : if (num) if (num > sizeof(mail) || num < 1) write("Number out of bounds (6!!!!)\n"); else { reply_message(mail[num-1][M_FROM], mail[num-1][M_SUB], mail[num-1][M_CC]+","+ implode(explode(mail[num-1][M_CC]+","+ mail[num-1][M_TO], ",") - ({ from }), ",")); return 0; } else { /* ok so handle the fact that we may be a CC and send to the person who * it was addressed to as well. */ reply_message(mail[cur-1][M_FROM], mail[cur-1][M_SUB], implode(explode(mail[cur-1][M_CC]+","+ mail[cur-1][M_TO], ",") - ({ from }), ",")); return 0; } break; case "h" : if(!str || str=="") show_headers((string)this_player()->query_name(), expand_range("")); else show_headers(0, expand_range(str)); break; case "?" : cat("/doc/helpdir/mailer"); break; case "R" : if (num) if (num > sizeof(mail) || num < 1) write("Number out of bounds. Better hire a better chicken\n"); else /* dont remember CC's */ { reply_message(mail[num-1][M_FROM], mail[num-1][M_SUB], ""); return 0; } else { reply_message(mail[cur-1][M_FROM], mail[cur-1][M_SUB], ""); return 0; } break; case "s" : /* save to a file... only for the lonely, I mean wizs */ if (!this_player()->query_creator()) { write("Only creators can save files, sorry.\n"); break; } if (!num) num = cur; if (num < 1 || num > sizeof(mail)) { write("Message out of bounds.\n"); break; } str = (string)this_player()->get_path(str); if (!"/secure/master"->valid_write(str, geteuid(this_player()), "write_file")) { write("You cannot write to that file.\n"); break; } if ((i=file_size(str)) > 0) write("Appending.\n"); else if (i == -2) { write("Directory\n"); break; } seteuid(geteuid(this_player())); if (!write_file(str, message_string(num))) write("Write file failed.\n"); else write("Saved message "+num+" to "+str+".\n"); seteuid("mailer"); break; case "f" : /* forward a message... */ if (!num) num = cur; if (num < 1 || num > sizeof(mail)) { write("Message out of bounds.\n"); break; } do_forward(str, "Fwd: "+mail[num-1][M_SUB], ">"+replace(message_string(num), "\n", "\n>")); return 0; } status_line(); input_to("read_loop"); } /* read_loop() */ void dest_me() { MAIL_TRACK->delete_mailer(this_object()); ::dest_me(); } int *expand_range(string str) { int *ms, i, num, start, end; string s1,s2; if (str == "" || !str) str = ""+cur; if (!sizeof(mail)) return ({ }); str = implode(explode(str, " "),""); ms = ({ }); if (sscanf(str, "%sall%s", s1,s2)==2) { for (i=1;i<sizeof(mail)+1;i++) ms += ({ i }); return ms; } while (sscanf(str, "%d%s",start,str) == 2) { if (start < 1) start = 1; if (start > sizeof(mail)) start = sizeof(mail); if (str && str != "" && str[0] == '-') { sscanf(str, "-%d%s", end, str); if (end >= start) { if (end > sizeof(mail)) end = sizeof(mail); for (i=start;i<=end;i++) if (member_array(i, ms) == -1) ms += ({ i }); } } else if (member_array(start, ms) == -1) ms += ({ start }); sscanf(str,",%s",str); } return ms; } /* expand_range() */