" ====================================== "; " PATCH FOR ENCORE 4.0 "; " THIS FIXES EMAIL SYNCHRONIZATION ERROR "; " AND OBSOLETE TIMESTAMP SYNTAX "; " ====================================== "; " Copyright (C) 2004, Daniel Jung "; " Last official update: 8 Jul 2004 15:05 "; " ====================================== "; " No guarantee! Back up existing verbs! "; " If you change this code, please mark "; " it clearly and notify me of the "; " changes. Input is always appreciated. "; " Don't remove copyright notice. "; " ====================================== "; " ====================================== "; " 1. Do this only once: "; " (remove quotes) "; " ====================================== "; " @prop $network.debugging_active " @prop $network.maildrop_port " @prop $network.maildrop_timeformat " @prop $time_utils.timezones_for_mail " @verb $time_utils:convert_timezone none none none rxd " @verb $network:tell_debuggers none none none rxd " ====================================== "; " 2. This is the code: "; " ====================================== "; @set $network.debugging_active to 0 @set $network.debugging to {} @set $network.maildrop_port to 25 @set $network.maildrop_timeformat to "$d, $t $n $Y $H:$M:$S $x" @set-note-text $time_utils.timezones_for_mail A => +0100 ACDT => +1030 ACST => +0930 ADT => -0300 AEDT => +1100 AEST => +1000 AKDT => -0800 AKST => -0900 AST => -0400 AWST => +0800 B => +0200 BST => +0100 C => +0300 CDT => +1030 CDT => -0500 CEST => +0200 CET => +0100 CST => +0930 CST => -0600 CXT => +0700 D => +0400 E => +0500 EDT => +1100 EDT => -0400 EEST => +0300 EET => +0200 EST => +1000 EST => -0500 F => +0600 G => +0700 GMT => +0000 H => +0800 HAA => -0300 HAC => -0500 HADT => -0900 HAE => -0400 HAP => -0700 HAR => -0600 HAST => -1000 HAT => -0230 HAY => -0800 HNA => -0400 HNC => -0600 HNE => -0500 HNP => -0800 HNR => -0700 HNT => -0330 HNY => -0900 I => +0900 IST => +0100 K => +1000 L => +1100 M => +1200 MDT => -0600 MESZ => +0200 MEZ => +0100 MST => -0700 N => -0100 NDT => -0230 NFT => +1130 NST => -0330 O => -0200 P => -0300 PDT => -0700 PST => -0800 Q => -0400 R => -0500 S => -0600 T => -0700 U => -0800 UTC => +0000 V => -0900 W => -1000 WEST => +0100 WET => +0000 WST => +0800 X => -1100 Y => -1200 Z => +0000 . @program $network:tell_debuggers " ==================================================== "; " Copyright (C) 2004, Daniel Jung. 8 Jul 2004 "; " ==================================================== "; " Let one or more persons follow what is going on when "; " sending mail. You must set both .active to 1 and "; " .debugging to one or more hearing objects (players, "; " recorders, connections) for this to work. Switch it "; " off when done. "; " ==================================================== "; if (this.debugging_active) {our_message, ?remote_message = 0} = args; debuggers = typeof(this.debugging) != LIST ? {this.debugging} | this.debugging; for d in (debuggers) d = toobj(d); d:tell(tostr(this.moo_name, "> ", our_message)); remote_message ? d:tell_lines({tostr(this.maildrop, "> ", remote_message), ""}) | 0; endfor endif . @program $network:raw_sendmail " ==================================================== "; " Makes a mailbody, opens a smtp connection, sends "; " mailheaders and body and quits. Returns remote "; " response if unsuccessfull, else 0. "; " ==================================================== "; " Changed the forked notify/read to nested ifs for "; " better synchronisation and debugging. Added "; " queue_mail if remote server is busy. Redid the "; " debugging procedure. Daniel Jung, 8 Jul 2004 "; " ==================================================== "; if (!caller_perms().wizard) return E_PERM; endif if (!this.active) return "Networking is disabled."; endif address = args[1]; body = listdelete(args, 1); " ===================== "; " === make mailbody === "; " ===================== "; blank = 0; data = {}; for b in (body) this:suspend_if_needed(0); if (!(blank || match(b, "[a-z0-9-]*: "))) if (b) data = {@data, ""}; endif blank = 1; endif data = {@data, b != "." ? b | tostr(".", b)}; endfor " ===================== "; " === open the pipe === "; " ===================== "; target = this:open(this.maildrop, toint(this.maildrop_port)); if (typeof(target) == ERR) if (task_id() != this.queued_mail_task) this:add_queued_mail(@args); return 0; else return tostr("Cannot open connection to maildrop ", this.maildrop, ", port ", this.maildrop_port, ": ", target); endif endif try remote_message = read(target); this:tell_debuggers("(upon establishing connection)", remote_message); if (index(remote_message, "220") == 1) " ===================== "; " === send protocol === "; " ===================== "; notify(target, our_message = tostr("HELO ", this.site)); remote_message = read(target); this:tell_debuggers(our_message, remote_message); if (index(remote_message, "2") == 1) notify(target, our_message = tostr("MAIL FROM: <", this.envelope_from, ">")); remote_message = read(target); this:tell_debuggers(our_message, remote_message); if (index(remote_message, "2") == 1) notify(target, our_message = tostr("RCPT TO: <", address, ">")); remote_message = read(target); this:tell_debuggers(our_message, remote_message); if (index(remote_message, "2") == 1) notify(target, "DATA"); remote_message = read(target); this:tell_debuggers("DATA", remote_message); if (index(remote_message, "354") == 1) " ===================== "; " === send the body === "; " ===================== "; for line in (data) this:suspend_if_needed(0); this:tell_debuggers(line); while (!notify(target, line, 1)) suspend(0); endwhile endfor " ======================= "; " === quit connection === "; " ======================= "; for line in ({".", "QUIT", ""}) notify(target, line); this:tell_debuggers(line); endfor " ===================== "; " === all went well === "; " ===================== "; remote_message = 0; endif elseif (index(remote_message, "4") == 1) this:add_queued_mail(@args); remote_message = 0; endif elseif (index(remote_msg, "4") == 1) this:add_queued_mail(@args); remote_message = 0; endif endif endif except error (ANY) remote_message = toliteral(error); endtry $network:close(target); return remote_message; . @program $xpress_moo_mailer:sendmail " ==================================================== "; " :sendmail(from, to, subject, line1, line2, ...) "; " sends mail to email address 'to', with given subject."; " This is a modified version of $network:sendmail to "; " allow the Xpress web mail system to send email. "; " ==================================================== "; " Changed concatenation code style, changed if-logic. "; " Changed time format (which is now retrieved from "; " property). Daniel Jung, 8 Jul 2004 "; " ==================================================== "; {user, recipient, subj, message } = {args[1], args[2], args[3], args[4..$]}; if (!caller_perms().wizard) return E_PERM; elseif (reason = $network:invalid_email_address(to = recipient)) return reason; else date = tostr("Date: ", $time_utils:time_sub($network.maildrop_timeformat)); from = tostr("From: ", $network:return_address_for(user)); toto = tostr("To: ", to); subject = tostr("Subject: ", subj); reply = tostr("Reply-to: ", user.email_address); errors = tostr("Errors-to: ", $network.errors_to_address); content = tostr("Content-Type: text/plain"); agent = tostr("X-Mail-Agent: ", $network.moo_name, " (", $encore_web_utils:baseurl(), ")"); return $network:raw_sendmail(to, date, from, toto, subject, reply, errors, content, agent, @message); endif . @program $network:sendmail " ==================================================== "; " :sendmail(to, subject, line1, line2, ...) "; " sends mail to email address 'to', with given subject."; " It fills in various fields, such as date, from "; " (from player), etc. The rest of the arguments are "; " remaining lines of the message, and may begin with "; " additional header fields. Requires $network.trust "; " to call (no anonymous mail from MOO). (must match "; " RFC822 specification). Returns 0 if successful, "; " or else error condition or string saying why not. "; " ==================================================== "; " Changed concatenation code style, changed if-logic. "; " Changed time format (which is now retrieved from "; " property). Daniel Jung, 8 Jul 2004 "; " ==================================================== "; {recipient, subj, message} = {args[1], args[2], args[3..$]}; if (!this:trust(caller_perms())) return E_PERM; elseif (reason = $network:invalid_email_address(to = recipient)) return reason; else date = tostr("Date: ", $time_utils:time_sub($network.maildrop_timeformat)); from = tostr("From: ", this:return_address_for(player)); toto = tostr("To: ", to); subject = tostr("Subject: ", subj); errors = tostr("Errors-to: ", this.errors_to_address); agent = tostr("X-Mail-Agent: ", $network.moo_name, " (", this.site, " ", this.port, ")"); return this:raw_sendmail(to, date, from, toto, subject, errors, agent, @message); endif . @program $time_utils:time_sub " ============================================================ "; " Works like pronoun substitution, but substitutes time stuff. "; " Call with time_sub(string, time). returns a string. "; " time is an optional integer in time() format. If omitted, "; " time() is used. Macros which are unknown are ignored. "; " $Q -> the empty string. Terminal $ are ignored. "; " ============================================================ "; " This verb stolen from Ozymandias's #4835:time_subst. "; " ============================================================ "; " $H -> hour (fixed) $h -> hour (not fixed) "; " $M -> min (fixed) $m -> min (not fixed) "; " $S -> second (fixed) $s -> second (not fixed) "; " $O -> num. hour (12-format) $o -> num. hour (12-format) "; " $D -> long day name $d -> short day name. "; " $N -> long month name $n -> short month name. "; " $Y -> long year ('1991') $y -> short year ('91') "; " $P -> AM/PM $p -> am/pm. "; " $T -> date number (fixed) $t -> date number (not fixed) "; " $1 -> num. month (01-12) $2 -> num.month (1-12) "; " $3 -> Date in fixed-width format, 0-fill "; " $$ -> $. "; " $Z -> the time zone (added in by r'm later) "; " ============================================================ "; " Added new time zone style +0200 etc. for email protocol. "; " Called with $x. Changed reference to player, since this can "; " be called from other places as well. Daniel Jung 8 Jul 2004. "; " ============================================================ "; res = ""; {thestr, ?thetime = time()} = args; if (typeof(thestr) != STR || typeof(thetime) != INT) return E_INVARG; endif itslength = length(thestr); if (!itslength) return ""; endif done = 0; cctime = ctime(thetime); while (dollar = index(thestr, "$")) res = res + thestr[1..dollar - 1]; if (dollar == length(thestr)) return res; endif thechar = thestr[dollar + 1]; thestr[1..dollar + 1] = ""; if (thechar == "$") res = res + "$"; elseif (!strcmp(thechar, "h")) res = res + $string_utils:trim(tostr(toint(cctime[12..13]))); elseif (thechar == "H") res = res + cctime[12..13]; elseif (!strcmp(thechar, "m")) res = res + $string_utils:trim(tostr(toint(cctime[15..16]))); elseif (thechar == "M") res = res + cctime[15..16]; elseif (!strcmp(thechar, "s")) res = res + $string_utils:trim(tostr(toint(cctime[18..19]))); elseif (thechar == "S") res = res + cctime[18..19]; elseif (!strcmp(thechar, "D")) res = res + $time_utils:day(thetime); elseif (thechar == "d") res = res + cctime[1..3]; elseif (!strcmp(thechar, "N")) res = res + $time_utils:month(thetime); elseif (thechar == "n") res = res + cctime[5..7]; elseif (!strcmp(thechar, "T")) res = res + cctime[9..10]; elseif (thechar == "t") res = res + $string_utils:trim(cctime[9..10]); elseif (thechar == "O") res = res + tostr((toint(cctime[12..13]) + 11) % 12 + 1); elseif (!strcmp(thechar, "p")) res = res + (toint(cctime[12..13]) >= 12 ? "pm" | "am"); elseif (thechar == "P") res = res + (toint(cctime[12..13]) >= 12 ? "PM" | "AM"); elseif (!strcmp(thechar, "y")) res = res + cctime[23..24]; elseif (thechar == "Y") res = res + cctime[21..24]; elseif (thechar == "Z") res = res + cctime[26..28]; elseif (thechar == "1") res = res + $string_utils:right(tostr($string_utils:explode(cctime)[2] in this.monthabbrs), 2, "0"); elseif (thechar == "2") res = res + tostr($string_utils:explode(cctime)[2] in this.monthabbrs); elseif (thechar == "3") res = res + $string_utils:subst(cctime[9..10], {{" ", "0"}}); elseif (thechar == "x") res = res + this:convert_timezone(cctime[26..$]); endif endwhile return res + thestr; . @program $time_utils:convert_timezone " ==================================================== "; " Copyright (C) 2004, Daniel Jung "; " ==================================================== "; " Take `CES' and turn it into +0200 etc. "; " Same table style retrieval as in $lang_utils. "; " ==================================================== "; {string} = args; for line in (this.timezones_for_mail) spaced = tostr(string, " "); if (spaced == line[1..length(spaced)]) return line[index(line, "=> ") + 3..$]; endif endfor return string; .