// file: mailbox. // By inspiral, ported from Pinkfish ?? // No, originally written by Huthar, rewritten by Inspiral. // Leto added checks for when there is prev_obj anymore with never drivers // Leto changed logging to us elogs.h #pragma save_binary #define LOCAL_TZONE "CET" #define MONITOR_TIME 2500 #include <uid.h> #include <config.h> #include <mailer.h> #include <net/macros.h> #include <logs.h> #define QUERY_NAME link_data( "name" ) // XXX: for TMI 1.0 mudlibs // The following are the variables that will be saved as the datafiles mapping *mailbox, my_groups; static string file, *dir_list; static int maxmsg, dir_idx; int valid_access( string frm ) { string accessor; mixed owner; if( previous_object() ) { if( geteuid( previous_object() ) == ROOT_UID ) return 1; // Next two ifs check to see if this is a trusted mailer accessor = base_name( previous_object() ); if( member_array( accessor, TRUSTED_MAILERS ) > -1 ) return 1; } // If a frm == 0 then this is a read operation. If the player may // always read mail if he is the owner of the box. if( file ) { owner = explode( file, "/" ); if ( !owner || !owner[<1] ) return 0; owner = owner[<1]; if ( (string)this_player(1)->QUERY_NAME == owner && !frm ) return 1; } // If frm != 0 then make sure that frm == this_player(1) to // prevent forgeries... if( frm == ( string ) this_player( 1 ) -> QUERY_NAME ) return 1; return 0; // Not a legal operation! } // valid_access create() { seteuid( ROOT_UID ); mailbox = ({ }); maxmsg = 0; file = 0; dir_idx = sizeof( dir_list = get_dir( MBOXDIR ) ) - 1; // Mobydick commented out the monitor call to save CPU and file access. // This, he thinks, is probably something we should run only when we // think a lot of mailboxes have had users deleted out from under them.. // Right after a purge, perhaps. // call_out( "monitor_boxes", 10 ); } // create void update_box( string owner ) { if( file != user_mbox_file( owner ) ) { if( file ) { if( sizeof( mailbox ) ) save_object( file ); else rm( file + __SAVE_EXTENSION__ ); } file = user_mbox_file( owner ); mailbox = ({ }); if( file_exists( file + __SAVE_EXTENSION__ ) ) restore_object( file ); if( !mailbox ) mailbox = ({ }); maxmsg = sizeof( mailbox ); } } // update_box int remote_mail( string rcvr, mapping data ) { string own, mud; if( sscanf( rcvr, "%s@%s", own, mud ) != 2 ) return 0; if( htonn( mud ) == mud_nname() ) return 0; /* if( previous_object() != find_object_or_load( NETMAIL_D ) ) NETMAIL_D -> push_mail( copy( data ) ); */ return 1; } // remote_mail varargs void remove_message( string owner, int num ) { update_box( owner ); /* if( !valid_access( 0 ) ) { printf( "Illegal access attempt to mailer_d.\n" ); return; } */ if( num < 0 || num >= maxmsg ) return; // remove msg & decrement maxmsg MAILMESG_D -> delete_mesg( mailbox[num]["idx"], owner ); mailbox = mailbox[0 .. num - 1] + mailbox[ num + 1 ..--maxmsg]; } // remove_message int add_message( string owner, mapping data ) { string own, mud; owner = lower_case( owner ); if( remote_mail( owner, data ) ) return 1; if( !user_exists( owner ) ) return 0; update_box( owner ); if( !valid_access( data["from"] ) ) { printf( "Illegal access attempt to mailer_d.\n" ); return 0; } mailbox += ({ data }); maxmsg++; update_box( owner ); return 1; } // add_message mixed mail_status( string owner ) { int cnt, i; update_box( owner ); i = maxmsg; while( i-- ) { if( !( mailbox[i]["flags"]&MAIL_READ ) ) cnt++; } return([ "unread" : cnt, "total" : maxmsg ]); } // mail_status void set_flags( string owner, int num, int flags ) { update_box( owner ); if( !valid_access( 0 ) ) { printf( "Illegal access attempt to mailer_d.\n" ); return; } if( num < 0 || num >= maxmsg ) return; if( !mailbox[num]["idx"] ) mailbox[num]["idx"] = mailbox[num]["date"]; mailbox[num]["flags"] = flags; } // set_flags void biff( string str, string from, string subject ) { string grp, *grparr; object ob; int i; if( sscanf( str, "(%s)", grp ) ) { grparr = ( ( mapping ) GROUP_OB -> query_groups() )[grp]; i = sizeof( grparr ); while( i-- ) biff( grparr[i], from, subject ); return; } if( ( ob = find_player( str ) ) && ( ob -> getenv( "mail_notification" ) ) ) message( "system", sprintf( "\ \n>>> New mail has arrived from: %s.\n>>> Subject: %s\n", capitalize( from ), subject ), ob ); } // biff string * expand_to( mixed str ) { string grp, *rtn; int i, max; mapping grps; string t1, t2; rtn = ({ }); i = sizeof( str ); while( i-- ) { if( !str[i] ) continue; str[i] = lower_case( str[i] ); if( sscanf( str[i], "%s@%s", t1, t2 ) == 2 ) { rtn += ({ str[i] }); continue; } if( sscanf( str[i], "(%s)", grp ) ) { grps = ( mapping ) GROUP_OB -> query_groups(); if( sizeof( grps[grp] ) ) rtn += expand_to( grps[grp] ); else printf( "Group `%s' doesn't exist.\n", grp ); continue; } if( user_exists( str[i] ) ) rtn += ({ str[i] }); else printf( "User `%s' not found.\n", str[i] ); } return rtn; } // expand_to string * send_mail( mapping newmsg ) { int i, j; string *tmpto, *rtn, previous; mapping bouncemsg; string mesg; newmsg += ([ ]); previous = base_name( previous_object() ); if( !valid_access( newmsg["from"] ) ) { log_file( "MAILER_LOG", "Illegal access by: " + identify( previous_object() ) + "\n" ); return ({ }); } tmpto = expand_to( newmsg["to"] ) + expand_to( newmsg["cc"] ); tmpto = uniq_array( tmpto ); i = sizeof( tmpto ); rtn = allocate( i ); j = 0; while( i-- ) { if( !remote_mail( tmpto[i], newmsg ) ) rtn[j++] = tmpto[i]; } if( j != sizeof( tmpto ) ) if( previous_object() != find_object_or_load( NETMAIL_D ) ) NETMAIL_D -> push_mail( copy( newmsg ) ); rtn = rtn[0..j - 1]; mesg = copy( newmsg["message"] ); map_delete( newmsg, "message" ); newmsg["idx"] = (int) MAILMESG_D -> add_mesg( rtn, mesg ); while( j-- ) { // Messages coming in from NETMAIL_D look like "<user>@Tabor" sscanf( rtn[j], "%s@%*s", rtn[j] ); // If we fail sending the message to the user on this mud, then // we prepare and send out a bounced message report. if( !add_message( rtn[j], newmsg ) ) { bouncemsg = allocate_mapping( 6 ); // We have to make a copy because we're still needing newmsg // fully intact, and here, we plan towmsg ); bouncemsg["message"] = "> " + replace_string( mesg, "\n", "\n> " ); bouncemsg[ "message" ] = "Date: " + ctime( time() ) + " " LOCAL_TZONE + ".\n" + "Message from POSTMASTER@" + Mud_name() + ":\n" + "Unable to send to user: " + capitalize( rtn[j] ) + "@" + Mud_name() + ".\n\n" + read_file( MAIL_BOUNCE_FILE ) + "Original Subject: " + newmsg["subject"] + "\n" + bouncemsg[ "message" ] + "\n**** End of Message ****\n"; bouncemsg[ "subject" ] = "User \"" + rtn[j] + "\" doesn't exist."; bouncemsg[ "date" ] = time(); map_delete( bouncemsg, "cc" ); bouncemsg[ "to" ] = ({ newmsg[ "from" ] }); bouncemsg[ "from" ] = "POSTMASTER"; log_file( "MAILER_LOG", sprintf( "%s unable to send to %s\n", newmsg["from"], rtn[j] ) ); NETMAIL_D -> push_mail( bouncemsg ); continue; } call_out( "biff", 0, rtn[j], newmsg["from"], newmsg["subject"] ); } // If i > j, then there's a mud to send to. First, make sure // we aren't the netmail daemon sending us a message to process. // We stick this at the end because we don't have to send it immediately, // and because otherwise, since netmail does some funky things with // the mapping, we'd have to copy() the mapping before we sent if off. if( ( previous != NETMAIL_D ) && ( i > j ) ) NETMAIL_D -> push_mail( newmsg ); return tmpto; } // send_mail int valid_shadow() { return 1; } void flush_files( mapping groups ) { if( !file ) return; if( sizeof( mailbox ) ) save_object( file ); else if( file_exists( file + __SAVE_EXTENSION__ ) ) rm( file + __SAVE_EXTENSION__ ); } int fix_message( string owner, mapping data ) { string own, mud; string mesg; string *tmpto; owner = lower_case( owner ); if( !user_exists( owner ) ) return 0; update_box( owner ); mesg = copy( data["message"] ); tmpto = expand_to( data["to"] ) + expand_to( data["cc"] ); tmpto = uniq_array( tmpto ); tmpto = filter_array( tmpto, "not_saved", this_object() ); data["idx"] = (int) MAILMESG_D -> add_mesg( tmpto, mesg ); map_delete( data, "message" ); mailbox += ({ data }); maxmsg++; update_box( owner ); MAILMESG_D -> save_mesg(); return 1; } // fix_message int not_saved( string name ) { if( strsrch( name, "@" ) == -1 ) if( user_exists( lower_case( name ) ) ) return 1; return 0; } static void remove_box( string owner ) { int i; update_box( owner ); i = sizeof( mailbox ); while( i-- ) remove_message( owner, i ); rm( user_mbox_file( owner ) + __SAVE_EXTENSION__ ); } int monitor_boxes() { int i, out; string *names; names = get_dir( MBOXDIR + "/" + dir_list[dir_idx] + "/" ); i = sizeof( names ); while( i-- ) { names[i] = replace_string( names[i], __SAVE_EXTENSION__, "" ); if( !user_exists( names[i] ) ) { out++; message( "debug", "notuser: " + names[i] + "\n", find_player( "inspiral" ) ); remove_box( names[i] ); continue; } call_out( "clean_box", 4+(3*i), names[i] ); } if( --dir_idx < 0 ) dir_idx = sizeof( dir_list = get_dir( MBOXDIR ) ) - 1; call_out( "monitor_boxes", MONITOR_TIME ); return out; } int clean_box( string owner ) { int i, j; update_box( owner ); i = sizeof( mailbox ); while( i-- ) { if( !file_exists( mail_mesg_file( mailbox[i]["idx"] ) + __SAVE_EXTENSION__ ) ) { remove_message( owner, i ); j++; } } return j; } string *verify_mbox( string *whom, int idx ) { int i, j; string *tmp; tmp = ({ }); i = sizeof( whom ); while( i-- ) { update_box( whom[i] ); j = sizeof( mailbox ); while( j-- ) if( mailbox[j]["idx"] == idx ) { tmp += ({ whom[i] }); } } return tmp; } /* EOF */