new object $smtp_interface: $connection_interface, $has_name; var $has_commands local = #[]; var $has_commands remote = #[]; var $has_commands shortcuts = #[]; var $has_name name = ['prop, "smtp_interface", "smtp_interface"]; var $root created_on = 849172060; var $root flags = ['variables, 'methods, 'code, 'core]; var $root inited = 1; var $root managed = [$smtp_interface]; var $root manager = $smtp_interface; var $root quota_exempt = 1; var $smtp_interface cmd_help = #[["HELP", ["HELP [<topic>]", " For more help on any command type 'help <cmd>'"]], ["QUIT", ["QUIT", " Ends your mail session"]], ["EXPN", ["EXPN <recipient>", " Expand an address."]], ["VRFY", ["VRFY <recipient>", " Verify an address."]], ["HELO", ["HELO <hostname>", " Introduce yourself."]], ["MAIL", ["MAIL FROM: <sender>", " Specify sender/return path."]], ["NOOP", ["NOOP", " Do nothing"]], ["RCPT", ["RCPT TO:<recipient>", " Specifies the recipient. Can be used any number of times."]], ["DATA", ["DATA", " Following data is collected as the message", " End with a single dot"]]]; var $smtp_interface cmds = #[["HELP", 'help_cmd], ["QUIT", 'quit_cmd], ["VRFY", 'verify_cmd], ["EXPN", 'verify_cmd], ["HELO", 'hello_cmd], ["MAIL", 'mail_from_cmd], ["NOOP", 'noop_cmd], ["RCPT", 'recipient_cmd], ["DATA", 'data_cmd]]; var $smtp_interface given_hostname = ""; var $smtp_interface header = 0; var $smtp_interface mail_body = 0; var $smtp_interface mail_from = 0; var $smtp_interface mail_status = 0; var $smtp_interface mail_to = 0; var $smtp_interface read_header = 0; public method .connection_starting() { arg addr, port; (.connection()).write((("220 " + ($sys.server_info('server_hostname))) + " SMTP ColdMail 1.0/1.0; ") + ($time.format("%a, %d %b %Y %T %Z"))); }; public method .data_cmd() { arg rest; var conn; conn = .connection(); if (mail_from == "") { conn.write("503 Need MAIL command"); } else if (mail_to == []) { conn.write("503 Need RCPT command"); } else { conn.write("354 Enter mail, end with \".\" on a line by itself"); mail_status = 'read_body; } }; public method .get_cmd() { arg cmd; return (> cmds[cmd] <); }; public method .get_cmd_help() { arg help; return (> cmd_help[help] <); }; public method .get_cmds() { return cmds.keys(); }; public method .hello_cmd() { arg rest; var conn; conn = .connection(); if ((rest.length()) == 0) { conn.write("501 HELO requires domain address"); } else if (given_hostname == 0) { conn.write(((("250 " + ($sys.server_info('server_hostname))) + " Hello ") + (conn.address())) + ", pleased to meet you"); given_hostname = rest; } else { conn.write("503 portland.puremagic.com Duplicate HELO"); } }; public method .help_cmd() { arg rest; var i, conn; conn = .connection(); if ((rest.length()) == 0) { conn.write(["214-This is ColdMail 0.01.", "214-Valid Commands:"]); for i in (definer().get_cmds()) conn.write("214- " + i); conn.write("214 End of Help"); } else { catch ~keynf { rest = definer().get_cmd_help(rest); for i in (rest) conn.write("214-" + i); conn.write("214 End of Help"); } with { conn.write(("504 HELP topic '" + rest) + "' not found."); } } }; public method .init_smtp_interface() { .reset_interface(); mail_status = 'idle; }; public method .mail_from_cmd() { arg rest; var conn, i; conn = .connection(); if (((rest.length()) <= 5) || (((i = ":" in rest) != 5) || ((| rest.subrange(1, 5) |) != "from:"))) { conn.write(("501 Syntax error in \"" + (rest.subrange(1, (i == 0) ? (rest.length()) : (i - 1)))) + "\""); } else if (mail_from != "") { conn.write("503 Sender already specified"); } else { .reset_interface(); mail_from = (rest.subrange(6)).trim(); conn.write(("250 " + mail_from) + "... sender ok"); } }; public method .noop_cmd() { arg rest; (.connection()).write("250 Ok"); }; public method .parse_line() { arg line; var method, cmd, args, name, rest, m, last; if (mail_status == 'read_body) { if (line == ".") { return .send_mail(); } else { if (read_header) { mail_body += [line]; } else if (!line) { read_header = 1; } else if ((m = regexp(line, "^([^ ][^:]+) *: *(.*)$"))) { header += [m]; } else if (header) { last = header[listlen(header)]; header = sublist(header, 1, listlen(header)); last = replace(last, 2, (last[2]) + line); header += [last]; } return; } } cmd = line.word(1); if ((line.length()) >= ((cmd.length()) + 2)) args = line.subrange((cmd.length()) + 2); else args = ""; catch ~keynf { method = definer().get_cmd(cmd); } with { (.connection()).write("500 unrecognized command"); return 'disconenct; } return .(method)(args); }; public method .quit_cmd() { arg rest; (.connection()).write(("221 " + ($sys.server_info('server_hostname))) + " closing connection"); return 'disconnect; }; public method .recipient_cmd() { arg rest; var conn, i, user; conn = .connection(); if (mail_from == "") { conn.write("503 Need MAIL before RCPT"); } else if (((rest.length()) <= 3) || (((i = ":" in rest) != 3) || ((| rest.subrange(1, 3) |) != "to:"))) { conn.write(("501 Syntax error in \"" + (rest.subrange(1, (i == 0) ? (rest.length()) : (i - 1)))) + "\""); } else { catch any { user = $smtp.parse_recipient(rest.subrange(4)); mail_to += [user]; conn.write(("250 " + user) + "... recipient ok"); } with { if (error() == ~ambig) conn.write("553 Ambiguous Recipient"); else conn.write(((((traceback()[1])[3]) || 550) + " ") + ((traceback()[1])[2])); } } }; public method .reset_interface() { header = []; read_header = 0; mail_from = ""; mail_to = []; mail_body = []; }; public method .send_mail() { var mail, l, subj; .set_name(mail_from, 'prop); mail = $mail_message.new_mail(); subj = "<NO SUBJECT>"; for l in (header) { if ((l[1]) == "Subject") subj = l[2]; } mail.set_subject(subj); mail.set_text(mail_body); catch any { mail.set_meta(header); mail.send(@mail_to); mail.set_from(mail_from); (.connection()).write(("250 " + ($smtp_daemon.get_msg_id())) + " Message accepted for delivery"); } with { (.connection()).write("550 Requested action not taken: Error delivering mail"); } .reset_interface(); }; public method .uninit_smtp_interface() { header = 0; read_header = 0; mail_from = 0; mail_to = 0; mail_body = 0; mail_status = 0; }; public method .verify_cmd() { arg rest; var conn, user, i, out; conn = .connection(); if ((rest.length()) == 0) { conn.write("501 Argument required"); } else { if (!($smtp.allowed('VRFY))) { conn.write("252 VRFY not allowed"); return; } out = []; for i in (rest.explode()) { catch any { out = setadd(out, $smtp.parse_recipient(i)); } with { switch (error()) { case ~ambig: conn.write("553 Ambiguous Recipient"); default: conn.write(((((traceback()[1])[3]) || 550) + " ") + ((traceback()[1])[2])); return; } } } for i in [1 .. (out.length()) - 1] conn.write("250-" + ($smtp.format_email_address(out[i]))); if (out) conn.write("250 " + ($smtp.format_email_address(out.last()))); } };