home *** CD-ROM | disk | FTP | other *** search
- // This file is encoded in UTF-8.
- //
- // This is generic code for talking to an email server.
- // Copyright 2003 Adobe Systems Inc.
-
-
-
- // Create an email object. The function may be called both
- // as a global function and as a constructor. It takes the
- // name of the email server, and an optional Boolean that,
- // if true, prints debugging messages.
- // This object is not guaranteed to work for all SMTP servers,
- // some of them may require a different set of commands.
-
- // functions:
- // send (fromAddress, toAddress, subject, text) - send an email
- // auth (name, pass) - do an authorization via POP3
- // both functions return false on errors
-
- // sample:
- // e = new EmailSocket ("mail.host.com");
- // authorize via POP3 (not all servers require authorization)
- // e.auth ("myname", "mypass");
- // send the email
- // e.send ("me@my.com", "you@you.com", "My Subject", "Hi there!")
-
- // This script makes use of the Socket object, and creates a new class
- // called EmailSocket that is derived from Socket. For more information on
- // creating new classes in this way, consult chapter 7 of JavaScript, The
- // Definitive Guide, by David Flanagan (O'Reilly).
- //
- // Version History:
- // V1 initial release
- // v2 - fix problems with bare linefeeds in the email that
- // caused it to be rejected by some servers. http://cr.yp.to/docs/smtplf.html
- // v3 - add support for the SMTP AUTH command. Only the LOGIN
- // protocol is supported since it looks like all servers support
- // it, while not all support PLAIN. Outlook Express 4.x and 5.x use
- // LOGIN as there AUTH protocol.
- // Also fix bug where EHLO sent a syntactically incorrect argument
-
- //This is the constructor for the email socket. It takes as arguments:
- //server - the address of the email server (is not checked for validity here)
- //dbg - a boolean, if true, prints additional error information
-
- function EmailSocket (server, dbg) {
- var obj = new Socket;
- obj._host = server;
- obj._debug = (dbg == true);
- obj.__proto__ = EmailSocket.prototype;
- return obj;
- }
-
- // correct the protoype chain to point to the Socket prototype chain
- // - this is what actually causes the derivation from Socket.
-
- EmailSocket.prototype.__proto__ = Socket.prototype;
-
- // This sets up the send() member function. send() takes as arguments:
- // from - the email address of the sender. This is not validated.
- // to - the email address of the recipient. If there is an error,
- // and the from address is incorrect, you will not be notified.
- // subject - the contents of the subject field.
- // text - the body of the message.
- // auth_user - OPTIONAL the username of the account to authorize with the smtp server
- // auth_password - OPTIONAL - the already base64 encoded password
- //
- // Returns:
- // true if sending succeeded
- // THROWS AN ERROR STRING if the function fails.
- //
- //
- // Note that this code uses a local function object to create
- // the function that is assigned to send.
-
- EmailSocket.prototype.send = function (from, to, subject, text, auth_user, auth_password) {
- // open the socket on port 25 (SMTP)
- // right now this is binary because otherwise the CRLF got reinterpreted and
- // my server would not accept it. We will need changes to the socket object
- // to fix correctly.
- if (!this.open (this._host + ":25", "binary"))
- return false;
- try {
- // discard the greeting
- var greeting = this.read();
- if (this._debug)
- write ("RECV: " + greeting);
-
- // issue EHLO and other commands
- // one user is having aproblem with the full email as the @ sign is illegal
- // we should use the ip of the client http://cr.yp.to/smtp/helo.html#helo
- // but we can't get that with the socket object. therefore we are using
- // the host portion of the reply to email address.
- var client_only = from.split("@")[1];
-
- this._SMTP ("EHLO " + client_only);
- var response = this.read();
-
- if (auth_user) {
- // now send the auth stuff
- this._SMTP("AUTH LOGIN");
- this._SMTP(this._ENCODE_BASE_64(auth_user));
- this._SMTP(auth_password);
- }
-
- this._SMTP ("MAIL FROM: " + from);
- this._SMTP ("RCPT TO: " + to);
- this._SMTP ("DATA");
- // send subject and time stamp
- this.writecrlfln ("From: " + from);
- this.writecrlfln ("To: " + to);
- this.writecrlfln ("Date: " + new Date().toString());
- if (typeof subject != undefined)
- this.writecrlfln ("Subject: " + subject);
- this.writecrlfln();
- // send the text
- if (typeof text != undefined)
- this.writecrlfln (text);
- // terminate with a single dot and wait for response
- this._SMTP (".");
- // terminate the session
- this._SMTP ("QUIT");
- this.close();
- return true;
- }
- catch (e) {
- this.close();
- throw e;
- }
- }
-
- // Authorize via POP3. Supply name and password.
- //
- // Returns:
- // true if sending succeeded
- // false otherwise (if there was an error)
- //
- // Arguments:
- // name - the userName of the account
- // pass - the password
-
- EmailSocket.prototype.auth = function (name, pass) {
- // open the connection on port 110 (POP3)
- if (!this.open (this._host + ":110"))
- return false;
- try {
- // discard the greeting
- var greeting = this.read();
- if (this._debug)
- write ("RECV: " + greeting);
- // issue POP3 commands
- this._POP3 ("USER " + name);
- this._POP3 ("PASS " + pass);
- this._POP3 ("QUIT");
- this.close();
- return true;
- }
- catch (e) {
- this.close();
- return false;
- }
- }
-
- // Users of the EmailSocket do not need to be concerned with
- // the following method. It is an implementation helper.
-
- // local function to send a command & check a POP3 reply
- // throws in case of error
- EmailSocket.prototype._POP3 = function (cmd) {
- if (this._debug)
- writeLn ("SEND: " + cmd);
- if (!this.writecrlfln (cmd))
- throw "Error";
- var reply = this.read();
- if (this._debug)
- write ("RECV: " + reply);
- // the reply starts by either + or -
- if (reply [0] == "+")
- return;
- throw "Error";
- }
-
- // Users of the EmailSocket do not need to be concerned with
- // the following method. It is an implementation helper.
-
- // local function to send a command & check a SMTP reply
- // throws in case of error
- EmailSocket.prototype._SMTP = function (cmd) {
- if (this._debug)
- writeLn ("SEND: " + cmd);
- if (!this.writecrlfln (cmd))
- throw "Error";
- var reply = this.read();
- if (this._debug)
- write ("RECV: " + reply);
- // the reply is a three-digit code followed by a space
- var match = reply.match (/^(\d{3})\s/m);
- if (match.length == 2) {
- var n = Number (match [1]);
- if (n >= 200 && n <= 399)
- return;
- }
- throw reply;
- }
-
- // email can't contain bare linefeeds: http://cr.yp.to/docs/smtplf.html
- EmailSocket.prototype.writecrlfln = function (cmd) {
- if (cmd) {
- return this.write(cmd + "\r\n");
- } else {
- return this.write("\r\n");
- }
- }
-
-
-
- // This base64 encodes str. RFC-2045
- EmailSocket.prototype._ENCODE_BASE_64 = function(str)
- {
- var lut = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
- var chunk = 0;
-
- var result = "";
-
- for( var i = 0; i < str.length; i += 3) {
- chunk = str.charCodeAt(i) & 0xFF;
- chunk = chunk << 8;
-
- // asking for a char out of range returns ""
- chunk |= str.charCodeAt(i+1) & 0xFF;
- chunk = chunk << 8;
-
- chunk |= str.charCodeAt(i+2) & 0xFF;
-
- // these are the number of gaps until we hit %3
- var partialEnd = 3 - (str.length - i) ;
-
- var num6bits = 4;
- //
- if (partialEnd == 2) { // one character encoded
- num6bits = 2;
- } else if (partialEnd == 1) { // two encoded
- num6bits = 3;
- }
-
- for( var j = 0; j < num6bits; j++){
- result += lut.charAt((chunk & 0xFC0000) >> 18); // six bits
- chunk = chunk << 6;
- }
-
- // fill with = chars
- if (partialEnd < 3) {
- for( var j = 0; j < partialEnd; j++){
- result += "=";
- }
- }
- }
-
- return result;
- }
-
- // nice to have: a toString()
- // This function allows the email object to be printed.
-
- EmailSocket.prototype.toString = function() {
- return "[object Email]";
- }
-
-