Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/secure/mailer.c b/secure/mailer.c
new file mode 100644
index 0000000..9901fac
--- /dev/null
+++ b/secure/mailer.c
@@ -0,0 +1,632 @@
+// MorgenGrauen MUDlib
+//
+// mailer.c
+//
+// $Id: mailer.c 9547 2016-04-17 19:27:47Z Zesstra $
+
+/*
+ *------------------------------------------------------------
+ * The mail demon. Receives mail from users and delivers it into
+ * the mail directory.
+ *
+ * Deepthought, Nightfall, 25-May-92
+ * Remove-Functions : Jof, 29-June-92
+ * Caching, DeleteUnreadFolder, small changes: Loco, 08-Feb-97
+ * General clean-up and speed-up: Tiamak, 18-Jan-2000
+ * DON'T USE restore_object any more, use GetFolders instead!
+ *------------------------------------------------------------
+ *
+ * Save file format (sort of formal notation):
+ *
+ * mixed *folders = ({
+ * ({ string name1; string name2; ... string nameN; })
+ * ({ mixed *msgs1; mixed *msgs2; ... mixed *msgsN; })
+ * })
+ *
+ * Each msgs field is an array of messages:
+ *
+ * mixed *msgs = ({ mixed *message1; ... mixed *messageM })
+ *
+ * A message is represented as an array with the following fields:
+ *
+ * mixed *message = ({
+ * string from;
+ * string sender;
+ * string recipient;
+ * string *cc;
+ * string *bcc;
+ * string subject;
+ * string date;
+ * string id;
+ * string body;
+ * })
+ *
+ * The mailer demon (/secure/mailer) provides the following functions:
+ *
+ * string *DeliverMail(mixed *message)
+ * Hand a mail message over to the mailer demon. The mailer
+ * demon extracts recipients from the recipient, cc and bcc
+ * fields and removes the bcc information. It then deposits
+ * the message to the mail files of all recipients. A valid
+ * message is shown above. Returns a list of successfully
+ * delivered recipients.
+ *
+ * int FingerMail(string user)
+ * Gives the number of unread messages a user has.
+ *------------------------------------------------------------
+ */
+#pragma strict_types
+#pragma no_clone
+#pragma no_shadow
+#pragma no_inherit
+#pragma verbose_errors
+#pragma pedantic
+#pragma warn_deprecated
+
+#include <config.h>
+#include <mail.h>
+#include <wizlevels.h>
+
+// debugging
+#define DEBUG(msg) if ( find_player("zesstra") ) \
+ tell_object( find_player("zesstra"), "MAILER: "+msg )
+#undef DEBUG
+#define DEBUG(x)
+
+// write out a message to the recipient
+#define NOTIFY_RECIPIENT
+// who gets undeliverable mail?
+#define BOUNCE_ADDR "mud@mg.mud.de"
+#define SECURITY(x) (geteuid(x) == ROOTID || geteuid(x) == MAILID)
+// flag for _DeliverMail
+#define MAIL_DELAYED 4096
+
+// prototypes
+protected void create();
+static int GetFolders( string user );
+static string _unify( string str );
+static string *unify( string *str );
+static string *expand( string *addr, int expa );
+static string _filter_addr( string addr );
+public string *DeliverMail( mixed msg, int expa );
+public int FingerMail( string user );
+static void save_msg( mixed msg, string user );
+public int RemoveMsg( int msg, int folder, string user );
+public int MoveMsg( int msg, int folder, string newfolder, string user );
+public int DeleteUnreadFolder( string user );
+public int RemoveFolder( string folder, string user );
+public int MakeFolder( string folder, string user );
+public int query_recipient_ok( string name );
+public void deliver_mail( string recipient, string from, string subject,
+ string mail_body );
+
+
+mixed *folders; /* used for save and restore of mail files */
+static mapping alias;
+static string cachedname; /* whose folder is still in memory? */
+
+
+protected void create()
+{
+ mixed tmp;
+ int i;
+ string s1, s2;
+
+ seteuid(ROOTID);
+ alias=([]);
+
+ if ( tmp = read_file("/mail/system.mailrc") ){
+ tmp = explode( tmp, "\n" );
+
+ for ( i = sizeof(tmp); i--; )
+ if ( sscanf( tmp[i], "%s %s", s1, s2 ) == 2 )
+ alias[s1] = s2;
+ }
+}
+
+
+// GetFolders laedt einen folder, wenn er nicht im cache ist, und gibt
+// 0 zurueck, wenn der folder nicht vorhanden oder evtl auch leer ist.
+// Sinn: Vor allem bei Listenargumenten im mailer kann es leicht vorkommen,
+// dass dasselbe mailfile einige Male hintereinander gebraucht wird.
+
+static int GetFolders( string user )
+{
+ if ( user == cachedname ){
+ DEBUG( "Using cached folder for " + user + "\n" );
+ return sizeof(folders[1]);
+ }
+
+ cachedname = user;
+
+ if ( !restore_object( MAILPATH + "/" + user[0..0] + "/" + user ) ){
+ DEBUG( "Loading folder: " + user + " (empty)\n" );
+ folders = ({ ({}), ({}) });
+ return 0;
+ }
+
+ DEBUG( "Loading folder:" + user + "\n" );
+ return 1;
+}
+
+
+static string _unify( string str )
+{
+ return str[0] == '\\' ? str[1..] : str;
+}
+
+
+static string *unify( string *str )
+{
+ if ( !pointerp(str) )
+ return ({});
+
+ str = map( filter( str, #'stringp/*'*/ ), #'lower_case/*'*/ );
+ str = map( str, "_unify", this_object() );
+
+ return m_indices( mkmapping(str) );
+}
+
+
+#define MG_NAMES ({ MUDNAME, "mg", "morgengrauen", "mud", "mg.mud.de" })
+
+string expandSystemRecursive(string addr,int maxrec){
+ string *list,*tlist;
+ string ret,tmp;
+ int i,size;
+
+ if(maxrec>8 || !addr){
+ return addr;
+ }
+ maxrec++;
+
+ tlist=({});
+ ret="";
+
+ list=explode(addr,",");
+ list-=({""});
+ size=sizeof(list);
+ for(i=0;i<size;i++){
+ if(tmp=alias[list[i]]){
+ tlist+=explode(tmp,",");
+ }
+ else{
+ tlist+=({list[i]});
+ }
+ }
+ tlist-=({""});
+ ret=implode(tlist,",");
+
+ if((ret!=addr)!=0){
+ ret=expandSystemRecursive(ret,maxrec);
+ }
+ return ret;
+}
+
+// expa: also do alias and forward-expansion? (for inbound external mail)
+// expa == 0 means full expansion, known flags are NO_SYSTEM_ALIASES
+// and NO_USER_ALIASES
+static string *expand( string *addr, int expa )
+{
+ string tmp, *new, *ret;
+ int i;
+ closure qf;
+
+ ret = ({});
+ addr -= ({""});
+ qf = symbol_function( "QueryForward", FWSERV );
+
+ for ( i = sizeof(addr); i--; ){
+ addr[i] = lower_case( addr[i] );
+ // @morgengrauen-namen werden lokal zugestellt.
+ if ( sizeof(new = explode( addr[i], "@" )) == 2 &&
+ member( MG_NAMES, new[1] ) != -1 )
+ addr[i] = new[0];
+
+ if ( !(expa & NO_SYSTEM_ALIASES) && tmp = expandSystemRecursive(addr[i],0) ){
+ ret += explode( tmp, "," );
+ }
+ else
+ ret += ({ addr[i] });
+ }
+
+ for ( i = sizeof(ret); i--; ){
+ if ( ret[i][0] == '\\' )
+ ret[i] = ret[i][1..];
+ else if ( !(expa & NO_USER_ALIASES) )
+ ret = ret - ({ ret[i] }) +
+ explode( funcall( qf, ret[i] ), "," );
+ }
+
+ return ret;
+}
+
+
+static string _filter_addr( string addr )
+{
+ addr = regreplace( addr, "[^<]*<(.*)>[^>]*", "\\1", 0);
+ return regreplace( addr, " *([^ ][^ ]*).*", "\\1", 0);
+}
+
+#ifdef INTERNET_MAIL_ENABLED
+#define FOOTER \
+ "\n*****************************************************************\n" \
+ "* MorgenGrauen MailRelay v1.0 - Processed %s, %s *\n" \
+ "* MorgenGrauen - mg.mud.de 23 - 87.79.24.60 23 *\n" \
+ "*****************************************************************"
+#endif
+
+public string *DeliverMail( mixed msg, int expa )
+{
+ string sender, *recipients, *recok, t, *tmp;
+ mixed *newmsg;
+ int i;
+#ifdef INTERNET_MAIL_ENABLED
+ int ext;
+#endif
+
+ if ( !pointerp(msg) || sizeof(msg) != 9 )
+ return 0;
+
+ DEBUG( sprintf( "DeliverMail: %O %O\n", msg[0..4] +({0})+ msg[6..7], expa ) );
+ t = ctime(time());
+
+ // Ohne Empfaenger wird abgebrochen
+ if (!stringp(msg[MSG_RECIPIENT]))
+ return 0;
+
+ if ( !(expa & MAIL_DELAYED) ){
+ /* determine the real sender */
+ if ( extern_call() && object_name(previous_object())[0..7] != "/secure/" )
+ sender = getuid( this_interactive() || previous_object() );
+ else
+ sender = msg[MSG_SENDER];
+
+ /* make a list of all recipients */
+ recipients = ({ msg[MSG_RECIPIENT] });
+
+ if ( !(expa & NO_CARBON_COPIES) ){
+ if ( pointerp(msg[MSG_CC]) )
+ recipients += msg[MSG_CC];
+
+ if ( pointerp(msg[MSG_BCC]) )
+ recipients += msg[MSG_BCC];
+ }
+
+ // Mail-Aliase ersetzen
+ recipients = expand( recipients, expa );
+
+ // doppelte Adressen loeschen (nebenbei: auf Kleinschreibung wandeln)
+ recipients = unify( recipients );
+
+ // Realnamen und Kommentare entfernen
+ recipients = map( recipients, "_filter_addr", this_object() );
+
+ // auf ungueltige Zeichen checken
+ if ( sizeof(tmp = regexp( recipients, "^[-_.@a-z0-9]*$" ))
+ != sizeof(recipients) ){
+ tmp = recipients - tmp;
+
+ for ( i = sizeof(tmp); i--; )
+ log_file( "MAIL_INVALID", sprintf( "%s: Mail von %O (%O) an "
+ "'%O'.\n", dtime(time()),
+ msg[MSG_FROM],
+ sender, tmp[i] ) );
+
+ recipients -= tmp;
+ }
+
+ // check for valid Subject and Body
+ if (!stringp(msg[MSG_SUBJECT]))
+ msg[MSG_SUBJECT] = "(no subject given)";
+ if (!stringp(msg[MSG_BODY]))
+ msg[MSG_BODY] =
+ "\n\nSorry - This mail was delivered without a mail body\n\n";
+
+ DEBUG( sprintf( "NEED TO DELIVER TO %O\n", recipients ) );
+
+ /* build the new message */
+ newmsg = ({ msg[MSG_FROM], sender, msg[MSG_RECIPIENT],
+ msg[MSG_CC], "", msg[MSG_SUBJECT],
+ dtime(time()), MUDNAME + ":" + time(),
+ msg[MSG_BODY] });
+ }
+
+ /* Send it off ... */
+ recok = ({ });
+
+ // ACHTUNG: durch expand() geaenderte Adressen werden zugestellt,
+ // aber durch /mail/mailer.c zusaetzlich als unzustellbar genannt!
+
+ for ( i = sizeof(recipients); i-- /*&& get_eval_cost() > 500000*/; ){
+ DEBUG( sprintf( "Begin delivering to %s. Evalcosts left: %d.\n",
+ recipients[i], get_eval_cost() ) );
+ if ( member( recipients[i], '@' ) > 0 &&
+ strstr( recipients[i], "daemon" ) < 0 ) {
+ string rec, mud;
+
+ tmp = explode( recipients[i], "@" );
+ mud = tmp[1];
+ rec = tmp[0];
+ sender = regreplace( sender, "@", "%", 1 );
+ // Zustellung via Intermud-Mail an andere Muds.
+ if ( member( mud, '.' ) == -1 ) {
+ "/secure/udp_mail"->deliver_mail( rec, mud, sender,
+ msg[MSG_SUBJECT],
+ msg[MSG_BODY] );
+ recok += ({ recipients[i] });
+ }
+#ifdef INTERNET_MAIL_ENABLED
+ // Zustellung in den Rest des Internets.
+ else {
+ ext = 1;
+ sender = explode( sender, "%" )[0];
+ rec = explode( regreplace( rec, "@", "%", 1 ), "%" )[0];
+ mud = explode( regreplace( mud, "@", "%", 1 ), "%" )[0];
+
+ write_file( sprintf( "/mail/outbound/%s.%d-%d-%d",
+ sender, time(), i, random(123456) ),
+ sprintf( "%s\n%s@%s\n"
+ "Subject: %s\n"
+ "X-MUD-From: %s\n"
+ "X-MUD-To: %s\n"
+ "X-MUD-Cc: %s\n"
+ "X-MU-Subject: %s\n\n",
+ sender, rec, mud,
+ msg[MSG_SUBJECT],
+ sender, recipients[0],
+ pointerp(msg[MSG_CC]) ?
+ implode( msg[MSG_CC], "," ) : "",
+ msg[MSG_SUBJECT] ) + msg[MSG_BODY] +
+ sprintf( FOOTER, t[4..10] + t[20..], t[11..18] )
+ + "\n" );
+ recok += ({ recipients[i] });
+ }
+#endif // INTERNET_MAIL_ENABLED
+
+ }
+ else
+ if ( file_size( SAVEPATH + recipients[i][0..0] + "/" +
+ recipients[i] + ".o" ) >=0 ){
+ save_msg( newmsg, recipients[i] );
+ recok += ({ recipients[i] });
+ }
+ else {
+ string *tmpmsg = copy(newmsg);
+ tmpmsg[MSG_BODY] = "--- Text der Mail geloescht. ---\n";
+ write_file( sprintf( "/mail/outbound/postmaster.%d-%d",
+ time(), random(time()) ),
+ sprintf( "postmaster\n" + BOUNCE_ADDR +
+ "\nSubject: Undeliverable Mail\n%O\n",
+ tmpmsg) );
+ }
+ DEBUG( sprintf( "End delivering to %s. Evalcosts left: %d.\n",
+ recipients[i], get_eval_cost() ) );
+ }
+#ifdef INTERNET_MAIL_ENABLED
+ if ( ext )
+ send_udp( UDPSERV, 4123, "DELIVERMAIL" );
+#endif
+ return recok;
+}
+
+
+public int FingerMail( string user )
+{
+ int newfolder, i;
+
+ //Zugriff beschraenken, Zahl der gelesenen Mails ist Privatsphaere
+ if (!objectp(this_interactive()) || !stringp(user) || !sizeof(user))
+ return(-1);
+ if ((getuid(this_interactive())!=user) &&
+ (process_call() || !ARCH_SECURITY)) return(-1);
+
+ if ( !GetFolders(user) )
+ return 0;
+
+ if ( (newfolder = member(folders[0],"unread")) != -1 )
+ return sizeof(folders[1][newfolder]);
+
+ return 0;
+}
+
+
+static void save_msg( mixed msg, string user )
+{
+ int newfolder;
+ object p;
+
+ GetFolders( user );
+
+ /* if folder 'unread' doesn't exist, create it */
+ newfolder = member( folders[0], "unread");
+
+ if ( newfolder == -1 ){
+ folders[0] += ({ "unread" });
+ folders[1] += ({ ({ }) });
+ newfolder = member( folders[0], "unread");
+ }
+
+ folders[1][newfolder] += ({ msg });
+ save_object( MAILPATH + user[0..0] + "/" + user );
+#ifdef NOTIFY_RECIPIENT
+ if ( p = find_player(user) )
+ tell_object( p, "Ein Postreiter ruft Dir aus einiger Entfernung zu, "
+ "dass Du neue Post hast!\n" );
+#endif
+}
+
+
+/* Remove a message from a folder */
+public int RemoveMsg( int msg, int folder, string user )
+{
+ if ( !SECURITY(previous_object()) )
+ return -2;
+
+ if ( !GetFolders(user) )
+ return -1; /* No such folder */
+
+ if ( !pointerp(folders) || !pointerp(folders[0]) ||
+ folder >= sizeof(folders[0]) )
+ return -1;
+
+ if ( msg < 0 || sizeof(folders[1][folder]) <= msg )
+ return 0; /* No such msg */
+
+ folders[1][folder][msg..msg] = ({});
+
+ save_object( MAILPATH + user[0..0] + "/" + user );
+ return 1; /* Success */
+}
+
+
+/* Move message into another folder */
+public int MoveMsg( int msg, int folder, string newfolder, string user )
+{
+ int target;
+
+ if ( !SECURITY(previous_object()) )
+ return -2;
+
+ if ( !GetFolders(user) )
+ return -1; /* Source folder not found */
+
+ if ( !pointerp(folders) || !pointerp(folders[0]) ||
+ folder >= sizeof(folders[0]) )
+ return -1;
+
+ if ( msg < 0 || sizeof(folders[1][folder]) <= msg )
+ return 0; /* No such msg */
+
+ if ( (target = member(folders[0], newfolder)) == -1 )
+ return -3;
+
+ if ( target == folder )
+ return 1;
+
+ if ( !pointerp(folders[1][target]) )
+ folders[1][target] = ({ folders[1][folder][msg] });
+ else
+ folders[1][target] += ({ folders[1][folder][msg] });
+
+ return RemoveMsg( msg, folder, user );
+}
+
+
+public int DeleteUnreadFolder( string user )
+{
+ int unread, newmail;
+
+ if ( !SECURITY(previous_object()) )
+ return -2;
+
+ if ( !GetFolders(user) )
+ return -1; /* Source folder not found */
+
+ if ( (unread = member( folders[0], "unread")) == -1 )
+ return 0;
+
+ if ( (newmail = member( folders[0], "newmail")) == -1 ){
+ folders[0] += ({ "newmail" });
+ folders[1] += ({({})});
+ newmail = sizeof(folders[1]) - 1;
+ }
+
+ if ( !pointerp(folders[1][newmail]) )
+ folders[1][newmail] = ({});
+
+ if ( pointerp(folders[1][unread]) )
+ folders[1][newmail] += folders[1][unread];
+
+ folders[0][unread..unread] = ({});
+ folders[1][unread..unread] = ({});
+
+ save_object( MAILPATH + user[0..0] + "/" + user );
+ return 0;
+}
+
+
+public int RemoveFolder( string folder, string user )
+{
+ int i;
+
+ if ( !SECURITY(previous_object()) )
+ return -2;
+
+ if ( !GetFolders(user) )
+ return -1; /* No such folder */
+
+ if ( (i = member( folders[0], folder)) == -1 )
+ return -1; /* No such folder */
+
+ if ( sizeof(folders[1][i]) > 0 )
+ return 0; /* Folder not empty */
+
+ folders[0][i..i] = ({});
+ folders[1][i..i] = ({});
+
+ save_object( MAILPATH + user[0..0] + "/" + user );
+ return 1;
+}
+
+
+public int MakeFolder( string folder, string user )
+{
+ if ( !SECURITY(previous_object()) )
+ return -2;
+
+ if ( !folder || !stringp(folder) )
+ return -1; /* Huh ? */
+
+ if ( folder == "unread" )
+ return 0; /* Folder exists virtually :) */
+
+ GetFolders( user );
+
+ if ( member( folders[0], folder) != -1 )
+ return 0; /* Folder exists */
+
+ folders[0] = folders[0] + ({ folder });
+ folders[1] = folders[1] + ({ ({}) });
+
+ save_object( MAILPATH + user[0..0] + "/" + user );
+ return 1;
+}
+
+
+public int query_recipient_ok( string name )
+{
+#if INTERNET_MAIL_ENABLED
+ return (file_size( "secure/save/" + name[0..0] + "/" + name + ".o" ) > 0
+ || member( name, '%' ) > 0 || member( name, '@' ) > 0 );
+#else
+ // es darf zwar ein @ in der Adresse vorkommen, dahinter aber kein . mehr
+ // (dann ist es ne Mail via Intermud-Mail, nicht ins Internet).
+ string *tmp;
+ return (file_size( "secure/save/" + name[0..0] + "/" + name + ".o" ) > 0
+ || member( name, '%' ) > 0
+ || (sizeof(tmp=explode(name,"@")) == 2 && strstr(tmp[1],".") == -1));
+#endif
+}
+
+
+public void deliver_mail(
+ string recipient, /* the local players real name*/
+ string from, /* A string depicting the sender */
+ string subject, /* The mail subject/header */
+ string mail_body /* The actual mail message */ )
+{
+ DEBUG( sprintf("DELIVER %O\n",
+ ({ from, from, recipient, ({}), ({}), subject, time() })) );
+
+ // Geloggt wird, wenn ein aufrufendes Objekt nicht sicher ist.
+ if (object_name(previous_object())[0..7]!="/secure/")
+ write_file("/secure/ARCH/DELIVER_MAIL",
+ sprintf("%s : Aufruf von /secure/mailer->deliver_mail()\n"
+ " Sender: %O Empfaenger: %O\n PO: %O TI: %O TP:%O\n\n",
+ ctime(time()),from, recipient,
+ previous_object(), this_interactive(), this_player()));
+
+ DeliverMail( ({ from, from, recipient, ({}), ({}), subject, time(),
+ "EXTERNAL", mail_body }), 0 );
+}