Changeset 3875eb6 in github


Ignore:
Timestamp:
Nov 24, 2011 5:54:59 AM (18 months ago)
Author:
alecpl <alec@…>
Branches:
master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.8
Children:
e4a4ca19
Parents:
f4cfb14
Message:
  • Add possibility to add SASL mechanisms for SMTP in smtp_connect hook (#1487937)
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • CHANGELOG

    r636bd77 r3875eb6  
    22=========================== 
    33 
     4- Add possibility to add SASL mechanisms for SMTP in smtp_connect hook (#1487937) 
    45- Mark (with different color) folders with recent messages (#1486234) 
    56- Fix possible infinite redirect on attachment preview (#1488199) 
  • program/include/rcube_smtp.php

    rfb40f37 r3875eb6  
    5151  { 
    5252    $RCMAIL = rcmail::get_instance(); 
    53    
     53 
    5454    // disconnect/destroy $this->conn 
    5555    $this->disconnect(); 
    56      
     56 
    5757    // reset error/response var 
    5858    $this->error = $this->response = null; 
    59    
     59 
    6060    // let plugins alter smtp connection config 
    6161    $CONFIG = $RCMAIL->plugins->exec_hook('smtp_connect', array( 
     
    6969      'smtp_helo_host' => $RCMAIL->config->get('smtp_helo_host'), 
    7070      'smtp_timeout'   => $RCMAIL->config->get('smtp_timeout'), 
     71      'smtp_auth_callbacks' => array(), 
    7172    )); 
    7273 
     
    108109    if ($RCMAIL->config->get('smtp_debug')) 
    109110      $this->conn->setDebug(true, array($this, 'debug_handler')); 
     111 
     112    // register authentication methods 
     113    if (!empty($CONFIG['smtp_auth_callbacks']) && method_exists($this->conn, 'setAuthMethod')) { 
     114      foreach ($CONFIG['smtp_auth_callbacks'] as $callback) { 
     115        $this->conn->setAuthMethod($callback['name'], $callback['function'], 
     116          isset($callback['prepend']) ? $callback['prepend'] : true); 
     117      } 
     118    } 
    110119 
    111120    // try to connect to server and exit on failure 
  • program/lib/Net/SMTP.php

    r462de2d r3875eb6  
    6363     * @access public 
    6464     */ 
    65     var $auth_methods = array('DIGEST-MD5', 'CRAM-MD5', 'LOGIN', 'PLAIN'); 
     65    var $auth_methods = array(); 
    6666 
    6767    /** 
     
    188188        $this->_timeout = $timeout; 
    189189 
    190         /* Include the Auth_SASL package.  If the package is not 
    191          * available, we disable the authentication methods that 
    192          * depend upon it. */ 
    193         if ((@include_once 'Auth/SASL.php') === false) { 
    194             $pos = array_search('DIGEST-MD5', $this->auth_methods); 
    195             unset($this->auth_methods[$pos]); 
    196             $pos = array_search('CRAM-MD5', $this->auth_methods); 
    197             unset($this->auth_methods[$pos]); 
    198         } 
     190        /* Include the Auth_SASL package.  If the package is available, we  
     191         * enable the authentication methods that depend upon it. */ 
     192        if ((@include_once 'Auth/SASL.php') === true) { 
     193            $this->setAuthMethod('CRAM-MD5', array($this, '_authCram_MD5')); 
     194            $this->setAuthMethod('DIGEST-MD5', array($this, '_authDigest_MD5')); 
     195        } 
     196 
     197        /* These standard authentication methods are always available. */ 
     198        $this->setAuthMethod('LOGIN', array($this, '_authLogin'), false); 
     199        $this->setAuthMethod('PLAIN', array($this, '_authPlain'), false); 
    199200    } 
    200201 
     
    251252     * @param   string  $data       The string of data to send. 
    252253     * 
    253      * @return  mixed   True on success or a PEAR_Error object on failure. 
     254     * @return  mixed   The number of bytes that were actually written, 
     255     *                  or a PEAR_Error object on failure. 
    254256     * 
    255257     * @access  private 
     
    260262        $this->_debug("Send: $data"); 
    261263 
    262         $error = $this->_socket->write($data); 
    263         if ($error === false || PEAR::isError($error)) { 
    264             $msg = ($error) ? $error->getMessage() : "unknown error"; 
    265             return PEAR::raiseError("Failed to write to socket: $msg"); 
    266         } 
    267  
    268         return true; 
     264        $result = $this->_socket->write($data); 
     265        if (!$result || PEAR::isError($result)) { 
     266            $msg = ($result) ? $result->getMessage() : "unknown error"; 
     267            return PEAR::raiseError("Failed to write to socket: $msg", 
     268                                    null, PEAR_ERROR_RETURN); 
     269        } 
     270 
     271        return $result; 
    269272    } 
    270273 
     
    293296 
    294297        if (strcspn($command, "\r\n") !== strlen($command)) { 
    295             return PEAR::raiseError('Commands cannot contain newlines'); 
     298            return PEAR::raiseError('Commands cannot contain newlines', 
     299                                    null, PEAR_ERROR_RETURN); 
    296300        } 
    297301 
     
    332336                $this->_debug("Recv: $line"); 
    333337 
    334                 /* If we receive an empty line, the connection has been closed. */ 
     338                /* If we receive an empty line, the connection was closed. */ 
    335339                if (empty($line)) { 
    336340                    $this->disconnect(); 
    337                     return PEAR::raiseError('Connection was unexpectedly closed'); 
     341                    return PEAR::raiseError('Connection was closed', 
     342                                            null, PEAR_ERROR_RETURN); 
    338343                } 
    339344 
     
    367372 
    368373        return PEAR::raiseError('Invalid response code received from server', 
    369                                 $this->_code); 
     374                                $this->_code, PEAR_ERROR_RETURN); 
     375    } 
     376 
     377    /** 
     378     * Issue an SMTP command and verify its response. 
     379     * 
     380     * @param   string  $command    The SMTP command string or data. 
     381     * @param   mixed   $valid      The set of valid response codes.  These 
     382     *                              may be specified as an array of integer 
     383     *                              values or as a single integer value. 
     384     * 
     385     * @return  mixed   True on success or a PEAR_Error object on failure. 
     386     * 
     387     * @access  public 
     388     * @since   1.6.0 
     389     */ 
     390    function command($command, $valid) 
     391    { 
     392        if (PEAR::isError($error = $this->_put($command))) { 
     393            return $error; 
     394        } 
     395        if (PEAR::isError($error = $this->_parseResponse($valid))) { 
     396            return $error; 
     397        } 
     398 
     399        return true; 
    370400    } 
    371401 
     
    500530            } 
    501531            if (PEAR::isError($this->_parseResponse(250))) { 
    502                 return PEAR::raiseError('HELO was not accepted: ', $this->_code); 
     532                return PEAR::raiseError('HELO was not accepted: ', $this->_code, 
     533                                        PEAR_ERROR_RETURN); 
    503534            } 
    504535 
     
    534565        $available_methods = explode(' ', $this->_esmtp['AUTH']); 
    535566 
    536         foreach ($this->auth_methods as $method) { 
     567        foreach ($this->auth_methods as $method => $callback) { 
    537568            if (in_array($method, $available_methods)) { 
    538569                return $method; 
     
    540571        } 
    541572 
    542         return PEAR::raiseError('No supported authentication methods'); 
     573        return PEAR::raiseError('No supported authentication methods', 
     574                                null, PEAR_ERROR_RETURN); 
    543575    } 
    544576 
     
    600632        } else { 
    601633            $method = strtoupper($method); 
    602             if (!in_array($method, $this->auth_methods)) { 
     634            if (!array_key_exists($method, $this->auth_methods)) { 
    603635                return PEAR::raiseError("$method is not a supported authentication method"); 
    604636            } 
    605637        } 
    606638 
    607         switch ($method) { 
    608         case 'DIGEST-MD5': 
    609             $result = $this->_authDigest_MD5($uid, $pwd, $authz); 
    610             break; 
    611  
    612         case 'CRAM-MD5': 
    613             $result = $this->_authCRAM_MD5($uid, $pwd); 
    614             break; 
    615  
    616         case 'LOGIN': 
    617             $result = $this->_authLogin($uid, $pwd); 
    618             break; 
    619  
    620         case 'PLAIN': 
    621             $result = $this->_authPlain($uid, $pwd, $authz); 
    622             break; 
    623  
    624         default: 
    625             $result = PEAR::raiseError("$method is not a supported authentication method"); 
    626             break; 
    627         } 
     639        if (!isset($this->auth_methods[$method])) { 
     640            return PEAR::raiseError("$method is not a supported authentication method"); 
     641        } 
     642 
     643        if (!is_callable($this->auth_methods[$method], false)) { 
     644            return PEAR::raiseError("$method authentication method cannot be called"); 
     645        } 
     646 
     647        if (is_array($this->auth_methods[$method])) { 
     648            list($object, $method) = $this->auth_methods[$method]; 
     649            $result = $object->{$method}($uid, $pwd, $authz, $this); 
     650        } else { 
     651            $func =  $this->auth_methods[$method]; 
     652            $result = $func($uid, $pwd, $authz, $this); 
     653         } 
    628654 
    629655        /* If an error was encountered, return the PEAR_Error object. */ 
    630656        if (PEAR::isError($result)) { 
    631657            return $result; 
     658        } 
     659 
     660        return true; 
     661    } 
     662 
     663    /** 
     664     * Add a new authentication method. 
     665     * 
     666     * @param string    The authentication method name (e.g. 'PLAIN') 
     667     * @param mixed     The authentication callback (given as the name of a  
     668     *                  function or as an (object, method name) array). 
     669     * @param bool      Should the new method be prepended to the list of  
     670     *                  available methods?  This is the default behavior,  
     671     *                  giving the new method the highest priority. 
     672     * 
     673     * @return  mixed   True on success or a PEAR_Error object on failure. 
     674     * 
     675     * @access public 
     676     * @since  1.6.0 
     677     */ 
     678    function setAuthMethod($name, $callback, $prepend = true) 
     679    { 
     680        if (!is_string($name)) { 
     681            return PEAR::raiseError('Method name is not a string'); 
     682        } 
     683 
     684        if (!is_string($callback) && !is_array($callback)) { 
     685            return PEAR::raiseError('Method callback must be string or array'); 
     686        } 
     687 
     688        if (is_array($callback)) { 
     689            if (!is_object($callback[0]) || !is_string($callback[1])) 
     690                return PEAR::raiseError('Bad mMethod callback array'); 
     691        } 
     692 
     693        if ($prepend) { 
     694            $this->auth_methods = array_merge(array($name => $callback), 
     695                                              $this->auth_methods); 
     696        } else { 
     697            $this->auth_methods[$name] = $callback; 
    632698        } 
    633699 
     
    692758     * @param string The userid to authenticate as. 
    693759     * @param string The password to authenticate with. 
     760     * @param string The optional authorization proxy identifier. 
    694761     * 
    695762     * @return mixed Returns a PEAR_Error with an error message on any 
     
    698765     * @since  1.1.0 
    699766     */ 
    700     function _authCRAM_MD5($uid, $pwd) 
     767    function _authCRAM_MD5($uid, $pwd, $authz = '') 
    701768    { 
    702769        if (PEAR::isError($error = $this->_put('AUTH', 'CRAM-MD5'))) { 
     
    731798     * @param string The userid to authenticate as. 
    732799     * @param string The password to authenticate with. 
     800     * @param string The optional authorization proxy identifier. 
    733801     * 
    734802     * @return mixed Returns a PEAR_Error with an error message on any 
     
    737805     * @since  1.1.0 
    738806     */ 
    739     function _authLogin($uid, $pwd) 
     807    function _authLogin($uid, $pwd, $authz = '') 
    740808    { 
    741809        if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) { 
     
    10131081             * connection, line by line.  Each line must be run through the  
    10141082             * quoting routine. */ 
    1015             while ($line = fgets($data, 1024)) { 
     1083            while (strlen($line = fread($data, 8192)) > 0) { 
     1084                /* If the last character is an newline, we need to grab the 
     1085                 * next character to check to see if it is a period. */ 
     1086                while (!feof($data)) { 
     1087                    $char = fread($data, 1); 
     1088                    $line .= $char; 
     1089                    if ($char != "\n") { 
     1090                        break; 
     1091                    } 
     1092                } 
    10161093                $this->quotedata($line); 
    10171094                if (PEAR::isError($result = $this->_send($line))) { 
Note: See TracChangeset for help on using the changeset viewer.