pike.git / lib / modules / Protocols.pmod / SMTP.pmod

version» Context lines:

pike.git/lib/modules/Protocols.pmod/SMTP.pmod:223:    int givedata = 1;   };      //! The low-level class for the SMTP server   class Connection {       inherit Configuration;    // The commands this module supports    array(string) commands = ({ "ehlo", "helo", "mail", "rcpt", "data",    "rset", "vrfy", "quit", "noop" }); +  // do we speak LMTP ? +  int lmtp_mode = 0;       // the fd of the socket    static object fd = Stdio.File();    // the domains for each i relay    static array(string) mydomains = ({ });    // the input buffer for read_cb    static string inputbuffer = "";    // the size of the old data string in read_cb    static int sizeofpreviousdata = 0;    // the from address
pike.git/lib/modules/Protocols.pmod/SMTP.pmod:246:    // the ident we get from ehlo/helo    static string ident = "";    // these are obvious    static string remoteaddr, localaddr;    static int localport;    // my name    static string localhost = gethostname();       // the sequence of commands the client send    static array(string) sequence = ({ }); +  // the message id of the current mail +  private string|int messageid;       // the callback functions used to guess if user is ok or not    static function cb_rcptto;    static function cb_data;    static function cb_mailfrom;       // whether you are in data mode or not...    int datamode = 0;       array(string) features = ({ "PIPELINING", "8BITMIME", "SIZE " + maxsize });    -  static void handle_timeout() +  static void handle_timeout(string cmd)    { -  catch(fd->write("421 Error: timeout exceeded\r\n")); -  close_cb(); +  string errmsg = "421 Error: timeout exceeded after command " + +  cmd || "unknown command!" + "\r\n"; +  catch(fd->write(errmsg)); +  log(errmsg); +  close_cb(1);    }       static void outcode(int code)    {    fd->write("%d %s\r\n", code, replycodes[code]);   #ifdef SMTP_DEBUG    log("%d %s\r\n", code, replycodes[code]);   #endif    }       static void log(string fmt, mixed ... args)    { -  werror("Pike SMTP server : " + fmt + "\n", args); +  string errmsg = Calendar.now()->format_time() + +  " Pike SMTP server : "; +  if(messageid) +  errmsg += messageid + ": "; +  errmsg += fmt + "\n"; +  werror(errmsg, args);    }       // make the received header -  static string received(int messageid) +  static string received()    {    string remotehost =    Protocols.DNS.client()->gethostbyaddr(remoteaddr)[0]    || remoteaddr;    string rec; -  +  string mode = lmtp_mode ? "LMTP": "ESMTP";    rec=sprintf("from %s (%s [%s]) " -  "by %s (Pike SMTP server) with %s id %d ; %s", +  "by %s (Pike %s server) with %s id %d ; %s",    ident, remotehost, remoteaddr, -  gethostname(), "ESMTP", messageid, +  gethostname(), mode, mode, messageid,    Calendar.now()->format_smtp());    return rec;    }       void helo(string argument)    {    remove_call_out(handle_timeout); -  call_out(handle_timeout, 310); +  call_out(handle_timeout, 310, "HELO");    if(sizeof(argument) > 0)    {    fd->write("250 %s\r\n", localhost);    ident = argument;   #ifdef SMTP_DEBUG    log("helo from %s", ident);   #endif    sequence += ({ "helo" });    }    else    outcode(501);    }       void ehlo(string argument)    {    remove_call_out(handle_timeout); -  call_out(handle_timeout, 310); +  call_out(handle_timeout, 310, "EHLO");    if(sizeof(argument) > 0)    {    string out = "250-" + localhost + "\r\n";    int i = 0;    for(; i < sizeof(features) - 1; i++)    {    out += "250-" + features[i] + "\r\n";    }    out += "250 " + features[i] + "\r\n";    fd->write(out);
pike.git/lib/modules/Protocols.pmod/SMTP.pmod:381:    log("relaying denied, command=%O, mydomains=%O, domain=%O\n",    what, mydomains, domain);    return 553;    }    return validating_mail;    }       void mail(string argument)    {    remove_call_out(handle_timeout); -  call_out(handle_timeout, 310); +  call_out(handle_timeout, 310, "MAIL FROM");    int sequence_ok = 0;    foreach(({ "ehlo", "helo", "lhlo" }), string needle)    {    if(has_value(sequence, needle))    sequence_ok = 1;    }    if(sequence_ok)    {    mixed email = parse_email(argument, "from");    if(intp(email))
pike.git/lib/modules/Protocols.pmod/SMTP.pmod:436:    }    }    else    outcode(503);    }       void rcpt(string argument)    {    mixed err;    remove_call_out(handle_timeout); -  call_out(handle_timeout, 310); +  call_out(handle_timeout, 310, "RCPT TO");    if(!has_value(sequence, "mail from"))    {    outcode(503);    return;    }    if(sizeof(mailto) >= maxrcpt)    {    outcode(552);    return;    }
pike.git/lib/modules/Protocols.pmod/SMTP.pmod:472:    mailto += ({ email });    sequence += ({ "rcpt to" });    }    outcode(check);    }    }       void data(string argument)    {    remove_call_out(handle_timeout); -  call_out(handle_timeout, 610); +  call_out(handle_timeout, 610, "DATA");    if(!has_value(sequence, "rcpt to"))    {    outcode(503);    return;    }    datamode = 1;    outcode(354);    }       MIME.Message format_headers(MIME.Message message)    { -  int messageid = hash(message->getdata()[..1000]) || random(100000); +  messageid = hash(message->getdata()[..1000]) || random(100000);    // first add missing headers    if(!message->headers->to)    message->headers->to = "Undisclosed-recipients";    if(!message->headers->from)    message->headers->from = mailfrom;    if(!message->headers->subject)    message->headers->subject = "";    if(!message->headers->received) -  message->headers->received = received(messageid); +  message->headers->received = received();    else -  message->headers->received = received(messageid) +  message->headers->received = received()    + "\0"+message->headers->received;    if(!message->headers["message-id"])    {    message->headers["message-id"] = sprintf("<%d@%s>", messageid,    gethostname());    }    return message;    }       void message(string content)
pike.git/lib/modules/Protocols.pmod/SMTP.pmod:531:    }    err = catch {    message = format_headers(message);    };    if(err)    {    outcode(554);    log(describe_backtrace(err));    return;    } +  // if we are in LMTP mode we call cb_data for each recipient +  // and with one recipient. This way we have one mime message per +  // recipient and one outcode to display to the client per recipient +  // (that is LMTP specific) +  if(lmtp_mode) +  { +  foreach(mailto, string recipient) +  {    int check;    if(givedata) -  +  err = catch(check = cb_data(copy_value(message), mailfrom, +  recipient, content)); +  else +  err = catch(check = cb_data(copy_value(message), mailfrom, recipient)); +  if(err || !check) +  { +  outcode(554); +  log(describe_backtrace(err)); +  continue; +  } +  outcode(check); +  } +  } +  // SMTP mode, cb_data is called one time with an array of recipients +  // and the same MIME object +  else +  { +  int check; +  if(givedata)    err = catch(check = cb_data(message, mailfrom, mailto, content));    else    err = catch(check = cb_data(message, mailfrom, mailto));    if(err || !check)    {    outcode(554);    log(describe_backtrace(err));    return;    }    outcode(check);    } -  +  }       void noop()    {    remove_call_out(handle_timeout); -  call_out(handle_timeout, 310); +  call_out(handle_timeout, 310, "NOOP");    outcode(250);    }       void rset()    {    remove_call_out(handle_timeout); -  call_out(handle_timeout, 310); +  call_out(handle_timeout, 310, "RSET");    inputbuffer = "";    mailfrom = "";    mailto = ({ }); -  +  messageid = 0;    //sequence = ({ });    outcode(250);    }       void vrfy()    {    remove_call_out(handle_timeout); -  call_out(handle_timeout, 310); +  call_out(handle_timeout, 310, "VRFY");    outcode(252);    }       void quit()    {    fd->write("221 " + replace(replycodes[221], "<host>", localhost)    + "\r\n"); -  close_cb(); +  close_cb(1);    }       static int launch_functions(string line)    {    array(string) command = line / " ";    // success    if(sizeof(command) > 0)    {    string _command = lower_case(command[0]);    mixed err = 0;
pike.git/lib/modules/Protocols.pmod/SMTP.pmod:666:    }    }       static void write_cb()    {    fd->write("220 " + replace(replycodes[220], "<host>", localhost)    + "\r\n");    fd->set_write_callback(0);    }    -  static void close_cb() +  static void close_cb(int i_close_the_stream)    { -  +  if(!i_close_the_stream) +  { +  string errmsg = "Connexion closed by client "; +  if(sequence && sizeof(sequence) > 1) +  errmsg += sequence[-1]; +  log(errmsg); +  }    catch (fd->close());    remove_call_out(handle_timeout);    }       void create(object _fd, array(string) _domains, function _cb_mailfrom,    function _cb_rcptto, function _cb_data)    {    foreach(_domains, string domain)    mydomains += ({ lower_case(domain) });    cb_mailfrom = _cb_mailfrom;    cb_rcptto = _cb_rcptto;    cb_data = _cb_data;    fd->assign(_fd);    catch(remoteaddr=((fd->query_address()||"")/" ")[0]);    catch(localaddr=((fd->query_address(1)||"")/" ")[0]);    catch(localport=(int)((fd->query_address(1)||"")/" ")[1]);    if(!remoteaddr)    {    fd->write("421 " + replace(replycodes[421], "<host>", localhost)    + "\r\n"); -  close_cb(); +  close_cb(1);    return;    }    if(!localaddr)    {    fd->write("421 " + replace(replycodes[421], "<host>", localhost)    + "\r\n"); -  close_cb(); +  close_cb(1);    return;    }    //log("connection from %s to %s:%d", remoteaddr, localaddr, localport);    fd->set_nonblocking(read_cb, write_cb, close_cb); -  call_out(handle_timeout, 300); +  call_out(handle_timeout, 300, "'First connexion'");    }      };      //! The use of Protocols.SMTP.server is quite easy and allow you   //! to design custom functions to process mail. This module does not   //! handle mail storage nor relaying to other domains.   //! So it is your job to provide mail storage and relay mails to other servers   class Server {