/
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/
/*
 * Intermud mail server, used by Huthar's mailer daemon
 * Original author: Huthar
 * Rewritten to conform to new socket efun specs,  Blackthorn (10/31/92)
 * Modified by Truilkan for use in Basis mudlib (11/01/92)
 * Modified by Pinkfish for use in the Discworld mudlib (5 jan 92)
 * (Stupid american date formats).
 */

#include "mail.h"
#include "nameserver.h"
#include "socket.h"
#include "inet.h"

#define SAVE "/net/save/"

#define report(x) log_file("MAIL",ctime(time())+" "+x+"\n")
#define log(x) log_file("MS", x)
#define MS_SAVE "mail-queue"
#define FLUSH_TIME 86400
#define AGE_TIME 604800
#define EOF "%EOF%"
#define EOT "%EOT%"

#define DEBUG

#ifdef DEBUG
#define TP(STR) tell_object(find_player("newstyle"), STR)
#else
#define TP(STR)
#endif

static mixed mqi;
static mixed outgoing;
static int conn;

mixed   mail_queue;
int     date_last_flushed;

void    process_message( int fd );
void    flush_mail_queue();
void    age_queue();

void    reset()
{
    if( (time() - date_last_flushed) > FLUSH_TIME )
    {
	mqi = keys( mail_queue );
	flush_mail_queue();
	date_last_flushed = time();
    }
    age_queue();
}				/* reset() */

void    create()
{
    seteuid( (string)"/secure/master"->creator_file( file_name( this_object() ) ) );
    mail_queue = ([ ]);
    mqi = ({ });
    restore_object( SAVE + MS_SAVE );
    mqi = keys( mail_queue );
    flush_mail_queue();
}				/* create() */

/*
 * Ahhh, so this send the intermud mail...
 */
void    remote_mail( string from, string to, string subject, string cc,
		     string body, string *goto )
{
    int     i;
    string *tmp, name, mud;

    tmp = explode( body, "\n" );
    while( tmp && (i = member_array( EOF, tmp )) != -1 )
    {
	tmp[ i ] = EOF + ".";
    }

    if( !tmp )
	tmp = ({ });
    body = implode( tmp, "\n" );

/* Ok, now make up a list of muds and who to send to at each one. */
    for( i = 0; i < sizeof( goto ); i++ )
    {
	sscanf( goto[ i ], "%s@%s", name, mud );
	if( !mail_queue[ mud ] )
	{
	    mail_queue[ mud ] = ({ });
	}
	mail_queue[ mud ] += ({ 
      ([ "recipient": name, "to": to, "cc":cc,
      "from": from, "subject": subject, "date":time(),
      "message":		      body ]),
				    });
	mqi += ({ mud });
	if( member_array( mud, mqi ) == -1 )
	    mqi += ({ mud });
    }

    save_object( SAVE + MS_SAVE );
    flush_mail_queue();
}				/* remote_mail() */

void    dest_me()
{
    destruct( this_object() );
}				/* dest_me() */

void    set_mqi( mixed m )
{
    mqi = m;
}
string *query_mqi()
{
    return mqi;
}

mapping query_mail_queue()
{
    return mail_queue;
}
void    set_mail_queue( mixed a )
{
    mail_queue = a;
}

void    clear_mail_queue()
{
    mail_queue = ([ ]);
    save_object( SAVE + "mail-queue" );
}				/* clear_mail_queue() */

void    age_queue()
{
    int     i, j;
    string *key;
    mixed   tmp;

    key = keys( mail_queue );

    for( i = 0; i < sizeof( key ); i++ )
    {
	tmp = mail_queue[ key[ i ] ];
	for( j = 0; j < sizeof( tmp ); j++ )
	{
	    if( time() - tmp[ j ][ "date" ] > AGE_TIME )
	    {
		log( "Aging mail from: " +
		     tmp[ j ][ "from" ] + ", dated: " + tmp[ j ][ "date" ] + "\n" );
		tmp = delete( tmp, j, 1 );
/* Thats probably what exclude_array does.
   exclude_array(tmp, j);
 */
	    }
	}
    }
}				/* age_queue() */

void    flush_mail_queue()
{
    string *muds, address, port;
    int     id;

    if( !sizeof( mqi ) )
	return;

    outgoing = mail_queue[ mqi[ 0 ] ];
/* ahhhh.  so this is what does the junk! */
    INET_D->open_to_service( "mail", INETD_TYPE, mqi[ 0 ] );
    TP( "Opening to " + mqi[ 0 ] + "\n" );
    conn = 0;
}				/* flush_mail_queue() */

/*
 * Send a bounce to all the messages in the outgoing queue...
 */
void    bounce_message( string mess )
{
    int     i;

    for( i = 0; i < sizeof( outgoing ); i++ )
    {
	MAILER->do_mail_message( outgoing[ i ][ "from" ], "Mail-Server",
				 "Delivery failed: " + mess, "",
				 "Message sent follows:\n>To: " + outgoing[ i ][ "to" ] +
				 "\n>Cc : " + outgoing[ i ][ "cc" ] + "\n>Subject: " +
				 outgoing[ i ][ "subject" ] + "\n\n" + outgoing[ i ][ "message" ],
				 1 );
	report( "F " + outgoing[ i ][ "from" ] + " " + outgoing[ i ][ "to" ] + " (" + mess + ")" );
    }
}				/* bounce_message() */

void    failed( string reason )
{
    TP( "Failed.\n" );
    bounce_message( reason );
    map_delete( mail_queue, mqi[ 0 ] );
    mqi -= ({ mqi[ 0 ] });
    save_object( SAVE + MS_SAVE );
    call_out( "flush_mail_queue", 60 );
}				/* failed() */

void    connected( int id )
{
    int     i;

    TP( "Connected.\n" );
    previous_object()->write_fd( id, MUD_NAME + "\n" );
    for( i = 0; i < sizeof( outgoing ); i++ )
    {
	previous_object()->write_fd( id, outgoing[ i ][ "recipient" ] + "\n" );
	previous_object()->write_fd( id, replace( outgoing[ i ][ "to" ], ",", " " ) + "\n" );
	previous_object()->write_fd( id, replace( outgoing[ i ][ "cc" ], ",", " " ) + "\n" );
	previous_object()->write_fd( id, outgoing[ i ][ "from" ] + "\n" );
	previous_object()->write_fd( id, outgoing[ i ][ "subject" ] + "\n" );
	previous_object()->write_fd( id, outgoing[ i ][ "date" ] + "\n" );
	previous_object()->write_fd( id, outgoing[ i ][ "message" ] + "\n" );
	previous_object()->write_fd( id, EOF + "\n" );
	report( "S " + outgoing[ i ][ "from" ] + " " + outgoing[ i ][ "to" ] );
    }
    previous_object()->write_fd( id, EOT + "\n" );
/* previous_object()->close_fd(id); */
    map_delete( mail_queue, mqi[ 0 ] );
    mqi -= ({ mqi[ 0 ] });
    save_object( SAVE + MS_SAVE );
    conn = 1;
    call_out( "flush_mail_queue", 60 );
    previous_object()->close_fd( id );
}				/* connected() */

void    close_callback( int id )
{
    TP( "Close.\n" );
    if( !conn )
    {
	bounce_message( "connection timed out" );
	map_delete( mail_queue, mqi[ 0 ] );
	mqi -= ({ mqi[ 0 ] });
	save_object( SAVE + MS_SAVE );
	call_out( "flush_mail_queue", 60 );
    }
}				/* close_call_back() */