wp/wp-includes/class-smtp.php
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     1 <?php
       
     2 /*~ class.smtp.php
       
     3 .---------------------------------------------------------------------------.
       
     4 |  Software: PHPMailer - PHP email class                                    |
       
     5 |   Version: 5.2.4                                                          |
       
     6 |      Site: https://code.google.com/a/apache-extras.org/p/phpmailer/       |
       
     7 | ------------------------------------------------------------------------- |
       
     8 |     Admin: Jim Jagielski (project admininistrator)                        |
       
     9 |   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
       
    10 |          : Marcus Bointon (coolbru) coolbru@users.sourceforge.net         |
       
    11 |          : Jim Jagielski (jimjag) jimjag@gmail.com                        |
       
    12 |   Founder: Brent R. Matzelle (original founder)                           |
       
    13 | Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved.              |
       
    14 | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |
       
    15 | Copyright (c) 2001-2003, Brent R. Matzelle                                |
       
    16 | ------------------------------------------------------------------------- |
       
    17 |   License: Distributed under the Lesser General Public License (LGPL)     |
       
    18 |            http://www.gnu.org/copyleft/lesser.html                        |
       
    19 | This program is distributed in the hope that it will be useful - WITHOUT  |
       
    20 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
       
    21 | FITNESS FOR A PARTICULAR PURPOSE.                                         |
       
    22 '---------------------------------------------------------------------------'
       
    23 */
       
    24 
       
    25 /**
       
    26  * PHPMailer - PHP SMTP email transport class
       
    27  * NOTE: Designed for use with PHP version 5 and up
       
    28  * @package PHPMailer
       
    29  * @author Andy Prevost
       
    30  * @author Marcus Bointon
       
    31  * @copyright 2004 - 2008 Andy Prevost
       
    32  * @author Jim Jagielski
       
    33  * @copyright 2010 - 2012 Jim Jagielski
       
    34  * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
       
    35  */
       
    36 
       
    37 /**
       
    38  * PHP RFC821 SMTP client
       
    39  *
       
    40  * Implements all the RFC 821 SMTP commands except TURN which will always return a not implemented error.
       
    41  * SMTP also provides some utility methods for sending mail to an SMTP server.
       
    42  * @author Chris Ryan
       
    43  * @package PHPMailer
       
    44  */
       
    45 
       
    46 class SMTP {
       
    47   /**
       
    48    *  SMTP server port
       
    49    *  @var int
       
    50    */
       
    51   public $SMTP_PORT = 25;
       
    52 
       
    53   /**
       
    54    *  SMTP reply line ending (don't change)
       
    55    *  @var string
       
    56    */
       
    57   public $CRLF = "\r\n";
       
    58 
       
    59   /**
       
    60    *  Sets whether debugging is turned on
       
    61    *  @var bool
       
    62    */
       
    63   public $do_debug;       // the level of debug to perform
       
    64 
       
    65   /**
       
    66    * Sets the function/method to use for debugging output.
       
    67    * Right now we only honor "echo" or "error_log"
       
    68    * @var string
       
    69    */
       
    70   public $Debugoutput     = "echo";
       
    71 
       
    72   /**
       
    73    *  Sets VERP use on/off (default is off)
       
    74    *  @var bool
       
    75    */
       
    76   public $do_verp = false;
       
    77 
       
    78   /**
       
    79    * Sets the SMTP timeout value for reads, in seconds
       
    80    * @var int
       
    81    */
       
    82   public $Timeout         = 15;
       
    83 
       
    84   /**
       
    85    * Sets the SMTP timelimit value for reads, in seconds
       
    86    * @var int
       
    87    */
       
    88   public $Timelimit       = 30;
       
    89 
       
    90   /**
       
    91    * Sets the SMTP PHPMailer Version number
       
    92    * @var string
       
    93    */
       
    94   public $Version         = '5.2.4';
       
    95 
       
    96   /////////////////////////////////////////////////
       
    97   // PROPERTIES, PRIVATE AND PROTECTED
       
    98   /////////////////////////////////////////////////
       
    99 
       
   100   /**
       
   101    * @var resource The socket to the server
       
   102    */
       
   103   private $smtp_conn;
       
   104   /**
       
   105    * @var string Error message, if any, for the last call
       
   106    */
       
   107   private $error;
       
   108   /**
       
   109    * @var string The reply the server sent to us for HELO
       
   110    */
       
   111   private $helo_rply;
       
   112 
       
   113   /**
       
   114    * Outputs debugging info via user-defined method
       
   115    * @param string $str
       
   116    */
       
   117   private function edebug($str) {
       
   118     if ($this->Debugoutput == "error_log") {
       
   119         error_log($str);
       
   120     } else {
       
   121         echo $str;
       
   122     }
       
   123   }
       
   124 
       
   125   /**
       
   126    * Initialize the class so that the data is in a known state.
       
   127    * @access public
       
   128    * @return SMTP
       
   129    */
       
   130   public function __construct() {
       
   131     $this->smtp_conn = 0;
       
   132     $this->error = null;
       
   133     $this->helo_rply = null;
       
   134 
       
   135     $this->do_debug = 0;
       
   136   }
       
   137 
       
   138   /////////////////////////////////////////////////
       
   139   // CONNECTION FUNCTIONS
       
   140   /////////////////////////////////////////////////
       
   141 
       
   142   /**
       
   143    * Connect to the server specified on the port specified.
       
   144    * If the port is not specified use the default SMTP_PORT.
       
   145    * If tval is specified then a connection will try and be
       
   146    * established with the server for that number of seconds.
       
   147    * If tval is not specified the default is 30 seconds to
       
   148    * try on the connection.
       
   149    *
       
   150    * SMTP CODE SUCCESS: 220
       
   151    * SMTP CODE FAILURE: 421
       
   152    * @access public
       
   153    * @param string $host
       
   154    * @param int $port
       
   155    * @param int $tval
       
   156    * @return bool
       
   157    */
       
   158   public function Connect($host, $port = 0, $tval = 30) {
       
   159     // set the error val to null so there is no confusion
       
   160     $this->error = null;
       
   161 
       
   162     // make sure we are __not__ connected
       
   163     if($this->connected()) {
       
   164       // already connected, generate error
       
   165       $this->error = array("error" => "Already connected to a server");
       
   166       return false;
       
   167     }
       
   168 
       
   169     if(empty($port)) {
       
   170       $port = $this->SMTP_PORT;
       
   171     }
       
   172 
       
   173     // connect to the smtp server
       
   174     $this->smtp_conn = @fsockopen($host,    // the host of the server
       
   175                                  $port,    // the port to use
       
   176                                  $errno,   // error number if any
       
   177                                  $errstr,  // error message if any
       
   178                                  $tval);   // give up after ? secs
       
   179     // verify we connected properly
       
   180     if(empty($this->smtp_conn)) {
       
   181       $this->error = array("error" => "Failed to connect to server",
       
   182                            "errno" => $errno,
       
   183                            "errstr" => $errstr);
       
   184       if($this->do_debug >= 1) {
       
   185         $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />');
       
   186       }
       
   187       return false;
       
   188     }
       
   189 
       
   190     // SMTP server can take longer to respond, give longer timeout for first read
       
   191     // Windows does not have support for this timeout function
       
   192     if(substr(PHP_OS, 0, 3) != "WIN") {
       
   193      $max = ini_get('max_execution_time');
       
   194      if ($max != 0 && $tval > $max) { // don't bother if unlimited
       
   195       @set_time_limit($tval);
       
   196      }
       
   197      stream_set_timeout($this->smtp_conn, $tval, 0);
       
   198     }
       
   199 
       
   200     // get any announcement
       
   201     $announce = $this->get_lines();
       
   202 
       
   203     if($this->do_debug >= 2) {
       
   204       $this->edebug("SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />');
       
   205     }
       
   206 
       
   207     return true;
       
   208   }
       
   209 
       
   210   /**
       
   211    * Initiate a TLS communication with the server.
       
   212    *
       
   213    * SMTP CODE 220 Ready to start TLS
       
   214    * SMTP CODE 501 Syntax error (no parameters allowed)
       
   215    * SMTP CODE 454 TLS not available due to temporary reason
       
   216    * @access public
       
   217    * @return bool success
       
   218    */
       
   219   public function StartTLS() {
       
   220     $this->error = null; # to avoid confusion
       
   221 
       
   222     if(!$this->connected()) {
       
   223       $this->error = array("error" => "Called StartTLS() without being connected");
       
   224       return false;
       
   225     }
       
   226 
       
   227     fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
       
   228 
       
   229     $rply = $this->get_lines();
       
   230     $code = substr($rply,0,3);
       
   231 
       
   232     if($this->do_debug >= 2) {
       
   233       $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
       
   234     }
       
   235 
       
   236     if($code != 220) {
       
   237       $this->error =
       
   238          array("error"     => "STARTTLS not accepted from server",
       
   239                "smtp_code" => $code,
       
   240                "smtp_msg"  => substr($rply,4));
       
   241       if($this->do_debug >= 1) {
       
   242         $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   243       }
       
   244       return false;
       
   245     }
       
   246 
       
   247     // Begin encrypted connection
       
   248     if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
       
   249       return false;
       
   250     }
       
   251 
       
   252     return true;
       
   253   }
       
   254 
       
   255   /**
       
   256    * Performs SMTP authentication.  Must be run after running the
       
   257    * Hello() method.  Returns true if successfully authenticated.
       
   258    * @access public
       
   259    * @param string $username
       
   260    * @param string $password
       
   261    * @param string $authtype
       
   262    * @param string $realm
       
   263    * @param string $workstation
       
   264    * @return bool
       
   265    */
       
   266   public function Authenticate($username, $password, $authtype='LOGIN', $realm='', $workstation='') {
       
   267     if (empty($authtype)) {
       
   268       $authtype = 'LOGIN';
       
   269     }
       
   270 
       
   271     switch ($authtype) {
       
   272       case 'PLAIN':
       
   273         // Start authentication
       
   274         fputs($this->smtp_conn,"AUTH PLAIN" . $this->CRLF);
       
   275     
       
   276         $rply = $this->get_lines();
       
   277         $code = substr($rply,0,3);
       
   278     
       
   279         if($code != 334) {
       
   280           $this->error =
       
   281             array("error" => "AUTH not accepted from server",
       
   282                   "smtp_code" => $code,
       
   283                   "smtp_msg" => substr($rply,4));
       
   284           if($this->do_debug >= 1) {
       
   285             $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   286           }
       
   287           return false;
       
   288         }
       
   289         // Send encoded username and password
       
   290         fputs($this->smtp_conn, base64_encode("\0".$username."\0".$password) . $this->CRLF);
       
   291 
       
   292         $rply = $this->get_lines();
       
   293         $code = substr($rply,0,3);
       
   294     
       
   295         if($code != 235) {
       
   296           $this->error =
       
   297             array("error" => "Authentication not accepted from server",
       
   298                   "smtp_code" => $code,
       
   299                   "smtp_msg" => substr($rply,4));
       
   300           if($this->do_debug >= 1) {
       
   301             $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   302           }
       
   303           return false;
       
   304         }
       
   305         break;
       
   306       case 'LOGIN':
       
   307         // Start authentication
       
   308         fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
       
   309     
       
   310         $rply = $this->get_lines();
       
   311         $code = substr($rply,0,3);
       
   312     
       
   313         if($code != 334) {
       
   314           $this->error =
       
   315             array("error" => "AUTH not accepted from server",
       
   316                   "smtp_code" => $code,
       
   317                   "smtp_msg" => substr($rply,4));
       
   318           if($this->do_debug >= 1) {
       
   319             $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   320           }
       
   321           return false;
       
   322         }
       
   323     
       
   324         // Send encoded username
       
   325         fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
       
   326     
       
   327         $rply = $this->get_lines();
       
   328         $code = substr($rply,0,3);
       
   329     
       
   330         if($code != 334) {
       
   331           $this->error =
       
   332             array("error" => "Username not accepted from server",
       
   333                   "smtp_code" => $code,
       
   334                   "smtp_msg" => substr($rply,4));
       
   335           if($this->do_debug >= 1) {
       
   336             $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   337           }
       
   338           return false;
       
   339         }
       
   340     
       
   341         // Send encoded password
       
   342         fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
       
   343     
       
   344         $rply = $this->get_lines();
       
   345         $code = substr($rply,0,3);
       
   346     
       
   347         if($code != 235) {
       
   348           $this->error =
       
   349             array("error" => "Password not accepted from server",
       
   350                   "smtp_code" => $code,
       
   351                   "smtp_msg" => substr($rply,4));
       
   352           if($this->do_debug >= 1) {
       
   353             $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   354           }
       
   355           return false;
       
   356         }
       
   357         break;
       
   358       case 'NTLM':
       
   359         /*
       
   360          * ntlm_sasl_client.php
       
   361          ** Bundled with Permission
       
   362          **
       
   363          ** How to telnet in windows: http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
       
   364          ** PROTOCOL Documentation http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
       
   365          */
       
   366         require_once('ntlm_sasl_client.php');
       
   367         $temp = new stdClass();
       
   368         $ntlm_client = new ntlm_sasl_client_class;
       
   369         if(! $ntlm_client->Initialize($temp)){//let's test if every function its available
       
   370             $this->error = array("error" => $temp->error);
       
   371             if($this->do_debug >= 1) {
       
   372                 $this->edebug("You need to enable some modules in your php.ini file: " . $this->error["error"] . $this->CRLF);
       
   373             }
       
   374             return false;
       
   375         }
       
   376         $msg1 = $ntlm_client->TypeMsg1($realm, $workstation);//msg1
       
   377         
       
   378         fputs($this->smtp_conn,"AUTH NTLM " . base64_encode($msg1) . $this->CRLF);
       
   379 
       
   380         $rply = $this->get_lines();
       
   381         $code = substr($rply,0,3);
       
   382         
       
   383 
       
   384         if($code != 334) {
       
   385             $this->error =
       
   386                 array("error" => "AUTH not accepted from server",
       
   387                       "smtp_code" => $code,
       
   388                       "smtp_msg" => substr($rply,4));
       
   389             if($this->do_debug >= 1) {
       
   390                 $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF);
       
   391             }
       
   392             return false;
       
   393         }
       
   394         
       
   395         $challange = substr($rply,3);//though 0 based, there is a white space after the 3 digit number....//msg2
       
   396         $challange = base64_decode($challange);
       
   397         $ntlm_res = $ntlm_client->NTLMResponse(substr($challange,24,8),$password);
       
   398         $msg3 = $ntlm_client->TypeMsg3($ntlm_res,$username,$realm,$workstation);//msg3
       
   399         // Send encoded username
       
   400         fputs($this->smtp_conn, base64_encode($msg3) . $this->CRLF);
       
   401 
       
   402         $rply = $this->get_lines();
       
   403         $code = substr($rply,0,3);
       
   404 
       
   405         if($code != 235) {
       
   406             $this->error =
       
   407                 array("error" => "Could not authenticate",
       
   408                       "smtp_code" => $code,
       
   409                       "smtp_msg" => substr($rply,4));
       
   410             if($this->do_debug >= 1) {
       
   411                 $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF);
       
   412             }
       
   413             return false;
       
   414         }
       
   415         break;
       
   416     }
       
   417     return true;
       
   418   }
       
   419 
       
   420   /**
       
   421    * Returns true if connected to a server otherwise false
       
   422    * @access public
       
   423    * @return bool
       
   424    */
       
   425   public function Connected() {
       
   426     if(!empty($this->smtp_conn)) {
       
   427       $sock_status = socket_get_status($this->smtp_conn);
       
   428       if($sock_status["eof"]) {
       
   429         // the socket is valid but we are not connected
       
   430         if($this->do_debug >= 1) {
       
   431             $this->edebug("SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected");
       
   432         }
       
   433         $this->Close();
       
   434         return false;
       
   435       }
       
   436       return true; // everything looks good
       
   437     }
       
   438     return false;
       
   439   }
       
   440 
       
   441   /**
       
   442    * Closes the socket and cleans up the state of the class.
       
   443    * It is not considered good to use this function without
       
   444    * first trying to use QUIT.
       
   445    * @access public
       
   446    * @return void
       
   447    */
       
   448   public function Close() {
       
   449     $this->error = null; // so there is no confusion
       
   450     $this->helo_rply = null;
       
   451     if(!empty($this->smtp_conn)) {
       
   452       // close the connection and cleanup
       
   453       fclose($this->smtp_conn);
       
   454       $this->smtp_conn = 0;
       
   455     }
       
   456   }
       
   457 
       
   458   /////////////////////////////////////////////////
       
   459   // SMTP COMMANDS
       
   460   /////////////////////////////////////////////////
       
   461 
       
   462   /**
       
   463    * Issues a data command and sends the msg_data to the server
       
   464    * finializing the mail transaction. $msg_data is the message
       
   465    * that is to be send with the headers. Each header needs to be
       
   466    * on a single line followed by a <CRLF> with the message headers
       
   467    * and the message body being seperated by and additional <CRLF>.
       
   468    *
       
   469    * Implements rfc 821: DATA <CRLF>
       
   470    *
       
   471    * SMTP CODE INTERMEDIATE: 354
       
   472    *     [data]
       
   473    *     <CRLF>.<CRLF>
       
   474    *     SMTP CODE SUCCESS: 250
       
   475    *     SMTP CODE FAILURE: 552,554,451,452
       
   476    * SMTP CODE FAILURE: 451,554
       
   477    * SMTP CODE ERROR  : 500,501,503,421
       
   478    * @access public
       
   479    * @param string $msg_data
       
   480    * @return bool
       
   481    */
       
   482   public function Data($msg_data) {
       
   483     $this->error = null; // so no confusion is caused
       
   484 
       
   485     if(!$this->connected()) {
       
   486       $this->error = array(
       
   487               "error" => "Called Data() without being connected");
       
   488       return false;
       
   489     }
       
   490 
       
   491     fputs($this->smtp_conn,"DATA" . $this->CRLF);
       
   492 
       
   493     $rply = $this->get_lines();
       
   494     $code = substr($rply,0,3);
       
   495 
       
   496     if($this->do_debug >= 2) {
       
   497       $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
       
   498     }
       
   499 
       
   500     if($code != 354) {
       
   501       $this->error =
       
   502         array("error" => "DATA command not accepted from server",
       
   503               "smtp_code" => $code,
       
   504               "smtp_msg" => substr($rply,4));
       
   505       if($this->do_debug >= 1) {
       
   506         $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   507       }
       
   508       return false;
       
   509     }
       
   510 
       
   511     /* the server is ready to accept data!
       
   512      * according to rfc 821 we should not send more than 1000
       
   513      * including the CRLF
       
   514      * characters on a single line so we will break the data up
       
   515      * into lines by \r and/or \n then if needed we will break
       
   516      * each of those into smaller lines to fit within the limit.
       
   517      * in addition we will be looking for lines that start with
       
   518      * a period '.' and append and additional period '.' to that
       
   519      * line. NOTE: this does not count towards limit.
       
   520      */
       
   521 
       
   522     // normalize the line breaks so we know the explode works
       
   523     $msg_data = str_replace("\r\n","\n",$msg_data);
       
   524     $msg_data = str_replace("\r","\n",$msg_data);
       
   525     $lines = explode("\n",$msg_data);
       
   526 
       
   527     /* we need to find a good way to determine is headers are
       
   528      * in the msg_data or if it is a straight msg body
       
   529      * currently I am assuming rfc 822 definitions of msg headers
       
   530      * and if the first field of the first line (':' sperated)
       
   531      * does not contain a space then it _should_ be a header
       
   532      * and we can process all lines before a blank "" line as
       
   533      * headers.
       
   534      */
       
   535 
       
   536     $field = substr($lines[0],0,strpos($lines[0],":"));
       
   537     $in_headers = false;
       
   538     if(!empty($field) && !strstr($field," ")) {
       
   539       $in_headers = true;
       
   540     }
       
   541 
       
   542     $max_line_length = 998; // used below; set here for ease in change
       
   543 
       
   544     while(list(,$line) = @each($lines)) {
       
   545       $lines_out = null;
       
   546       if($line == "" && $in_headers) {
       
   547         $in_headers = false;
       
   548       }
       
   549       // ok we need to break this line up into several smaller lines
       
   550       while(strlen($line) > $max_line_length) {
       
   551         $pos = strrpos(substr($line,0,$max_line_length)," ");
       
   552 
       
   553         // Patch to fix DOS attack
       
   554         if(!$pos) {
       
   555           $pos = $max_line_length - 1;
       
   556           $lines_out[] = substr($line,0,$pos);
       
   557           $line = substr($line,$pos);
       
   558         } else {
       
   559           $lines_out[] = substr($line,0,$pos);
       
   560           $line = substr($line,$pos + 1);
       
   561         }
       
   562 
       
   563         /* if processing headers add a LWSP-char to the front of new line
       
   564          * rfc 822 on long msg headers
       
   565          */
       
   566         if($in_headers) {
       
   567           $line = "\t" . $line;
       
   568         }
       
   569       }
       
   570       $lines_out[] = $line;
       
   571 
       
   572       // send the lines to the server
       
   573       while(list(,$line_out) = @each($lines_out)) {
       
   574         if(strlen($line_out) > 0)
       
   575         {
       
   576           if(substr($line_out, 0, 1) == ".") {
       
   577             $line_out = "." . $line_out;
       
   578           }
       
   579         }
       
   580         fputs($this->smtp_conn,$line_out . $this->CRLF);
       
   581       }
       
   582     }
       
   583 
       
   584     // message data has been sent
       
   585     fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
       
   586 
       
   587     $rply = $this->get_lines();
       
   588     $code = substr($rply,0,3);
       
   589 
       
   590     if($this->do_debug >= 2) {
       
   591       $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
       
   592     }
       
   593 
       
   594     if($code != 250) {
       
   595       $this->error =
       
   596         array("error" => "DATA not accepted from server",
       
   597               "smtp_code" => $code,
       
   598               "smtp_msg" => substr($rply,4));
       
   599       if($this->do_debug >= 1) {
       
   600         $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   601       }
       
   602       return false;
       
   603     }
       
   604     return true;
       
   605   }
       
   606 
       
   607   /**
       
   608    * Sends the HELO command to the smtp server.
       
   609    * This makes sure that we and the server are in
       
   610    * the same known state.
       
   611    *
       
   612    * Implements from rfc 821: HELO <SP> <domain> <CRLF>
       
   613    *
       
   614    * SMTP CODE SUCCESS: 250
       
   615    * SMTP CODE ERROR  : 500, 501, 504, 421
       
   616    * @access public
       
   617    * @param string $host
       
   618    * @return bool
       
   619    */
       
   620   public function Hello($host = '') {
       
   621     $this->error = null; // so no confusion is caused
       
   622 
       
   623     if(!$this->connected()) {
       
   624       $this->error = array(
       
   625             "error" => "Called Hello() without being connected");
       
   626       return false;
       
   627     }
       
   628 
       
   629     // if hostname for HELO was not specified send default
       
   630     if(empty($host)) {
       
   631       // determine appropriate default to send to server
       
   632       $host = "localhost";
       
   633     }
       
   634 
       
   635     // Send extended hello first (RFC 2821)
       
   636     if(!$this->SendHello("EHLO", $host)) {
       
   637       if(!$this->SendHello("HELO", $host)) {
       
   638         return false;
       
   639       }
       
   640     }
       
   641 
       
   642     return true;
       
   643   }
       
   644 
       
   645   /**
       
   646    * Sends a HELO/EHLO command.
       
   647    * @access private
       
   648    * @param string $hello
       
   649    * @param string $host
       
   650    * @return bool
       
   651    */
       
   652   private function SendHello($hello, $host) {
       
   653     fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
       
   654 
       
   655     $rply = $this->get_lines();
       
   656     $code = substr($rply,0,3);
       
   657 
       
   658     if($this->do_debug >= 2) {
       
   659       $this->edebug("SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />');
       
   660     }
       
   661 
       
   662     if($code != 250) {
       
   663       $this->error =
       
   664         array("error" => $hello . " not accepted from server",
       
   665               "smtp_code" => $code,
       
   666               "smtp_msg" => substr($rply,4));
       
   667       if($this->do_debug >= 1) {
       
   668         $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   669       }
       
   670       return false;
       
   671     }
       
   672 
       
   673     $this->helo_rply = $rply;
       
   674 
       
   675     return true;
       
   676   }
       
   677 
       
   678   /**
       
   679    * Starts a mail transaction from the email address specified in
       
   680    * $from. Returns true if successful or false otherwise. If True
       
   681    * the mail transaction is started and then one or more Recipient
       
   682    * commands may be called followed by a Data command.
       
   683    *
       
   684    * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
       
   685    *
       
   686    * SMTP CODE SUCCESS: 250
       
   687    * SMTP CODE SUCCESS: 552,451,452
       
   688    * SMTP CODE SUCCESS: 500,501,421
       
   689    * @access public
       
   690    * @param string $from
       
   691    * @return bool
       
   692    */
       
   693   public function Mail($from) {
       
   694     $this->error = null; // so no confusion is caused
       
   695 
       
   696     if(!$this->connected()) {
       
   697       $this->error = array(
       
   698               "error" => "Called Mail() without being connected");
       
   699       return false;
       
   700     }
       
   701 
       
   702     $useVerp = ($this->do_verp ? " XVERP" : "");
       
   703     fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
       
   704 
       
   705     $rply = $this->get_lines();
       
   706     $code = substr($rply,0,3);
       
   707 
       
   708     if($this->do_debug >= 2) {
       
   709       $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
       
   710     }
       
   711 
       
   712     if($code != 250) {
       
   713       $this->error =
       
   714         array("error" => "MAIL not accepted from server",
       
   715               "smtp_code" => $code,
       
   716               "smtp_msg" => substr($rply,4));
       
   717       if($this->do_debug >= 1) {
       
   718         $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   719       }
       
   720       return false;
       
   721     }
       
   722     return true;
       
   723   }
       
   724 
       
   725   /**
       
   726    * Sends the quit command to the server and then closes the socket
       
   727    * if there is no error or the $close_on_error argument is true.
       
   728    *
       
   729    * Implements from rfc 821: QUIT <CRLF>
       
   730    *
       
   731    * SMTP CODE SUCCESS: 221
       
   732    * SMTP CODE ERROR  : 500
       
   733    * @access public
       
   734    * @param bool $close_on_error
       
   735    * @return bool
       
   736    */
       
   737   public function Quit($close_on_error = true) {
       
   738     $this->error = null; // so there is no confusion
       
   739 
       
   740     if(!$this->connected()) {
       
   741       $this->error = array(
       
   742               "error" => "Called Quit() without being connected");
       
   743       return false;
       
   744     }
       
   745 
       
   746     // send the quit command to the server
       
   747     fputs($this->smtp_conn,"quit" . $this->CRLF);
       
   748 
       
   749     // get any good-bye messages
       
   750     $byemsg = $this->get_lines();
       
   751 
       
   752     if($this->do_debug >= 2) {
       
   753       $this->edebug("SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />');
       
   754     }
       
   755 
       
   756     $rval = true;
       
   757     $e = null;
       
   758 
       
   759     $code = substr($byemsg,0,3);
       
   760     if($code != 221) {
       
   761       // use e as a tmp var cause Close will overwrite $this->error
       
   762       $e = array("error" => "SMTP server rejected quit command",
       
   763                  "smtp_code" => $code,
       
   764                  "smtp_rply" => substr($byemsg,4));
       
   765       $rval = false;
       
   766       if($this->do_debug >= 1) {
       
   767         $this->edebug("SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />');
       
   768       }
       
   769     }
       
   770 
       
   771     if(empty($e) || $close_on_error) {
       
   772       $this->Close();
       
   773     }
       
   774 
       
   775     return $rval;
       
   776   }
       
   777 
       
   778   /**
       
   779    * Sends the command RCPT to the SMTP server with the TO: argument of $to.
       
   780    * Returns true if the recipient was accepted false if it was rejected.
       
   781    *
       
   782    * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
       
   783    *
       
   784    * SMTP CODE SUCCESS: 250,251
       
   785    * SMTP CODE FAILURE: 550,551,552,553,450,451,452
       
   786    * SMTP CODE ERROR  : 500,501,503,421
       
   787    * @access public
       
   788    * @param string $to
       
   789    * @return bool
       
   790    */
       
   791   public function Recipient($to) {
       
   792     $this->error = null; // so no confusion is caused
       
   793 
       
   794     if(!$this->connected()) {
       
   795       $this->error = array(
       
   796               "error" => "Called Recipient() without being connected");
       
   797       return false;
       
   798     }
       
   799 
       
   800     fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
       
   801 
       
   802     $rply = $this->get_lines();
       
   803     $code = substr($rply,0,3);
       
   804 
       
   805     if($this->do_debug >= 2) {
       
   806       $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
       
   807     }
       
   808 
       
   809     if($code != 250 && $code != 251) {
       
   810       $this->error =
       
   811         array("error" => "RCPT not accepted from server",
       
   812               "smtp_code" => $code,
       
   813               "smtp_msg" => substr($rply,4));
       
   814       if($this->do_debug >= 1) {
       
   815         $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   816       }
       
   817       return false;
       
   818     }
       
   819     return true;
       
   820   }
       
   821 
       
   822   /**
       
   823    * Sends the RSET command to abort and transaction that is
       
   824    * currently in progress. Returns true if successful false
       
   825    * otherwise.
       
   826    *
       
   827    * Implements rfc 821: RSET <CRLF>
       
   828    *
       
   829    * SMTP CODE SUCCESS: 250
       
   830    * SMTP CODE ERROR  : 500,501,504,421
       
   831    * @access public
       
   832    * @return bool
       
   833    */
       
   834   public function Reset() {
       
   835     $this->error = null; // so no confusion is caused
       
   836 
       
   837     if(!$this->connected()) {
       
   838       $this->error = array(
       
   839               "error" => "Called Reset() without being connected");
       
   840       return false;
       
   841     }
       
   842 
       
   843     fputs($this->smtp_conn,"RSET" . $this->CRLF);
       
   844 
       
   845     $rply = $this->get_lines();
       
   846     $code = substr($rply,0,3);
       
   847 
       
   848     if($this->do_debug >= 2) {
       
   849       $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
       
   850     }
       
   851 
       
   852     if($code != 250) {
       
   853       $this->error =
       
   854         array("error" => "RSET failed",
       
   855               "smtp_code" => $code,
       
   856               "smtp_msg" => substr($rply,4));
       
   857       if($this->do_debug >= 1) {
       
   858         $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   859       }
       
   860       return false;
       
   861     }
       
   862 
       
   863     return true;
       
   864   }
       
   865 
       
   866   /**
       
   867    * Starts a mail transaction from the email address specified in
       
   868    * $from. Returns true if successful or false otherwise. If True
       
   869    * the mail transaction is started and then one or more Recipient
       
   870    * commands may be called followed by a Data command. This command
       
   871    * will send the message to the users terminal if they are logged
       
   872    * in and send them an email.
       
   873    *
       
   874    * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
       
   875    *
       
   876    * SMTP CODE SUCCESS: 250
       
   877    * SMTP CODE SUCCESS: 552,451,452
       
   878    * SMTP CODE SUCCESS: 500,501,502,421
       
   879    * @access public
       
   880    * @param string $from
       
   881    * @return bool
       
   882    */
       
   883   public function SendAndMail($from) {
       
   884     $this->error = null; // so no confusion is caused
       
   885 
       
   886     if(!$this->connected()) {
       
   887       $this->error = array(
       
   888           "error" => "Called SendAndMail() without being connected");
       
   889       return false;
       
   890     }
       
   891 
       
   892     fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
       
   893 
       
   894     $rply = $this->get_lines();
       
   895     $code = substr($rply,0,3);
       
   896 
       
   897     if($this->do_debug >= 2) {
       
   898       $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
       
   899     }
       
   900 
       
   901     if($code != 250) {
       
   902       $this->error =
       
   903         array("error" => "SAML not accepted from server",
       
   904               "smtp_code" => $code,
       
   905               "smtp_msg" => substr($rply,4));
       
   906       if($this->do_debug >= 1) {
       
   907         $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
       
   908       }
       
   909       return false;
       
   910     }
       
   911     return true;
       
   912   }
       
   913 
       
   914   /**
       
   915    * This is an optional command for SMTP that this class does not
       
   916    * support. This method is here to make the RFC821 Definition
       
   917    * complete for this class and __may__ be implimented in the future
       
   918    *
       
   919    * Implements from rfc 821: TURN <CRLF>
       
   920    *
       
   921    * SMTP CODE SUCCESS: 250
       
   922    * SMTP CODE FAILURE: 502
       
   923    * SMTP CODE ERROR  : 500, 503
       
   924    * @access public
       
   925    * @return bool
       
   926    */
       
   927   public function Turn() {
       
   928     $this->error = array("error" => "This method, TURN, of the SMTP ".
       
   929                                     "is not implemented");
       
   930     if($this->do_debug >= 1) {
       
   931       $this->edebug("SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />');
       
   932     }
       
   933     return false;
       
   934   }
       
   935 
       
   936   /**
       
   937   * Get the current error
       
   938   * @access public
       
   939   * @return array
       
   940   */
       
   941   public function getError() {
       
   942     return $this->error;
       
   943   }
       
   944 
       
   945   /////////////////////////////////////////////////
       
   946   // INTERNAL FUNCTIONS
       
   947   /////////////////////////////////////////////////
       
   948 
       
   949   /**
       
   950    * Read in as many lines as possible
       
   951    * either before eof or socket timeout occurs on the operation.
       
   952    * With SMTP we can tell if we have more lines to read if the
       
   953    * 4th character is '-' symbol. If it is a space then we don't
       
   954    * need to read anything else.
       
   955    * @access private
       
   956    * @return string
       
   957    */
       
   958   private function get_lines() {
       
   959     $data = "";
       
   960     $endtime = 0;
       
   961     /* If for some reason the fp is bad, don't inf loop */
       
   962     if (!is_resource($this->smtp_conn)) {
       
   963       return $data;
       
   964     }
       
   965     stream_set_timeout($this->smtp_conn, $this->Timeout);
       
   966     if ($this->Timelimit > 0) {
       
   967       $endtime = time() + $this->Timelimit;
       
   968     }
       
   969     while(is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
       
   970       $str = @fgets($this->smtp_conn,515);
       
   971       if($this->do_debug >= 4) {
       
   972         $this->edebug("SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />');
       
   973         $this->edebug("SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />');
       
   974       }
       
   975       $data .= $str;
       
   976       if($this->do_debug >= 4) {
       
   977         $this->edebug("SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />');
       
   978       }
       
   979       // if 4th character is a space, we are done reading, break the loop
       
   980       if(substr($str,3,1) == " ") { break; }
       
   981       // Timed-out? Log and break
       
   982       $info = stream_get_meta_data($this->smtp_conn);
       
   983       if ($info['timed_out']) {
       
   984         if($this->do_debug >= 4) {
       
   985           $this->edebug("SMTP -> get_lines(): timed-out (" . $this->Timeout . " seconds) <br />");
       
   986         }
       
   987         break;
       
   988       }
       
   989       // Now check if reads took too long
       
   990       if ($endtime) {
       
   991         if (time() > $endtime) {
       
   992           if($this->do_debug >= 4) {
       
   993             $this->edebug("SMTP -> get_lines(): timelimit reached (" . $this->Timelimit . " seconds) <br />");
       
   994           }
       
   995           break;
       
   996         }
       
   997       }
       
   998     }
       
   999     return $data;
       
  1000   }
       
  1001 
       
  1002 }
       
  1003 ?>