/
LIB3/
LIB3/D/ADMIN/
LIB3/D/ADMIN/OBJ/
LIB3/D/ADMIN/ROOM/W/
LIB3/D/HOME/
LIB3/D/HOME/CITY/ARENA/
LIB3/D/HOME/CITY/ITEMS/
LIB3/D/HOME/CITY/POSTOFFI/
LIB3/DOC/
LIB3/GLOBAL/SPECIAL/
LIB3/GLOBAL/VIRTUAL/
LIB3/NET/
LIB3/NET/CONFIG/
LIB3/NET/DAEMON/CHARS/
LIB3/NET/GOPHER/
LIB3/NET/INHERIT/
LIB3/NET/OBJ/
LIB3/NET/SAVE/
LIB3/NET/VIRTUAL/
LIB3/OBJ/B_DAY/
LIB3/OBJ/HANDLERS/TERM_TYP/
LIB3/PLAYERS/B/
LIB3/PLAYERS/N/
LIB3/ROOM/
LIB3/SAVE/
LIB3/SAVE/BOARDS/
LIB3/SAVE/ENVIRON/
LIB3/SAVE/POST/
LIB3/STD/COMMANDS/SHADOWS/
LIB3/STD/CREATOR/
LIB3/STD/DOM/
LIB3/STD/EFFECTS/
LIB3/STD/EFFECTS/HEALING/
LIB3/STD/EFFECTS/OTHER/
LIB3/STD/EFFECTS/POISONS/
LIB3/STD/ENVIRON/
LIB3/STD/GUILDS/
LIB3/STD/LIQUIDS/
LIB3/STD/ROOM/
LIB3/STD/TRIGGER/SHADOW/
LIB3/W/
LIB3/W/BANNOR/
LIB3/W/NEWSTYLE/
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() */