a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
bb02cc1997-09-15Fredrik Hübinette (Hubbe) class protocol { // Maybe this should be the other way around?
5946a21998-04-29Fredrik Noring  inherit .NNTP.protocol;
bb02cc1997-09-15Fredrik Hübinette (Hubbe) }
dba8dd2001-11-08Martin Nilsson //!
bb02cc1997-09-15Fredrik Hübinette (Hubbe) class client { inherit protocol;
dba8dd2001-11-08Martin Nilsson  //! A mapping(int:string) that maps SMTP return //! codes to english textual messages.
cc1c0e1998-03-07Fredrik Noring  constant reply_codes = ([ 211:"System status, or system help reply", 214:"Help message", 220:"<host> Service ready", 221:"<host> Service closing transmission channel", 250:"Requested mail action okay, completed", 251:"User not local; will forward to <forward-path>", 354:"Start mail input; end with <CRLF>.<CRLF>", 421:"<host> Service not available, closing transmission channel " "[This may be a reply to any command if the service knows it " "must shut down]", 450:"Requested mail action not taken: mailbox unavailable " "[E.g., mailbox busy]", 451:"Requested action aborted: local error in processing", 452:"Requested action not taken: insufficient system storage", 500:"Syntax error, command unrecognized " "[This may include errors such as command line too long]", 501:"Syntax error in parameters or arguments", 502:"Command not implemented", 503:"Bad sequence of commands", 504:"Command parameter not implemented", 550:"Requested action not taken: mailbox unavailable " "[E.g., mailbox not found, no access]", 551:"User not local; please try <forward-path>", 552:"Requested mail action aborted: exceeded storage allocation", 553:"Requested action not taken: mailbox name not allowed "
145b242001-11-14Henrik Grubbström (Grubba)  "[E.g., mailbox syntax incorrect or relaying denied]",
cc1c0e1998-03-07Fredrik Noring  554:"Transaction failed" ]); static private int cmd(string c, string|void comment) { int r = command(c); switch(r) { case 200..399: break; default:
484a742002-03-09Martin Nilsson  error( "SMTP: "+c+"\n"+(comment?"SMTP: "+comment+"\n":"")+ "SMTP: "+reply_codes[r]+"\n" );
cc1c0e1998-03-07Fredrik Noring  } return r; }
dba8dd2001-11-08Martin Nilsson  //! @decl void create() //! @decl void create(Stdio.File server) //! @decl void create(string server, void|int port) //! Creates an SMTP mail client and connects it to the //! the @[server] provided. The server parameter may //! either be a string witht the hostnam of the mail server, //! or it may be a file object acting as a mail server. //! If @[server] is a string, than an optional port parameter //! may be provided. If no port parameter is provided, port //! 25 is assumed. If no parameters at all is provided //! the client will look up the mail host by searching //! for the DNS MX record. //! //! @throws //! Throws an exception if the client fails to connect to //! the mail server.
799d092001-07-18Mirar (Pontus Hagland)  void create(void|string|Stdio.File server, int|void port)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  { if(!server) { // Lookup MX record here (Using DNS.pmod) object dns=master()->resolv("Protocols")["DNS"]->client(); server=dns->get_primary_mx(gethostname()); }
799d092001-07-18Mirar (Pontus Hagland)  if (objectp(server)) assign(server); else
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
799d092001-07-18Mirar (Pontus Hagland)  if(!port) port = 25; if(!server || !connect(server, port)) {
484a742002-03-09Martin Nilsson  error("Failed to connect to mail server.\n");
799d092001-07-18Mirar (Pontus Hagland)  }
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  } if(readreturncode()/100 != 2)
484a742002-03-09Martin Nilsson  error("Connection refused by SMTP server.\n");
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
cc1c0e1998-03-07Fredrik Noring  if(catch(cmd("EHLO "+gethostname()))) cmd("HELO "+gethostname(), "greeting failed."); }
dba8dd2001-11-08Martin Nilsson  //! Sends a mail message from @[from] to the mail addresses //! listed in @[to] with the mail body @[body]. The body //! should be a correctly formatted mail DATA block, e.g. //! produced by @[MIME.Message]. //! //! @seealso //! @[simple_mail] //! //! @throws //! If the mail server returns any other return code than //! 200-399 an exception will be thrown.
6b0af52000-02-18Martin Nilsson  void send_message(string from, array(string) to, string body)
cc1c0e1998-03-07Fredrik Noring  {
76cd3d1999-06-29Henrik Grubbström (Grubba)  cmd("MAIL FROM: <" + from + ">"); foreach(to, string t) { cmd("RCPT TO: <" + t + ">"); }
cc1c0e1998-03-07Fredrik Noring  cmd("DATA");
27990a2001-12-06Henrik Grubbström (Grubba)  // Perform quoting according to RFC 2821 4.5.2. if (sizeof(body) && body[0] == '.') { body = "." + body; } body = replace(body, "\r\n.", "\r\n..");
2d77972001-12-06Henrik Grubbström (Grubba)  // RFC 2821
27990a2001-12-06Henrik Grubbström (Grubba)  // An extra <CRLF> MUST NOT be added, as that would cause an empty // line to be added to the message. if (has_suffix(body, "\r\n")) { body += "."; } else { body += "\r\n."; } cmd(body);
cc1c0e1998-03-07Fredrik Noring  cmd("QUIT");
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
76cd3d1999-06-29Henrik Grubbström (Grubba)  static string parse_addr(string addr) {
8cd5331999-07-07Fredrik Hübinette (Hubbe)  array(string|int) tokens = replace(MIME.tokenize(addr), '@', "@");
76cd3d1999-06-29Henrik Grubbström (Grubba)  int i; tokens = tokens[search(tokens, '<') + 1..]; if ((i = search(tokens, '>')) != -1) { tokens = tokens[..i-1]; } return tokens*""; }
dba8dd2001-11-08Martin Nilsson  //! Sends an e-mail. Wrapper function that uses @[send_message]. //!
5c1d3e2002-09-06Honza Petrous  //! @note //! Some important headers are set to:
cbe8c92003-04-07Martin Nilsson  //! @expr{"Content-Type: text/plain; charset=iso-8859-1"@} and //! @expr{"Content-Transfer-Encoding: 8bit"@}. @expr{"Date:"@} //! header isn't used at all.
5c1d3e2002-09-06Honza Petrous  //!
dba8dd2001-11-08Martin Nilsson  //! @throws //! If the mail server returns any other return code than //! 200-399 an exception will be thrown.
cc1c0e1998-03-07Fredrik Noring  void simple_mail(string to, string subject, string from, string msg)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
fca5372000-10-03Mirar (Pontus Hagland)  if (search(msg,"\r\n")==-1) msg=replace(msg,"\n","\r\n"); // *simple* mail /Mirar
76cd3d1999-06-29Henrik Grubbström (Grubba)  send_message(parse_addr(from), ({ parse_addr(to) }),
baa6a61998-05-12Marcus Comstedt  (string)MIME.Message(msg, (["mime-version":"1.0", "subject":subject, "from":from, "to":to, "content-type": "text/plain;charset=iso-8859-1", "content-transfer-encoding": "8bit"])));
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
1d1ac72000-05-18Mirar (Pontus Hagland) 
dba8dd2001-11-08Martin Nilsson  //! Verifies the mail address @[addr] against the mail server. //! //! @returns //! @array //! @elem int code //! The numerical return code from the VRFY call. //! @elem string message //! The textual answer to the VRFY call. //! @endarray //! //! @note //! Some mail servers does not answer truthfully to //! verfification queries in order to prevent spammers //! and others to gain information about the mail //! addresses present on the mail server. //! //! @throws //! If the mail server returns any other return code than //! 200-399 an exception will be thrown.
1d1ac72000-05-18Mirar (Pontus Hagland)  array(int|string) verify(string addr) { return ({command("VRFY "+addr),rest}); }
bb02cc1997-09-15Fredrik Hübinette (Hubbe) }