Net_SMTP
[ class tree: Net_SMTP ] [ index: Net_SMTP ] [ all elements ]

Source for file SMTP.php

Documentation is available at SMTP.php

  1. <?php
  2. /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Chuck Hagenbuch <chuck@horde.org>                           |
  17. // |          Jon Parise <jon@php.net>                                    |
  18. // |          Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>      |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: SMTP.php 284052 2009-07-14 05:34:26Z jon $
  22.  
  23. require_once 'PEAR.php';
  24. require_once 'Net/Socket.php';
  25.  
  26. /**
  27.  * Provides an implementation of the SMTP protocol using PEAR's
  28.  * Net_Socket:: class.
  29.  *
  30.  * @package Net_SMTP
  31.  * @author  Chuck Hagenbuch <chuck@horde.org>
  32.  * @author  Jon Parise <jon@php.net>
  33.  * @author  Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>
  34.  *
  35.  * @example basic.php   A basic implementation of the Net_SMTP package.
  36.  */
  37. class Net_SMTP
  38. {
  39.     /**
  40.      * The server to connect to.
  41.      * @var string 
  42.      * @access public
  43.      */
  44.     var $host = 'localhost';
  45.  
  46.     /**
  47.      * The port to connect to.
  48.      * @var int 
  49.      * @access public
  50.      */
  51.     var $port = 25;
  52.  
  53.     /**
  54.      * The value to give when sending EHLO or HELO.
  55.      * @var string 
  56.      * @access public
  57.      */
  58.     var $localhost = 'localhost';
  59.  
  60.     /**
  61.      * List of supported authentication methods, in preferential order.
  62.      * @var array 
  63.      * @access public
  64.      */
  65.     var $auth_methods = array('DIGEST-MD5''CRAM-MD5''LOGIN''PLAIN');
  66.  
  67.     /**
  68.      * Use SMTP command pipelining (specified in RFC 2920) if the SMTP
  69.      * server supports it.
  70.      *
  71.      * When pipeling is enabled, rcptTo(), mailFrom(), sendFrom(),
  72.      * somlFrom() and samlFrom() do not wait for a response from the
  73.      * SMTP server but return immediately.
  74.      *
  75.      * @var bool 
  76.      * @access public
  77.      */
  78.     var $pipelining = false;
  79.  
  80.     /**
  81.      * Number of pipelined commands.
  82.      * @var int 
  83.      * @access private
  84.      */
  85.     var $_pipelined_commands = 0;
  86.  
  87.     /**
  88.      * Should debugging output be enabled?
  89.      * @var boolean 
  90.      * @access private
  91.      */
  92.     var $_debug = false;
  93.  
  94.     /**
  95.      * Debug output handler.
  96.      * @var callback 
  97.      * @access private
  98.      */
  99.     var $_debug_handler = null;
  100.  
  101.     /**
  102.      * The socket resource being used to connect to the SMTP server.
  103.      * @var resource 
  104.      * @access private
  105.      */
  106.     var $_socket = null;
  107.  
  108.     /**
  109.      * The most recent server response code.
  110.      * @var int 
  111.      * @access private
  112.      */
  113.     var $_code = -1;
  114.  
  115.     /**
  116.      * The most recent server response arguments.
  117.      * @var array 
  118.      * @access private
  119.      */
  120.     var $_arguments = array();
  121.  
  122.     /**
  123.      * Stores the SMTP server's greeting string.
  124.      * @var string 
  125.      * @access private
  126.      */
  127.     var $_greeting = null;
  128.  
  129.     /**
  130.      * Stores detected features of the SMTP server.
  131.      * @var array 
  132.      * @access private
  133.      */
  134.     var $_esmtp = array();
  135.  
  136.     /**
  137.      * Instantiates a new Net_SMTP object, overriding any defaults
  138.      * with parameters that are passed in.
  139.      *
  140.      * If you have SSL support in PHP, you can connect to a server
  141.      * over SSL using an 'ssl://' prefix:
  142.      *
  143.      *   // 465 is a common smtps port.
  144.      *   $smtp = new Net_SMTP('ssl://mail.host.com', 465);
  145.      *   $smtp->connect();
  146.      *
  147.      * @param string  $host       The server to connect to.
  148.      * @param integer $port       The port to connect to.
  149.      * @param string  $localhost  The value to give when sending EHLO or HELO.
  150.      * @param boolean $pipeling   Use SMTP command pipelining
  151.      *
  152.      * @access  public
  153.      * @since   1.0
  154.      */
  155.     function Net_SMTP($host = null$port = null$localhost = null$pipelining = false)
  156.     {
  157.         if (isset($host)) {
  158.             $this->host = $host;
  159.         }
  160.         if (isset($port)) {
  161.             $this->port = $port;
  162.         }
  163.         if (isset($localhost)) {
  164.             $this->localhost = $localhost;
  165.         }
  166.         $this->pipelining = $pipelining;
  167.  
  168.         $this->_socket = new Net_Socket();
  169.  
  170.         /* Include the Auth_SASL package.  If the package is not
  171.          * available, we disable the authentication methods that
  172.          * depend upon it. */
  173.         if ((@include_once 'Auth/SASL.php'=== false{
  174.             $pos array_search('DIGEST-MD5'$this->auth_methods);
  175.             unset($this->auth_methods[$pos]);
  176.             $pos array_search('CRAM-MD5'$this->auth_methods);
  177.             unset($this->auth_methods[$pos]);
  178.         }
  179.     }
  180.  
  181.     /**
  182.      * Set the value of the debugging flag.
  183.      *
  184.      * @param   boolean $debug      New value for the debugging flag.
  185.      *
  186.      * @access  public
  187.      * @since   1.1.0
  188.      */
  189.     function setDebug($debug$handler = null)
  190.     {
  191.         $this->_debug $debug;
  192.         $this->_debug_handler $handler;
  193.     }
  194.  
  195.     /**
  196.      * Write the given debug text to the current debug output handler.
  197.      *
  198.      * @param   string  $message    Debug mesage text.
  199.      *
  200.      * @access  private
  201.      * @since   1.3.3
  202.      */
  203.     function _debug($message)
  204.     {
  205.         if ($this->_debug{
  206.             if ($this->_debug_handler{
  207.                 call_user_func_array($this->_debug_handler,
  208.                                      array(&$this$message));
  209.             else {
  210.                 echo "DEBUG: $message\n";
  211.             }
  212.         }
  213.     }
  214.  
  215.     /**
  216.      * Send the given string of data to the server.
  217.      *
  218.      * @param   string  $data       The string of data to send.
  219.      *
  220.      * @return  mixed   True on success or a PEAR_Error object on failure.
  221.      *
  222.      * @access  private
  223.      * @since   1.1.0
  224.      */
  225.     function _send($data)
  226.     {
  227.         $this->_debug("Send: $data");
  228.  
  229.         if (PEAR::isError($error $this->_socket->write($data))) {
  230.             return PEAR::raiseError('Failed to write to socket: ' .
  231.                                     $error->getMessage());
  232.         }
  233.  
  234.         return true;
  235.     }
  236.  
  237.     /**
  238.      * Send a command to the server with an optional string of
  239.      * arguments.  A carriage return / linefeed (CRLF) sequence will
  240.      * be appended to each command string before it is sent to the
  241.      * SMTP server - an error will be thrown if the command string
  242.      * already contains any newline characters. Use _send() for
  243.      * commands that must contain newlines.
  244.      *
  245.      * @param   string  $command    The SMTP command to send to the server.
  246.      * @param   string  $args       A string of optional arguments to append
  247.      *                               to the command.
  248.      *
  249.      * @return  mixed   The result of the _send() call.
  250.      *
  251.      * @access  private
  252.      * @since   1.1.0
  253.      */
  254.     function _put($command$args '')
  255.     {
  256.         if (!empty($args)) {
  257.             $command .= ' ' $args;
  258.         }
  259.  
  260.         if (strcspn($command"\r\n"!== strlen($command)) {
  261.             return PEAR::raiseError('Commands cannot contain newlines');
  262.         }
  263.  
  264.         return $this->_send($command "\r\n");
  265.     }
  266.  
  267.     /**
  268.      * Read a reply from the SMTP server.  The reply consists of a response
  269.      * code and a response message.
  270.      *
  271.      * @param   mixed   $valid      The set of valid response codes.  These
  272.      *                               may be specified as an array of integer
  273.      *                               values or as a single integer value.
  274.      * @param   bool    $later      Do not parse the response now, but wait
  275.      *                               until the last command in the pipelined
  276.      *                               command group
  277.      *
  278.      * @return  mixed   True if the server returned a valid response code or
  279.      *                   a PEAR_Error object is an error condition is reached.
  280.      *
  281.      * @access  private
  282.      * @since   1.1.0
  283.      *
  284.      * @see     getResponse
  285.      */
  286.     function _parseResponse($valid$later = false)
  287.     {
  288.         $this->_code = -1;
  289.         $this->_arguments = array();
  290.  
  291.         if ($later{
  292.             $this->_pipelined_commands++;
  293.             return true;
  294.         }
  295.  
  296.         for ($i = 0; $i <= $this->_pipelined_commands$i++{
  297.             while ($line $this->_socket->readLine()) {
  298.                 $this->_debug("Recv: $line");
  299.  
  300.                 /* If we receive an empty line, the connection has been closed. */
  301.                 if (empty($line)) {
  302.                     $this->disconnect();
  303.                     return PEAR::raiseError('Connection was unexpectedly closed');
  304.                 }
  305.  
  306.                 /* Read the code and store the rest in the arguments array. */
  307.                 $code substr($line03);
  308.                 $this->_arguments[trim(substr($line4));
  309.  
  310.                 /* Check the syntax of the response code. */
  311.                 if (is_numeric($code)) {
  312.                     $this->_code = (int)$code;
  313.                 else {
  314.                     $this->_code = -1;
  315.                     break;
  316.                 }
  317.  
  318.                 /* If this is not a multiline response, we're done. */
  319.                 if (substr($line31!= '-'{
  320.                     break;
  321.                 }
  322.             }
  323.         }
  324.  
  325.         $this->_pipelined_commands = 0;
  326.  
  327.         /* Compare the server's response code with the valid code/codes. */
  328.         if (is_int($valid&& ($this->_code === $valid)) {
  329.             return true;
  330.         elseif (is_array($valid&& in_array($this->_code$validtrue)) {
  331.             return true;
  332.         }
  333.  
  334.         return PEAR::raiseError('Invalid response code received from server',
  335.                                 $this->_code);
  336.     }
  337.  
  338.     /**
  339.      * Return a 2-tuple containing the last response from the SMTP server.
  340.      *
  341.      * @return  array   A two-element array: the first element contains the
  342.      *                   response code as an integer and the second element
  343.      *                   contains the response's arguments as a string.
  344.      *
  345.      * @access  public
  346.      * @since   1.1.0
  347.      */
  348.     function getResponse()
  349.     {
  350.         return array($this->_codejoin("\n"$this->_arguments));
  351.     }
  352.  
  353.     /**
  354.      * Return the SMTP server's greeting string.
  355.      *
  356.      * @return  string  A string containing the greeting string, or null if a
  357.      *                   greeting has not been received.
  358.      *
  359.      * @access  public
  360.      * @since   1.3.3
  361.      */
  362.     function getGreeting()
  363.     {
  364.         return $this->_greeting;
  365.     }
  366.  
  367.     /**
  368.      * Attempt to connect to the SMTP server.
  369.      *
  370.      * @param   int     $timeout    The timeout value (in seconds) for the
  371.      *                               socket connection.
  372.      * @param   bool    $persistent Should a persistent socket connection
  373.      *                               be used?
  374.      *
  375.      * @return mixed Returns a PEAR_Error with an error message on any
  376.      *                kind of failure, or true on success.
  377.      * @access public
  378.      * @since  1.0
  379.      */
  380.     function connect($timeout = null$persistent = false)
  381.     {
  382.         $this->_greeting = null;
  383.         $result $this->_socket->connect($this->host$this->port,
  384.                                           $persistent$timeout);
  385.         if (PEAR::isError($result)) {
  386.             return PEAR::raiseError('Failed to connect socket: ' .
  387.                                     $result->getMessage());
  388.         }
  389.  
  390.         if (PEAR::isError($error $this->_parseResponse(220))) {
  391.             return $error;
  392.         }
  393.  
  394.         /* Extract and store a copy of the server's greeting string. */
  395.         list($this->_greeting$this->getResponse();
  396.  
  397.         if (PEAR::isError($error $this->_negotiate())) {
  398.             return $error;
  399.         }
  400.  
  401.         return true;
  402.     }
  403.  
  404.     /**
  405.      * Attempt to disconnect from the SMTP server.
  406.      *
  407.      * @return mixed Returns a PEAR_Error with an error message on any
  408.      *                kind of failure, or true on success.
  409.      * @access public
  410.      * @since  1.0
  411.      */
  412.     function disconnect()
  413.     {
  414.         if (PEAR::isError($error $this->_put('QUIT'))) {
  415.             return $error;
  416.         }
  417.         if (PEAR::isError($error $this->_parseResponse(221))) {
  418.             return $error;
  419.         }
  420.         if (PEAR::isError($error $this->_socket->disconnect())) {
  421.             return PEAR::raiseError('Failed to disconnect socket: ' .
  422.                                     $error->getMessage());
  423.         }
  424.  
  425.         return true;
  426.     }
  427.  
  428.     /**
  429.      * Attempt to send the EHLO command and obtain a list of ESMTP
  430.      * extensions available, and failing that just send HELO.
  431.      *
  432.      * @return mixed Returns a PEAR_Error with an error message on any
  433.      *                kind of failure, or true on success.
  434.      *
  435.      * @access private
  436.      * @since  1.1.0
  437.      */
  438.     function _negotiate()
  439.     {
  440.         if (PEAR::isError($error $this->_put('EHLO'$this->localhost))) {
  441.             return $error;
  442.         }
  443.  
  444.         if (PEAR::isError($this->_parseResponse(250))) {
  445.             /* If we receive a 503 response, we're already authenticated. */
  446.             if ($this->_code === 503{
  447.                 return true;
  448.             }
  449.  
  450.             /* If the EHLO failed, try the simpler HELO command. */
  451.             if (PEAR::isError($error $this->_put('HELO'$this->localhost))) {
  452.                 return $error;
  453.             }
  454.             if (PEAR::isError($this->_parseResponse(250))) {
  455.                 return PEAR::raiseError('HELO was not accepted: '$this->_code);
  456.             }
  457.  
  458.             return true;
  459.         }
  460.  
  461.         foreach ($this->_arguments as $argument{
  462.             $verb strtok($argument' ');
  463.             $arguments substr($argumentstrlen($verb+ 1,
  464.                                 strlen($argumentstrlen($verb- 1);
  465.             $this->_esmtp[$verb$arguments;
  466.         }
  467.  
  468.         if (!isset($this->_esmtp['PIPELINING'])) {
  469.             $this->pipelining = false;
  470.         }
  471.  
  472.         return true;
  473.     }
  474.  
  475.     /**
  476.      * Returns the name of the best authentication method that the server
  477.      * has advertised.
  478.      *
  479.      * @return mixed    Returns a string containing the name of the best
  480.      *                   supported authentication method or a PEAR_Error object
  481.      *                   if a failure condition is encountered.
  482.      * @access private
  483.      * @since  1.1.0
  484.      */
  485.     function _getBestAuthMethod()
  486.     {
  487.         $available_methods explode(' '$this->_esmtp['AUTH']);
  488.  
  489.         foreach ($this->auth_methods as $method{
  490.             if (in_array($method$available_methods)) {
  491.                 return $method;
  492.             }
  493.         }
  494.  
  495.         return PEAR::raiseError('No supported authentication methods');
  496.     }
  497.  
  498.     /**
  499.      * Attempt to do SMTP authentication.
  500.      *
  501.      * @param string The userid to authenticate as.
  502.      * @param string The password to authenticate with.
  503.      * @param string The requested authentication method.  If none is
  504.      *                specified, the best supported method will be used.
  505.      *
  506.      * @return mixed Returns a PEAR_Error with an error message on any
  507.      *                kind of failure, or true on success.
  508.      * @access public
  509.      * @since  1.0
  510.      */
  511.     function auth($uid$pwd $method '')
  512.     {
  513.         /* We can only attempt a TLS connection if we're running PHP 5.1.0 or 
  514.          * later, have access to the OpenSSL extension, are connected to an 
  515.          * SMTP server which supports the STARTTLS extension, and aren't 
  516.          * already connected over a secure (SSL) socket connection. */
  517.         $tls version_compare(PHP_VERSION'5.1.0''>='&& extension_loaded('openssl'&&
  518.                isset($this->_esmtp['STARTTLS']&& strncasecmp($this->host'ssl://'6!= 0;
  519.  
  520.         if ($tls{
  521.             if (PEAR::isError($result $this->_put('STARTTLS'))) {
  522.                 return $result;
  523.             }
  524.             if (PEAR::isError($result $this->_parseResponse(220))) {
  525.                 return $result;
  526.             }
  527.             if (PEAR::isError($result $this->_socket->enableCrypto(trueSTREAM_CRYPTO_METHOD_TLS_CLIENT))) {
  528.                 return $result;
  529.             elseif ($result !== true{
  530.                 return PEAR::raiseError('STARTTLS failed');
  531.             }
  532.  
  533.             /* Send EHLO again to recieve the AUTH string from the
  534.              * SMTP server. */
  535.             $this->_negotiate();
  536.         }
  537.  
  538.         if (empty($this->_esmtp['AUTH'])) {
  539.             return PEAR::raiseError('SMTP server does not support authentication');
  540.         }
  541.  
  542.         /* If no method has been specified, get the name of the best
  543.          * supported method advertised by the SMTP server. */
  544.         if (empty($method)) {
  545.             if (PEAR::isError($method $this->_getBestAuthMethod())) {
  546.                 /* Return the PEAR_Error object from _getBestAuthMethod(). */
  547.                 return $method;
  548.             }
  549.         else {
  550.             $method strtoupper($method);
  551.             if (!in_array($method$this->auth_methods)) {
  552.                 return PEAR::raiseError("$method is not a supported authentication method");
  553.             }
  554.         }
  555.  
  556.         switch ($method{
  557.         case 'DIGEST-MD5':
  558.             $result $this->_authDigest_MD5($uid$pwd);
  559.             break;
  560.  
  561.         case 'CRAM-MD5':
  562.             $result $this->_authCRAM_MD5($uid$pwd);
  563.             break;
  564.  
  565.         case 'LOGIN':
  566.             $result $this->_authLogin($uid$pwd);
  567.             break;
  568.  
  569.         case 'PLAIN':
  570.             $result $this->_authPlain($uid$pwd);
  571.             break;
  572.  
  573.         default:
  574.             $result = PEAR::raiseError("$method is not a supported authentication method");
  575.             break;
  576.         }
  577.  
  578.         /* If an error was encountered, return the PEAR_Error object. */
  579.         if (PEAR::isError($result)) {
  580.             return $result;
  581.         }
  582.  
  583.         return true;
  584.     }
  585.  
  586.     /**
  587.      * Authenticates the user using the DIGEST-MD5 method.
  588.      *
  589.      * @param string The userid to authenticate as.
  590.      * @param string The password to authenticate with.
  591.      *
  592.      * @return mixed Returns a PEAR_Error with an error message on any
  593.      *                kind of failure, or true on success.
  594.      * @access private
  595.      * @since  1.1.0
  596.      */
  597.     function _authDigest_MD5($uid$pwd)
  598.     {
  599.         if (PEAR::isError($error $this->_put('AUTH''DIGEST-MD5'))) {
  600.             return $error;
  601.         }
  602.         /* 334: Continue authentication request */
  603.         if (PEAR::isError($error $this->_parseResponse(334))) {
  604.             /* 503: Error: already authenticated */
  605.             if ($this->_code === 503{
  606.                 return true;
  607.             }
  608.             return $error;
  609.         }
  610.  
  611.         $challenge base64_decode($this->_arguments[0]);
  612.         $digest &Auth_SASL::factory('digestmd5');
  613.         $auth_str base64_encode($digest->getResponse($uid$pwd$challenge,
  614.                                                        $this->host"smtp"));
  615.  
  616.         if (PEAR::isError($error $this->_put($auth_str))) {
  617.             return $error;
  618.         }
  619.         /* 334: Continue authentication request */
  620.         if (PEAR::isError($error $this->_parseResponse(334))) {
  621.             return $error;
  622.         }
  623.  
  624.         /* We don't use the protocol's third step because SMTP doesn't
  625.          * allow subsequent authentication, so we just silently ignore
  626.          * it. */
  627.         if (PEAR::isError($error $this->_put(''))) {
  628.             return $error;
  629.         }
  630.         /* 235: Authentication successful */
  631.         if (PEAR::isError($error $this->_parseResponse(235))) {
  632.             return $error;
  633.         }
  634.     }
  635.  
  636.     /**
  637.      * Authenticates the user using the CRAM-MD5 method.
  638.      *
  639.      * @param string The userid to authenticate as.
  640.      * @param string The password to authenticate with.
  641.      *
  642.      * @return mixed Returns a PEAR_Error with an error message on any
  643.      *                kind of failure, or true on success.
  644.      * @access private
  645.      * @since  1.1.0
  646.      */
  647.     function _authCRAM_MD5($uid$pwd)
  648.     {
  649.         if (PEAR::isError($error $this->_put('AUTH''CRAM-MD5'))) {
  650.             return $error;
  651.         }
  652.         /* 334: Continue authentication request */
  653.         if (PEAR::isError($error $this->_parseResponse(334))) {
  654.             /* 503: Error: already authenticated */
  655.             if ($this->_code === 503{
  656.                 return true;
  657.             }
  658.             return $error;
  659.         }
  660.  
  661.         $challenge base64_decode($this->_arguments[0]);
  662.         $cram &Auth_SASL::factory('crammd5');
  663.         $auth_str base64_encode($cram->getResponse($uid$pwd$challenge));
  664.  
  665.         if (PEAR::isError($error $this->_put($auth_str))) {
  666.             return $error;
  667.         }
  668.  
  669.         /* 235: Authentication successful */
  670.         if (PEAR::isError($error $this->_parseResponse(235))) {
  671.             return $error;
  672.         }
  673.     }
  674.  
  675.     /**
  676.      * Authenticates the user using the LOGIN method.
  677.      *
  678.      * @param string The userid to authenticate as.
  679.      * @param string The password to authenticate with.
  680.      *
  681.      * @return mixed Returns a PEAR_Error with an error message on any
  682.      *                kind of failure, or true on success.
  683.      * @access private
  684.      * @since  1.1.0
  685.      */
  686.     function _authLogin($uid$pwd)
  687.     {
  688.         if (PEAR::isError($error $this->_put('AUTH''LOGIN'))) {
  689.             return $error;
  690.         }
  691.         /* 334: Continue authentication request */
  692.         if (PEAR::isError($error $this->_parseResponse(334))) {
  693.             /* 503: Error: already authenticated */
  694.             if ($this->_code === 503{
  695.                 return true;
  696.             }
  697.             return $error;
  698.         }
  699.  
  700.         if (PEAR::isError($error $this->_put(base64_encode($uid)))) {
  701.             return $error;
  702.         }
  703.         /* 334: Continue authentication request */
  704.         if (PEAR::isError($error $this->_parseResponse(334))) {
  705.             return $error;
  706.         }
  707.  
  708.         if (PEAR::isError($error $this->_put(base64_encode($pwd)))) {
  709.             return $error;
  710.         }
  711.  
  712.         /* 235: Authentication successful */
  713.         if (PEAR::isError($error $this->_parseResponse(235))) {
  714.             return $error;
  715.         }
  716.  
  717.         return true;
  718.     }
  719.  
  720.     /**
  721.      * Authenticates the user using the PLAIN method.
  722.      *
  723.      * @param string The userid to authenticate as.
  724.      * @param string The password to authenticate with.
  725.      *
  726.      * @return mixed Returns a PEAR_Error with an error message on any
  727.      *                kind of failure, or true on success.
  728.      * @access private
  729.      * @since  1.1.0
  730.      */
  731.     function _authPlain($uid$pwd)
  732.     {
  733.         if (PEAR::isError($error $this->_put('AUTH''PLAIN'))) {
  734.             return $error;
  735.         }
  736.         /* 334: Continue authentication request */
  737.         if (PEAR::isError($error $this->_parseResponse(334))) {
  738.             /* 503: Error: already authenticated */
  739.             if ($this->_code === 503{
  740.                 return true;
  741.             }
  742.             return $error;
  743.         }
  744.  
  745.         $auth_str base64_encode(chr(0$uid chr(0$pwd);
  746.  
  747.         if (PEAR::isError($error $this->_put($auth_str))) {
  748.             return $error;
  749.         }
  750.  
  751.         /* 235: Authentication successful */
  752.         if (PEAR::isError($error $this->_parseResponse(235))) {
  753.             return $error;
  754.         }
  755.  
  756.         return true;
  757.     }
  758.  
  759.     /**
  760.      * Send the HELO command.
  761.      *
  762.      * @param string The domain name to say we are.
  763.      *
  764.      * @return mixed Returns a PEAR_Error with an error message on any
  765.      *                kind of failure, or true on success.
  766.      * @access public
  767.      * @since  1.0
  768.      */
  769.     function helo($domain)
  770.     {
  771.         if (PEAR::isError($error $this->_put('HELO'$domain))) {
  772.             return $error;
  773.         }
  774.         if (PEAR::isError($error $this->_parseResponse(250))) {
  775.             return $error;
  776.         }
  777.  
  778.         return true;
  779.     }
  780.  
  781.     /**
  782.      * Return the list of SMTP service extensions advertised by the server.
  783.      *
  784.      * @return array The list of SMTP service extensions.
  785.      * @access public
  786.      * @since 1.3
  787.      */
  788.     function getServiceExtensions()
  789.     {
  790.         return $this->_esmtp;
  791.     }
  792.  
  793.     /**
  794.      * Send the MAIL FROM: command.
  795.      *
  796.      * @param string $sender    The sender (reverse path) to set.
  797.      * @param string $params    String containing additional MAIL parameters,
  798.      *                           such as the NOTIFY flags defined by RFC 1891
  799.      *                           or the VERP protocol.
  800.      *
  801.      *                           If $params is an array, only the 'verp' option
  802.      *                           is supported.  If 'verp' is true, the XVERP
  803.      *                           parameter is appended to the MAIL command.  If
  804.      *                           the 'verp' value is a string, the full
  805.      *                           XVERP=value parameter is appended.
  806.      *
  807.      * @return mixed Returns a PEAR_Error with an error message on any
  808.      *                kind of failure, or true on success.
  809.      * @access public
  810.      * @since  1.0
  811.      */
  812.     function mailFrom($sender$params = null)
  813.     {
  814.         $args = "FROM:<$sender>";
  815.  
  816.         /* Support the deprecated array form of $params. */
  817.         if (is_array($params&& isset($params['verp'])) {
  818.             /* XVERP */
  819.             if ($params['verp'=== true{
  820.                 $args .= ' XVERP';
  821.  
  822.             /* XVERP=something */
  823.             elseif (trim($params['verp'])) {
  824.                 $args .= ' XVERP=' $params['verp'];
  825.             }
  826.         elseif (is_string($params)) {
  827.             $args .= ' ' $params;
  828.         }
  829.  
  830.         if (PEAR::isError($error $this->_put('MAIL'$args))) {
  831.             return $error;
  832.         }
  833.         if (PEAR::isError($error $this->_parseResponse(250$this->pipelining))) {
  834.             return $error;
  835.         }
  836.  
  837.         return true;
  838.     }
  839.  
  840.     /**
  841.      * Send the RCPT TO: command.
  842.      *
  843.      * @param string $recipient The recipient (forward path) to add.
  844.      * @param string $params    String containing additional RCPT parameters,
  845.      *                           such as the NOTIFY flags defined by RFC 1891.
  846.      *
  847.      * @return mixed Returns a PEAR_Error with an error message on any
  848.      *                kind of failure, or true on success.
  849.      *
  850.      * @access public
  851.      * @since  1.0
  852.      */
  853.     function rcptTo($recipient$params = null)
  854.     {
  855.         $args = "TO:<$recipient>";
  856.         if (is_string($params)) {
  857.             $args .= ' ' $params;
  858.         }
  859.  
  860.         if (PEAR::isError($error $this->_put('RCPT'$args))) {
  861.             return $error;
  862.         }
  863.         if (PEAR::isError($error $this->_parseResponse(array(250251)$this->pipelining))) {
  864.             return $error;
  865.         }
  866.  
  867.         return true;
  868.     }
  869.  
  870.     /**
  871.      * Quote the data so that it meets SMTP standards.
  872.      *
  873.      * This is provided as a separate public function to facilitate
  874.      * easier overloading for the cases where it is desirable to
  875.      * customize the quoting behavior.
  876.      *
  877.      * @param string $data  The message text to quote. The string must be passed
  878.      *                       by reference, and the text will be modified in place.
  879.      *
  880.      * @access public
  881.      * @since  1.2
  882.      */
  883.     function quotedata(&$data)
  884.     {
  885.         /* Change Unix (\n) and Mac (\r) linefeeds into
  886.          * Internet-standard CRLF (\r\n) linefeeds. */
  887.         $data preg_replace(array('/(?<!\r)\n/','/\r(?!\n)/')"\r\n"$data);
  888.  
  889.         /* Because a single leading period (.) signifies an end to the
  890.          * data, legitimate leading periods need to be "doubled"
  891.          * (e.g. '..'). */
  892.         $data str_replace("\n.""\n.."$data);
  893.     }
  894.  
  895.     /**
  896.      * Send the DATA command.
  897.      *
  898.      * @param string $data  The message body to send.
  899.      *
  900.      * @return mixed Returns a PEAR_Error with an error message on any
  901.      *                kind of failure, or true on success.
  902.      * @access public
  903.      * @since  1.0
  904.      */
  905.     function data($data)
  906.     {
  907.         /* RFC 1870, section 3, subsection 3 states "a value of zero
  908.          * indicates that no fixed maximum message size is in force".
  909.          * Furthermore, it says that if "the parameter is omitted no
  910.          * information is conveyed about the server's fixed maximum
  911.          * message size". */
  912.         if (isset($this->_esmtp['SIZE']&& ($this->_esmtp['SIZE'> 0)) {
  913.             if (strlen($data>= $this->_esmtp['SIZE']{
  914.                 $this->disconnect();
  915.                 return PEAR::raiseError('Message size excedes the server limit');
  916.             }
  917.         }
  918.  
  919.         /* Quote the data based on the SMTP standards. */
  920.         $this->quotedata($data);
  921.  
  922.         if (PEAR::isError($error $this->_put('DATA'))) {
  923.             return $error;
  924.         }
  925.         if (PEAR::isError($error $this->_parseResponse(354))) {
  926.             return $error;
  927.         }
  928.  
  929.         if (PEAR::isError($result $this->_send($data "\r\n.\r\n"))) {
  930.             return $result;
  931.         }
  932.         if (PEAR::isError($error $this->_parseResponse(250$this->pipelining))) {
  933.             return $error;
  934.         }
  935.  
  936.         return true;
  937.     }
  938.  
  939.     /**
  940.      * Send the SEND FROM: command.
  941.      *
  942.      * @param string The reverse path to send.
  943.      *
  944.      * @return mixed Returns a PEAR_Error with an error message on any
  945.      *                kind of failure, or true on success.
  946.      * @access public
  947.      * @since  1.2.6
  948.      */
  949.     function sendFrom($path)
  950.     {
  951.         if (PEAR::isError($error $this->_put('SEND'"FROM:<$path>"))) {
  952.             return $error;
  953.         }
  954.         if (PEAR::isError($error $this->_parseResponse(250$this->pipelining))) {
  955.             return $error;
  956.         }
  957.  
  958.         return true;
  959.     }
  960.  
  961.     /**
  962.      * Backwards-compatibility wrapper for sendFrom().
  963.      *
  964.      * @param string The reverse path to send.
  965.      *
  966.      * @return mixed Returns a PEAR_Error with an error message on any
  967.      *                kind of failure, or true on success.
  968.      *
  969.      * @access      public
  970.      * @since       1.0
  971.      * @deprecated  1.2.6
  972.      */
  973.     function send_from($path)
  974.     {
  975.         return sendFrom($path);
  976.     }
  977.  
  978.     /**
  979.      * Send the SOML FROM: command.
  980.      *
  981.      * @param string The reverse path to send.
  982.      *
  983.      * @return mixed Returns a PEAR_Error with an error message on any
  984.      *                kind of failure, or true on success.
  985.      * @access public
  986.      * @since  1.2.6
  987.      */
  988.     function somlFrom($path)
  989.     {
  990.         if (PEAR::isError($error $this->_put('SOML'"FROM:<$path>"))) {
  991.             return $error;
  992.         }
  993.         if (PEAR::isError($error $this->_parseResponse(250$this->pipelining))) {
  994.             return $error;
  995.         }
  996.  
  997.         return true;
  998.     }
  999.  
  1000.     /**
  1001.      * Backwards-compatibility wrapper for somlFrom().
  1002.      *
  1003.      * @param string The reverse path to send.
  1004.      *
  1005.      * @return mixed Returns a PEAR_Error with an error message on any
  1006.      *                kind of failure, or true on success.
  1007.      *
  1008.      * @access      public
  1009.      * @since       1.0
  1010.      * @deprecated  1.2.6
  1011.      */
  1012.     function soml_from($path)
  1013.     {
  1014.         return somlFrom($path);
  1015.     }
  1016.  
  1017.     /**
  1018.      * Send the SAML FROM: command.
  1019.      *
  1020.      * @param string The reverse path to send.
  1021.      *
  1022.      * @return mixed Returns a PEAR_Error with an error message on any
  1023.      *                kind of failure, or true on success.
  1024.      * @access public
  1025.      * @since  1.2.6
  1026.      */
  1027.     function samlFrom($path)
  1028.     {
  1029.         if (PEAR::isError($error $this->_put('SAML'"FROM:<$path>"))) {
  1030.             return $error;
  1031.         }
  1032.         if (PEAR::isError($error $this->_parseResponse(250$this->pipelining))) {
  1033.             return $error;
  1034.         }
  1035.  
  1036.         return true;
  1037.     }
  1038.  
  1039.     /**
  1040.      * Backwards-compatibility wrapper for samlFrom().
  1041.      *
  1042.      * @param string The reverse path to send.
  1043.      *
  1044.      * @return mixed Returns a PEAR_Error with an error message on any
  1045.      *                kind of failure, or true on success.
  1046.      *
  1047.      * @access      public
  1048.      * @since       1.0
  1049.      * @deprecated  1.2.6
  1050.      */
  1051.     function saml_from($path)
  1052.     {
  1053.         return samlFrom($path);
  1054.     }
  1055.  
  1056.     /**
  1057.      * Send the RSET command.
  1058.      *
  1059.      * @return mixed Returns a PEAR_Error with an error message on any
  1060.      *                kind of failure, or true on success.
  1061.      * @access public
  1062.      * @since  1.0
  1063.      */
  1064.     function rset()
  1065.     {
  1066.         if (PEAR::isError($error $this->_put('RSET'))) {
  1067.             return $error;
  1068.         }
  1069.         if (PEAR::isError($error $this->_parseResponse(250$this->pipelining))) {
  1070.             return $error;
  1071.         }
  1072.  
  1073.         return true;
  1074.     }
  1075.  
  1076.     /**
  1077.      * Send the VRFY command.
  1078.      *
  1079.      * @param string The string to verify
  1080.      *
  1081.      * @return mixed Returns a PEAR_Error with an error message on any
  1082.      *                kind of failure, or true on success.
  1083.      * @access public
  1084.      * @since  1.0
  1085.      */
  1086.     function vrfy($string)
  1087.     {
  1088.         /* Note: 251 is also a valid response code */
  1089.         if (PEAR::isError($error $this->_put('VRFY'$string))) {
  1090.             return $error;
  1091.         }
  1092.         if (PEAR::isError($error $this->_parseResponse(array(250252)))) {
  1093.             return $error;
  1094.         }
  1095.  
  1096.         return true;
  1097.     }
  1098.  
  1099.     /**
  1100.      * Send the NOOP command.
  1101.      *
  1102.      * @return mixed Returns a PEAR_Error with an error message on any
  1103.      *                kind of failure, or true on success.
  1104.      * @access public
  1105.      * @since  1.0
  1106.      */
  1107.     function noop()
  1108.     {
  1109.         if (PEAR::isError($error $this->_put('NOOP'))) {
  1110.             return $error;
  1111.         }
  1112.         if (PEAR::isError($error $this->_parseResponse(250))) {
  1113.             return $error;
  1114.         }
  1115.  
  1116.         return true;
  1117.     }
  1118.  
  1119.     /**
  1120.      * Backwards-compatibility method.  identifySender()'s functionality is
  1121.      * now handled internally.
  1122.      *
  1123.      * @return  boolean     This method always return true.
  1124.      *
  1125.      * @access  public
  1126.      * @since   1.0
  1127.      */
  1128.     function identifySender()
  1129.     {
  1130.         return true;
  1131.     }
  1132.  
  1133. }

Documentation generated on Mon, 11 Mar 2019 15:32:21 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.