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

Source for file LMTP.php

Documentation is available at LMTP.php

  1. <?php
  2. //
  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: Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>      |
  17. // |          Chuck Hagenbuch <chuck@horde.org>                           |
  18. // |          Jon Parise <jon@php.net>                                    |
  19. // |                                                                      |
  20. // +----------------------------------------------------------------------+
  21.  
  22. require_once 'Net/Socket.php';
  23.  
  24. /**
  25.  * Provides an implementation of the LMTP protocol using PEAR's
  26.  * Net_Socket:: class.
  27.  *
  28.  * @package Net_LMTP
  29.  * @author  Chuck Hagenbuch <chuck@horde.org>
  30.  * @author  Jon Parise <jon@php.net>
  31.  * @author  Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>
  32.  */
  33. class Net_LMTP {
  34.  
  35.  
  36.     /**
  37.      * The server to connect to.
  38.      * @var string 
  39.      */
  40.     var $_host;
  41.  
  42.     /**
  43.      * The port to connect to.
  44.      * @var int 
  45.      */
  46.     var $_port;
  47.  
  48.     /**
  49.      * The value to give when sending LHLO.
  50.      * @var string 
  51.      */
  52.     var $_localhost;
  53.  
  54.     /**
  55.      * Should debugging output be enabled?
  56.      * @var boolean 
  57.      * @access private
  58.      */
  59.     var $_debug = false;
  60.  
  61.     /**
  62.      * The socket resource being used to connect to the LMTP server.
  63.      * @var resource 
  64.      * @access private
  65.      */
  66.     var $_socket = null;
  67.  
  68.     /**
  69.      * The most recent server response code.
  70.      * @var int 
  71.      * @access private
  72.      */
  73.     var $_code = -1;
  74.  
  75.     /**
  76.      * The most recent server response arguments.
  77.      * @var array 
  78.      * @access private
  79.      */
  80.     var $_arguments = array();
  81.  
  82.     /**
  83.      * Stores detected features of the LMTP server.
  84.      * @var array 
  85.      * @access private
  86.      */
  87.     var $_esmtp = array();
  88.  
  89.  
  90.    /**
  91.     * The auth methods this class support
  92.     * @var array 
  93.     */
  94.     var $supportedAuthMethods=array('DIGEST-MD5''CRAM-MD5''LOGIN');
  95.  
  96.  
  97.     /**
  98.     * The auth methods this class support
  99.     * @var array 
  100.     */
  101.     var $supportedSASLAuthMethods=array('DIGEST-MD5''CRAM-MD5');
  102.  
  103.  
  104.  
  105.  
  106.     /**
  107.      * Instantiates a new Net_LMTP object, overriding any defaults
  108.      * with parameters that are passed in.
  109.      *
  110.      * @param string The server to connect to.
  111.      * @param int The port to connect to.
  112.      * @param string The value to give when sending LHLO.
  113.      *
  114.      * @access  public
  115.      * @since   1.0
  116.      */
  117.     function Net_LMTP($host 'localhost'$port = 2003$localhost 'localhost')
  118.     {
  119.         $this->_host $host;
  120.         $this->_port $port;
  121.         $this->_localhost $localhost;
  122.         $this->_socket = new Net_Socket();
  123.  
  124.        if ((@include_once 'Auth/SASL.php'== false{
  125.             foreach($this->supportedSASLAuthMethods as $SASLMethod){
  126.                 $pos array_search$SASLMethod $this->supportedAuthMethods);
  127.                 unset($this->supportedAuthMethods[$pos]);
  128.             }
  129.         }
  130.  
  131.  
  132.     }
  133.  
  134.     /**
  135.      * Set the value of the debugging flag.
  136.      *
  137.      * @param   boolean $debug      New value for the debugging flag.
  138.      *
  139.      * @access  public
  140.      * @since   1.0
  141.      */
  142.     function setDebug($debug)
  143.     {
  144.         $this->_debug $debug;
  145.     }
  146.  
  147.     /**
  148.      * Send the given string of data to the server.
  149.      *
  150.      * @param   string  $data       The string of data to send.
  151.      *
  152.      * @return  mixed   True on success or a PEAR_Error object on failure.
  153.      *
  154.      * @access  private
  155.      * @since   1.0
  156.      */
  157.     function _send($data)
  158.     {
  159.         if ($this->_debug{
  160.             echo "DEBUG: Send: $data\n";
  161.         }
  162.  
  163.         if (PEAR::isError($error $this->_socket->write($data))) {
  164.             return new PEAR_Error('Failed to write to socket: ' .
  165.                                   $error->getMessage());
  166.         }
  167.  
  168.         return true;
  169.     }
  170.  
  171.     /**
  172.      * Send a command to the server with an optional string of arguments.
  173.      * A carriage return / linefeed (CRLF) sequence will be appended to each
  174.      * command string before it is sent to the LMTP server.
  175.      *
  176.      * @param   string  $command    The LMTP command to send to the server.
  177.      * @param   string  $args       A string of optional arguments to append
  178.      *                               to the command.
  179.      *
  180.      * @return  mixed   The result of the _send() call.
  181.      *
  182.      * @access  private
  183.      * @since   1.0
  184.      */
  185.     function _put($command$args '')
  186.     {
  187.         if (!empty($args)) {
  188.             return $this->_send($command ' ' $args "\r\n");
  189.         }
  190.  
  191.         return $this->_send($command "\r\n");
  192.     }
  193.  
  194.     /**
  195.      * Read a reply from the LMTP server.  The reply consists of a response
  196.      * code and a response message.
  197.      *
  198.      * @param   mixed   $valid      The set of valid response codes.  These
  199.      *                               may be specified as an array of integer
  200.      *                               values or as a single integer value.
  201.      *
  202.      * @return  mixed   True if the server returned a valid response code or
  203.      *                   a PEAR_Error object is an error condition is reached.
  204.      *
  205.      * @access  private
  206.      * @since   1.0
  207.      *
  208.      * @see     getResponse
  209.      */
  210.     function _parseResponse($valid)
  211.     {
  212.         $this->_code = -1;
  213.         $this->_arguments = array();
  214.  
  215.         while ($line $this->_socket->readLine()) {
  216.             if ($this->_debug{
  217.                 echo "DEBUG: Recv: $line\n";
  218.             }
  219.  
  220.             /* If we receive an empty line, the connection has been closed. */
  221.             if (empty($line)) {
  222.                 $this->disconnect();
  223.                 return new PEAR_Error("Connection was unexpectedly closed");
  224.             }
  225.  
  226.             /* Read the code and store the rest in the arguments array. */
  227.             $code substr($line03);
  228.             $this->_arguments[trim(substr($line4));
  229.  
  230.             /* Check the syntax of the response code. */
  231.             if (is_numeric($code)) {
  232.                 $this->_code = (int)$code;
  233.             else {
  234.                 $this->_code = -1;
  235.                 break;
  236.             }
  237.  
  238.             /* If this is not a multiline response, we're done. */
  239.             if (substr($line31!= '-'{
  240.                 break;
  241.             }
  242.         }
  243.  
  244.         /* Compare the server's response code with the valid code. */
  245.         if (is_int($valid&& ($this->_code === $valid)) {
  246.             return true;
  247.         }
  248.  
  249.         /* If we were given an array of valid response codes, check each one. */
  250.         if (is_array($valid)) {
  251.             foreach ($valid as $valid_code{
  252.                 if ($this->_code === $valid_code{
  253.                     return true;
  254.                 }
  255.             }
  256.         }
  257.  
  258.         return new PEAR_Error("Invalid response code received from server");
  259.     }
  260.  
  261.     /**
  262.      * Return a 2-tuple containing the last response from the LMTP server.
  263.      *
  264.      * @return  array   A two-element array: the first element contains the
  265.      *                   response code as an integer and the second element
  266.      *                   contains the response's arguments as a string.
  267.      *
  268.      * @access  public
  269.      * @since   1.0
  270.      */
  271.     function getResponse()
  272.     {
  273.         return array($this->_codejoin("\n"$this->_arguments));
  274.     }
  275.  
  276.     /**
  277.      * Attempt to connect to the LMTP server.
  278.      *
  279.      * @param   int     $timeout    The timeout value (in seconds) for the
  280.      *                               socket connection.
  281.      *
  282.      * @return mixed Returns a PEAR_Error with an error message on any
  283.      *                kind of failure, or true on success.
  284.      * @access public
  285.      * @since  1.0
  286.      */
  287.     function connect($timeout = null)
  288.     {
  289.         $result $this->_socket->connect($this->_host$this->_port,
  290.                                           false$timeout);
  291.         if (PEAR::isError($result)) {
  292.             return new PEAR_Error('Failed to connect socket: ' .
  293.                                   $result->getMessage());
  294.         }
  295.  
  296.         if (PEAR::isError($error $this->_parseResponse(220))) {
  297.             return $error;
  298.         }
  299.         if (PEAR::isError($error $this->_negotiate())) {
  300.             return $error;
  301.         }
  302.  
  303.         return true;
  304.     }
  305.  
  306.     /**
  307.      * Attempt to disconnect from the LMTP server.
  308.      *
  309.      * @return mixed Returns a PEAR_Error with an error message on any
  310.      *                kind of failure, or true on success.
  311.      * @access public
  312.      * @since  1.0
  313.      */
  314.     function disconnect()
  315.     {
  316.         if (PEAR::isError($error $this->_put('QUIT'))) {
  317.             return $error;
  318.         }
  319.         if (PEAR::isError($error $this->_parseResponse(221))) {
  320.             return $error;
  321.         }
  322.         if (PEAR::isError($error $this->_socket->disconnect())) {
  323.             return new PEAR_Error('Failed to disconnect socket: ' .
  324.                                   $error->getMessage());
  325.         }
  326.  
  327.         return true;
  328.     }
  329.  
  330.     /**
  331.      * Attempt to send the LHLO command and obtain a list of ESMTP
  332.      * extensions available
  333.      *
  334.      * @return mixed Returns a PEAR_Error with an error message on any
  335.      *                kind of failure, or true on success.
  336.      *
  337.      * @access private
  338.      * @since  1.0
  339.      */
  340.     function _negotiate()
  341.     {
  342.         if (PEAR::isError($error $this->_put('LHLO'$this->_localhost))) {
  343.             return $error;
  344.         }
  345.  
  346.         if (PEAR::isError($this->_parseResponse(250))) {
  347.             return new PEAR_Error('LHLO was not accepted: '$this->_code);
  348.             return true;
  349.         }
  350.  
  351.         foreach ($this->_arguments as $argument{
  352.             $verb strtok($argument' ');
  353.             $arguments substr($argumentstrlen($verb+ 1,
  354.                                 strlen($argumentstrlen($verb- 1);
  355.             $this->_esmtp[$verb$arguments;
  356.         }
  357.  
  358.         return true;
  359.     }
  360.  
  361.     /**
  362.      * Returns the name of the best authentication method that the server
  363.      * has advertised.
  364.      *
  365.      * @return mixed    Returns a string containing the name of the best
  366.      *                   supported authentication method or a PEAR_Error object
  367.      *                   if a failure condition is encountered.
  368.      * @access private
  369.      * @since  1.0
  370.      */
  371.     function _getBestAuthMethod()
  372.     {
  373.         $available_methods explode(' '$this->_esmtp['AUTH']);
  374.  
  375.         foreach ($this->supportedAuthMethods as $method{
  376.             if (in_array($method$available_methods)) {
  377.                 return $method;
  378.             }
  379.         }
  380.  
  381.         return new PEAR_Error('No supported authentication methods');
  382.     }
  383.  
  384.     /**
  385.      * Attempt to do LMTP authentication.
  386.      *
  387.      * @param string The userid to authenticate as.
  388.      * @param string The password to authenticate with.
  389.      * @param string The requested authentication method.  If none is
  390.      *                specified, the best supported method will be used.
  391.      *
  392.      * @return mixed Returns a PEAR_Error with an error message on any
  393.      *                kind of failure, or true on success.
  394.      * @access public
  395.      * @since  1.0
  396.      */
  397.     function auth($uid$pwd $method '')
  398.     {
  399.         if (!array_key_exists('AUTH'$this->_esmtp)) {
  400.             if (!version_compare(PHP_VERSION'5.1.0''>=')) {
  401.                 return new PEAR_Error('LMTP server does no support authentication');
  402.             }
  403.  
  404.             if (!isset($this->_esmtp['STARTTLS'])) {
  405.                 return PEAR::raiseError('LMTP server does not support authentication');
  406.             }
  407.  
  408.             if (PEAR::isError($result $this->_put('STARTTLS'))) {
  409.                 return $result;
  410.             }
  411.  
  412.             if (PEAR::isError($result $this->_parseResponse(220))) {
  413.                 return $result;
  414.             }
  415.  
  416.             if (PEAR::isError($result $this->_socket->enableCrypto(trueSTREAM_CRYPTO_METHOD_TLS_CLIENT))) {
  417.                 return $result;
  418.             elseif ($result !== true{
  419.                 return PEAR::raiseError('STARTTLS failed');
  420.             }
  421.  
  422.             /* Send LHLO again to recieve the AUTH string from the
  423.              * LMTP server. */
  424.             $this->_negotiate();
  425.             if (empty($this->_esmtp['AUTH'])) {
  426.                 return PEAR::raiseError('LMTP server does not support authentication');
  427.             }
  428.         }
  429.  
  430.         /*
  431.          * If no method has been specified, get the name of the best supported
  432.          * method advertised by the LMTP server.
  433.          */
  434.         if (empty($method|| $method === true {
  435.             if (PEAR::isError($method $this->_getBestAuthMethod())) {
  436.                 /* Return the PEAR_Error object from _getBestAuthMethod(). */
  437.                 return $method;
  438.             
  439.         else {
  440.             $method strtoupper($method);
  441.         }
  442.  
  443.         switch ($method{
  444.             case 'DIGEST-MD5':
  445.                 $result $this->_authDigest_MD5($uid$pwd);
  446.                 break;
  447.             case 'CRAM-MD5':
  448.                 $result $this->_authCRAM_MD5($uid$pwd);
  449.                 break;
  450.             case 'LOGIN':
  451.                 $result $this->_authLogin($uid$pwd);
  452.                 break;
  453.             case 'PLAIN':
  454.                 $result $this->_authPlain($uid$pwd);
  455.                 break;
  456.             default : 
  457.                 $result = new PEAR_Error("$method is not a supported authentication method");
  458.                 break;
  459.         }
  460.  
  461.         /* If an error was encountered, return the PEAR_Error object. */
  462.         if (PEAR::isError($result)) {
  463.             return $result;
  464.         }
  465.  
  466.         /* RFC-2554 requires us to re-negotiate ESMTP after an AUTH. */
  467.         if (PEAR::isError($error $this->_negotiate())) {
  468.             return $error;
  469.         }
  470.  
  471.         return true;
  472.     }
  473.  
  474.     /* Authenticates the user using the DIGEST-MD5 method.
  475.      *
  476.      * @param string The userid to authenticate as.
  477.      * @param string The password to authenticate with.
  478.      *
  479.      * @return mixed Returns a PEAR_Error with an error message on any
  480.      *               kind of failure, or true on success.
  481.      * @access private
  482.      * @since  1.0
  483.      */
  484.     function _authDigest_MD5($uid$pwd)
  485.     {
  486.  
  487.  
  488.         if (PEAR::isError($error $this->_put('AUTH''DIGEST-MD5'))) {
  489.             return $error;
  490.         }
  491.         if (PEAR::isError($error $this->_parseResponse(334))) {
  492.             return $error;
  493.         }
  494.  
  495.         $challenge base64_decode($this->_arguments[0]);
  496.         $digest &Auth_SASL::factory('digestmd5');
  497.         $auth_str base64_encode($digest->getResponse($uid$pwd$challenge,
  498.                                                        $this->_host"smtp"));
  499.  
  500.         if (PEAR::isError($error $this->_put($auth_str ))) {
  501.             return $error;
  502.         }
  503.         if (PEAR::isError($error $this->_parseResponse(334))) {
  504.             return $error;
  505.         }
  506.  
  507.         /*
  508.          * We don't use the protocol's third step because LMTP doesn't allow
  509.          * subsequent authentication, so we just silently ignore it.
  510.          */
  511.         if (PEAR::isError($error $this->_put(' '))) {
  512.             return $error;
  513.         }
  514.         if (PEAR::isError($error $this->_parseResponse(235))) {
  515.             return $error;
  516.         }
  517.     }
  518.  
  519.     /* Authenticates the user using the CRAM-MD5 method.
  520.      *
  521.      * @param string The userid to authenticate as.
  522.      * @param string The password to authenticate with.
  523.      *
  524.      * @return mixed Returns a PEAR_Error with an error message on any
  525.      *               kind of failure, or true on success.
  526.      * @access private
  527.      * @since  1.0
  528.      */
  529.     function _authCRAM_MD5($uid$pwd)
  530.     {
  531.  
  532.  
  533.         if (PEAR::isError($error $this->_put('AUTH''CRAM-MD5'))) {
  534.             return $error;
  535.         }
  536.         if (PEAR::isError($error $this->_parseResponse(334))) {
  537.             return $error;
  538.         }
  539.  
  540.         $challenge base64_decode($this->_arguments[0]);
  541.         $cram &Auth_SASL::factory('crammd5');
  542.         $auth_str base64_encode($cram->getResponse($uid$pwd$challenge));
  543.  
  544.         if (PEAR::isError($error $this->_put($auth_str))) {
  545.             return $error;
  546.         }
  547.         if (PEAR::isError($error $this->_parseResponse(235))) {
  548.             return $error;
  549.         }
  550.     }
  551.  
  552.     /**
  553.      * Authenticates the user using the LOGIN method.
  554.      *
  555.      * @param string The userid to authenticate as.
  556.      * @param string The password to authenticate with.
  557.      *
  558.      * @return mixed Returns a PEAR_Error with an error message on any
  559.      *                kind of failure, or true on success.
  560.      * @access private
  561.      * @since  1.0
  562.      */
  563.     function _authLogin($uid$pwd)
  564.     {
  565.         if (PEAR::isError($error $this->_put('AUTH''LOGIN'))) 
  566.             return $error;
  567.         }
  568.         if (PEAR::isError($error $this->_parseResponse(334))) {
  569.             return $error;
  570.         }
  571.  
  572.         if (PEAR::isError($error $this->_put(base64_encode($uid)))) {
  573.             return $error;
  574.         }
  575.         if (PEAR::isError($error $this->_parseResponse(334))) {
  576.             return $error;
  577.         }
  578.  
  579.         if (PEAR::isError($error $this->_put(base64_encode($pwd)))) {
  580.             return $error;
  581.         }
  582.         if (PEAR::isError($error $this->_parseResponse(235))) {
  583.             return $error;
  584.         }
  585.  
  586.         return true;
  587.     }
  588.  
  589.     /**
  590.      * Authenticates the user using the PLAIN method.
  591.      *
  592.      * @param string The userid to authenticate as.
  593.      * @param string The password to authenticate with.
  594.      *
  595.      * @return mixed Returns a PEAR_Error with an error message on any
  596.      *                kind of failure, or true on success.
  597.      * @access private
  598.      * @since  1.0
  599.      */
  600.     function _authPlain($uid$pwd)
  601.     {
  602.         if (PEAR::isError($error $this->_put('AUTH''PLAIN'))) {
  603.             return $error;
  604.         }
  605.         if (PEAR::isError($error $this->_parseResponse(334))) {
  606.             return $error;
  607.         }
  608.  
  609.         $auth_str base64_encode(chr(0$uid chr(0$pwd);
  610.  
  611.         if (PEAR::isError($error $this->_put($auth_str))) {
  612.             return $error;
  613.         }
  614.         if (PEAR::isError($error $this->_parseResponse(235))) {
  615.             return $error;
  616.         }
  617.  
  618.         return true;
  619.     }
  620.  
  621.     /**
  622.      * Send the MAIL FROM: command.
  623.      *
  624.      * @param string The sender (reverse path) to set.
  625.      *
  626.      * @return mixed Returns a PEAR_Error with an error message on any
  627.      *                kind of failure, or true on success.
  628.      * @access public
  629.      * @since  1.0
  630.      */
  631.     function mailFrom($sender)
  632.     {
  633.         if (PEAR::isError($error $this->_put('MAIL'"FROM:<$sender>"))) {
  634.             return $error;
  635.         }
  636.         if (PEAR::isError($error $this->_parseResponse(250))) {
  637.             return $error;
  638.         }
  639.  
  640.         return true;
  641.     }
  642.  
  643.     /**
  644.      * Send the RCPT TO: command.
  645.      *
  646.      * @param string The recipient (forward path) to add.
  647.      *
  648.      * @return mixed Returns a PEAR_Error with an error message on any
  649.      *                kind of failure, or true on success.
  650.      * @access public
  651.      * @since  1.0
  652.      */
  653.     function rcptTo($recipient)
  654.     {
  655.         if (PEAR::isError($error $this->_put('RCPT'"TO:<$recipient>"))) {
  656.             return $error;
  657.         }
  658.         if (PEAR::isError($error $this->_parseResponse(array(250251)))) {
  659.             return $error;
  660.         }
  661.  
  662.         return true;
  663.     }
  664.  
  665.     /**
  666.      * Send the DATA command.
  667.      *
  668.      * @param string The message body to send.
  669.      *
  670.      * @return mixed Returns a PEAR_Error with an error message on any
  671.      *                kind of failure, or true on success.
  672.      * @access public
  673.      * @since  1.0
  674.      */
  675.     function data($data)
  676.     {
  677.  
  678.         if (isset($this->_esmtp['SIZE']&& ($this->_esmtp['SIZE'> 0)) {
  679.             if (strlen($data>= $this->_esmtp['SIZE']{
  680.                 $this->disconnect();
  681.                 return new PEAR_Error('Message size excedes the server limit');
  682.             }
  683.         }
  684.     
  685.  
  686.         /*
  687.          * Change Unix (\n) and Mac (\r) linefeeds into Internet-standard CRLF
  688.          * (\r\n) linefeeds.
  689.          */
  690.         $data preg_replace("/([^\r]{1})\n/""\\1\r\n"$data);
  691.         $data preg_replace("/\n\n/""\n\r\n"$data);
  692.  
  693.         /*
  694.          * Because a single leading period (.) signifies an end to the data,
  695.          * legitimate leading periods need to be "doubled" (e.g. '..').
  696.          */
  697.         $data preg_replace("/\n\./""\n.."$data);
  698.  
  699.         if (PEAR::isError($error $this->_put('DATA'))) {
  700.             return $error;
  701.         }
  702.         if (PEAR::isError($error $this->_parseResponse(354))) {
  703.             return $error;
  704.         }
  705.  
  706.         if (PEAR::isError($this->_send($data "\r\n.\r\n"))) {
  707.             return new PEAR_Error('write to socket failed');
  708.         }
  709.         if (PEAR::isError($error $this->_parseResponse(250))) {
  710.             return $error;
  711.         }
  712.  
  713.         return true;
  714.     }
  715.  
  716.     /**
  717.      * Send the RSET command.
  718.      *
  719.      * @return mixed Returns a PEAR_Error with an error message on any
  720.      *                kind of failure, or true on success.
  721.      * @access public
  722.      * @since  1.0
  723.      */
  724.     function rset()
  725.     {
  726.         if (PEAR::isError($error $this->_put('RSET'))) {
  727.             return $error;
  728.         }
  729.         if (PEAR::isError($error $this->_parseResponse(250))) {
  730.             return $error;
  731.         }
  732.  
  733.         return true;
  734.     }
  735.     /**
  736.      * Send the NOOP command.
  737.      *
  738.      * @return mixed Returns a PEAR_Error with an error message on any
  739.      *                kind of failure, or true on success.
  740.      * @access public
  741.      * @since  1.0
  742.      */
  743.     function noop()
  744.     {
  745.         if (PEAR::isError($error $this->_put('NOOP'))) {
  746.             return $error;
  747.         }
  748.         if (PEAR::isError($error $this->_parseResponse(250))) {
  749.             return $error;
  750.         }
  751.  
  752.         return true;
  753.     }
  754. }
  755.  
  756. ?>

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