steffen: server/kolab-resource-handlers/kolab-resource-handlers/fbview/fbview/framework/Net_LMTP LMTP.php, NONE, 1.1 package.xml, NONE, 1.1 test_lmtp.php, NONE, 1.1

cvs at intevation.de cvs at intevation.de
Fri Aug 20 01:24:49 CEST 2004


Author: steffen

Update of /kolabrepository/server/kolab-resource-handlers/kolab-resource-handlers/fbview/fbview/framework/Net_LMTP
In directory doto:/tmp/cvs-serv19806/Net_LMTP

Added Files:
	LMTP.php package.xml test_lmtp.php 
Log Message:
copy of Net_LMTP

--- NEW FILE: LMTP.php ---
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4                                                        |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group                                |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license,      |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.php.net/license/2_02.txt.                                 |
// | If you did not receive a copy of the PHP license and are unable to   |
// | obtain it through the world-wide-web, please send a note to          |
// | license at php.net so we can mail you a copy immediately.               |
// +----------------------------------------------------------------------+
// | Authors: Damian Alejandro Fernandez Sosa <damlists at cnba.uba.ar>      |
// |          Chuck Hagenbuch <chuck at horde.org>                           |
// |          Jon Parise <jon at php.net>                                    |
// |                                                                      |
// +----------------------------------------------------------------------+

require_once 'Net/Socket.php';

/**
 * Provides an implementation of the LMTP protocol using PEAR's
 * Net_Socket:: class.
 *
 * @package Net_LMTP
 * @author  Chuck Hagenbuch <chuck at horde.org>
 * @author  Jon Parise <jon at php.net>
 * @author  Damian Alejandro Fernandez Sosa <damlists at cnba.uba.ar>
 */
class Net_LMTP {


    /**
     * The server to connect to.
     * @var string
     */
    var $_host;

    /**
     * The port to connect to.
     * @var int
     */
    var $_port;

    /**
     * The value to give when sending LHLO.
     * @var string
     */
    var $_localhost;

    /**
     * Should debugging output be enabled?
     * @var boolean
     * @access private
     */
    var $_debug = false;

    /**
     * The socket resource being used to connect to the LMTP server.
     * @var resource
     * @access private
     */
    var $_socket = null;

    /**
     * The most recent server response code.
     * @var int
     * @access private
     */
    var $_code = -1;

    /**
     * The most recent server response arguments.
     * @var array
     * @access private
     */
    var $_arguments = array();

    /**
     * Stores detected features of the LMTP server.
     * @var array
     * @access private
     */
    var $_esmtp = array();


   /**
    * The auth methods this class support
    * @var array
    */
    var $supportedAuthMethods=array('DIGEST-MD5', 'CRAM-MD5', 'LOGIN');


    /**
    * The auth methods this class support
    * @var array
    */
    var $supportedSASLAuthMethods=array('DIGEST-MD5', 'CRAM-MD5');




    /**
     * Instantiates a new Net_LMTP object, overriding any defaults
     * with parameters that are passed in.
     *
     * @param string The server to connect to.
     * @param int The port to connect to.
     * @param string The value to give when sending LHLO.
     *
     * @access  public
     * @since   1.0
     */
    function Net_LMTP($host = 'localhost', $port = 2003, $localhost = 'localhost')
    {
        $this->_host = $host;
        $this->_port = $port;
        $this->_localhost = $localhost;
        $this->_socket = new Net_Socket();

       if ((@include_once 'Auth/SASL.php') == false) {
            foreach($this->supportedSASLAuthMethods as $SASLMethod){
                $pos = array_search( $SASLMethod , $this->supportedAuthMethods);
                unset($this->supportedAuthMethods[$pos]);
            }
        }


    }

    /**
     * Set the value of the debugging flag.
     *
     * @param   boolean $debug      New value for the debugging flag.
     *
     * @access  public
     * @since   1.0
     */
    function setDebug($debug)
    {
        $this->_debug = $debug;
    }

    /**
     * Send the given string of data to the server.
     *
     * @param   string  $data       The string of data to send.
     *
     * @return  mixed   True on success or a PEAR_Error object on failure.
     *
     * @access  private
     * @since   1.0
     */
    function _send($data)
    {
        if ($this->_debug) {
            echo "DEBUG: Send: $data\n";
        }

        if (PEAR::isError($error = $this->_socket->write($data))) {
            return new PEAR_Error('Failed to write to socket: ' .
                                  $error->getMessage());
        }

        return true;
    }

    /**
     * Send a command to the server with an optional string of arguments.
     * A carriage return / linefeed (CRLF) sequence will be appended to each
     * command string before it is sent to the LMTP server.
     *
     * @param   string  $command    The LMTP command to send to the server.
     * @param   string  $args       A string of optional arguments to append
     *                              to the command.
     *
     * @return  mixed   The result of the _send() call.
     *
     * @access  private
     * @since   1.0
     */
    function _put($command, $args = '')
    {
        if (!empty($args)) {
            return $this->_send($command . ' ' . $args . "\r\n");
        }

        return $this->_send($command . "\r\n");
    }

    /**
     * Read a reply from the LMTP server.  The reply consists of a response
     * code and a response message.
     *
     * @param   mixed   $valid      The set of valid response codes.  These
     *                              may be specified as an array of integer
     *                              values or as a single integer value.
     *
     * @return  mixed   True if the server returned a valid response code or
     *                  a PEAR_Error object is an error condition is reached.
     *
     * @access  private
     * @since   1.0
     *
     * @see     getResponse
     */
    function _parseResponse($valid)
    {
        $this->_code = -1;
        $this->_arguments = array();

        while ($line = $this->_socket->readLine()) {
            if ($this->_debug) {
                echo "DEBUG: Recv: $line\n";
            }

            /* If we receive an empty line, the connection has been closed. */
            if (empty($line)) {
                $this->disconnect();
                return new PEAR_Error("Connection was unexpectedly closed");
            }

            /* Read the code and store the rest in the arguments array. */
            $code = substr($line, 0, 3);
            $this->_arguments[] = trim(substr($line, 4));

            /* Check the syntax of the response code. */
            if (is_numeric($code)) {
                $this->_code = (int)$code;
            } else {
                $this->_code = -1;
                break;
            }

            /* If this is not a multiline response, we're done. */
            if (substr($line, 3, 1) != '-') {
                break;
            }
        }

        /* Compare the server's response code with the valid code. */
        if (is_int($valid) && ($this->_code === $valid)) {
            return true;
        }

        /* If we were given an array of valid response codes, check each one. */
        if (is_array($valid)) {
            foreach ($valid as $valid_code) {
                if ($this->_code === $valid_code) {
                    return true;
                }
            }
        }

        return new PEAR_Error("Invalid response code received from server");
    }

    /**
     * Return a 2-tuple containing the last response from the LMTP server.
     *
     * @return  array   A two-element array: the first element contains the
     *                  response code as an integer and the second element
     *                  contains the response's arguments as a string.
     *
     * @access  public
     * @since   1.0
     */
    function getResponse()
    {
        return array($this->_code, join("\n", $this->_arguments));
    }

    /**
     * Attempt to connect to the LMTP server.
     *
     * @param   int     $timeout    The timeout value (in seconds) for the
     *                              socket connection.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access public
     * @since  1.0
     */
    function connect($timeout = null)
    {
        $result = $this->_socket->connect($this->_host, $this->_port,
                                          false, $timeout);
        if (PEAR::isError($result)) {
            return new PEAR_Error('Failed to connect socket: ' .
                                  $result->getMessage());
        }

        if (PEAR::isError($error = $this->_parseResponse(220))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_negotiate())) {
            return $error;
        }

        return true;
    }

    /**
     * Attempt to disconnect from the LMTP server.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access public
     * @since  1.0
     */
    function disconnect()
    {
        if (PEAR::isError($error = $this->_put('QUIT'))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(221))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_socket->disconnect())) {
            return new PEAR_Error('Failed to disconnect socket: ' .
                                  $error->getMessage());
        }

        return true;
    }

    /**
     * Attempt to send the LHLO command and obtain a list of ESMTP
     * extensions available
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     *
     * @access private
     * @since  1.0
     */
    function _negotiate()
    {
        if (PEAR::isError($error = $this->_put('LHLO', $this->_localhost))) {
            return $error;
        }

        if (PEAR::isError($this->_parseResponse(250))) {
            return new PEAR_Error('LHLO was not accepted: ', $this->_code);
            return true;
        }

        foreach ($this->_arguments as $argument) {
            $verb = strtok($argument, ' ');
            $arguments = substr($argument, strlen($verb) + 1,
                                strlen($argument) - strlen($verb) - 1);
            $this->_esmtp[$verb] = $arguments;
        }

        return true;
    }

    /**
     * Returns the name of the best authentication method that the server
     * has advertised.
     *
     * @return mixed    Returns a string containing the name of the best
     *                  supported authentication method or a PEAR_Error object
     *                  if a failure condition is encountered.
     * @access private
     * @since  1.0
     */
    function _getBestAuthMethod()
    {
        $available_methods = explode(' ', $this->_esmtp['AUTH']);

        foreach ($this->supportedAuthMethods as $method) {
            if (in_array($method, $available_methods)) {
                return $method;
            }
        }

        return new PEAR_Error('No supported authentication methods');
    }

    /**
     * Attempt to do LMTP authentication.
     *
     * @param string The userid to authenticate as.
     * @param string The password to authenticate with.
     * @param string The requested authentication method.  If none is
     *               specified, the best supported method will be used.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access public
     * @since  1.0
     */
    function auth($uid, $pwd , $method = '')
    {
        if (!array_key_exists('AUTH', $this->_esmtp)) {
            return new PEAR_Error('LMTP server does no support authentication');
        }

        /*
         * If no method has been specified, get the name of the best supported
         * method advertised by the LMTP server.
         */
        if (empty($method) || $method === true ) {
            if (PEAR::isError($method = $this->_getBestAuthMethod())) {
                /* Return the PEAR_Error object from _getBestAuthMethod(). */
                return $method;
            } 
        } else {
            $method = strtoupper($method);
        }

        switch ($method) {
            case 'DIGEST-MD5':
                $result = $this->_authDigest_MD5($uid, $pwd);
                break;
            case 'CRAM-MD5':
                $result = $this->_authCRAM_MD5($uid, $pwd);
                break;
            case 'LOGIN':
                $result = $this->_authLogin($uid, $pwd);
                break;
            case 'PLAIN':
                $result = $this->_authPlain($uid, $pwd);
                break;
            default : 
                $result = new PEAR_Error("$method is not a supported authentication method");
                break;
        }

        /* If an error was encountered, return the PEAR_Error object. */
        if (PEAR::isError($result)) {
            return $result;
        }

        /* RFC-2554 requires us to re-negotiate ESMTP after an AUTH. */
        if (PEAR::isError($error = $this->_negotiate())) {
            return $error;
        }

        return true;
    }

    /* Authenticates the user using the DIGEST-MD5 method.
     *
     * @param string The userid to authenticate as.
     * @param string The password to authenticate with.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access private
     * @since  1.0
     */
    function _authDigest_MD5($uid, $pwd)
    {


        if (PEAR::isError($error = $this->_put('AUTH', 'DIGEST-MD5'))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(334))) {
            return $error;
        }

        $challenge = base64_decode($this->_arguments[0]);
        $digest = &Auth_SASL::factory('digestmd5');
        $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge,
                                                       $this->_host, "smtp"));

        if (PEAR::isError($error = $this->_put($auth_str ))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(334))) {
            return $error;
        }

        /*
         * We don't use the protocol's third step because LMTP doesn't allow
         * subsequent authentication, so we just silently ignore it.
         */
        if (PEAR::isError($error = $this->_put(' '))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(235))) {
            return $error;
        }
    }

    /* Authenticates the user using the CRAM-MD5 method.
     *
     * @param string The userid to authenticate as.
     * @param string The password to authenticate with.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access private
     * @since  1.0
     */
    function _authCRAM_MD5($uid, $pwd)
    {


        if (PEAR::isError($error = $this->_put('AUTH', 'CRAM-MD5'))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(334))) {
            return $error;
        }

        $challenge = base64_decode($this->_arguments[0]);
        $cram = &Auth_SASL::factory('crammd5');
        $auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));

        if (PEAR::isError($error = $this->_put($auth_str))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(235))) {
            return $error;
        }
    }

    /**
     * Authenticates the user using the LOGIN method.
     *
     * @param string The userid to authenticate as.
     * @param string The password to authenticate with.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access private 
     * @since  1.0
     */
    function _authLogin($uid, $pwd)
    {
        if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) { 
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(334))) {
            return $error;
        }

        if (PEAR::isError($error = $this->_put(base64_encode($uid)))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(334))) {
            return $error;
        }

        if (PEAR::isError($error = $this->_put(base64_encode($pwd)))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(235))) {
            return $error;
        }

        return true;
    }

    /**
     * Authenticates the user using the PLAIN method.
     *
     * @param string The userid to authenticate as.
     * @param string The password to authenticate with.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access private 
     * @since  1.0
     */
    function _authPlain($uid, $pwd)
    {
        if (PEAR::isError($error = $this->_put('AUTH', 'PLAIN'))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(334))) {
            return $error;
        }

        $auth_str = base64_encode(chr(0) . $uid . chr(0) . $pwd);

        if (PEAR::isError($error = $this->_put($auth_str))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(235))) {
            return $error;
        }

        return true;
    }

    /**
     * Send the MAIL FROM: command.
     *
     * @param string The sender (reverse path) to set.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access public
     * @since  1.0
     */
    function mailFrom($sender)
    {
        if (PEAR::isError($error = $this->_put('MAIL', "FROM:<$sender>"))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(250))) {
            return $error;
        }

        return true;
    }

    /**
     * Send the RCPT TO: command.
     *
     * @param string The recipient (forward path) to add.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access public
     * @since  1.0
     */
    function rcptTo($recipient)
    {
        if (PEAR::isError($error = $this->_put('RCPT', "TO:<$recipient>"))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(array(250, 251)))) {
            return $error;
        }

        return true;
    }

    /**
     * Send the DATA command.
     *
     * @param string The message body to send.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access public
     * @since  1.0
     */
    function data($data)
    {
        if (is_int($this->_esmtp['SIZE'])) {
            if (strlen($data) >= $this->_esmtp['SIZE']) {
                $this->disconnect();
                return new PEAR_Error('Message size excedes the server limit');
            }
        }

        /*
         * Change Unix (\n) and Mac (\r) linefeeds into Internet-standard CRLF
         * (\r\n) linefeeds.
         */
        $data = preg_replace("/([^\r]{1})\n/", "\\1\r\n", $data);
        $data = preg_replace("/\n\n/", "\n\r\n", $data);

        /*
         * Because a single leading period (.) signifies an end to the data,
         * legitimate leading periods need to be "doubled" (e.g. '..').
         */
        $data = preg_replace("/\n\./", "\n..", $data);

        if (PEAR::isError($error = $this->_put('DATA'))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(354))) {
            return $error;
        }

        if (PEAR::isError($this->_send($data . "\r\n.\r\n"))) {
            return new PEAR_Error('write to socket failed');
        }
        if (PEAR::isError($error = $this->_parseResponse(250))) {
            return $error;
        }

        return true;
    }

    /**
     * Send the RSET command.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access public
     * @since  1.0
     */
    function rset()
    {
        if (PEAR::isError($error = $this->_put('RSET'))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(250))) {
            return $error;
        }

        return true;
    }
    /**
     * Send the NOOP command.
     *
     * @return mixed Returns a PEAR_Error with an error message on any
     *               kind of failure, or true on success.
     * @access public
     * @since  1.0
     */
    function noop()
    {
        if (PEAR::isError($error = $this->_put('NOOP'))) {
            return $error;
        }
        if (PEAR::isError($error = $this->_parseResponse(250))) {
            return $error;
        }

        return true;
    }
}

?>

--- NEW FILE: package.xml ---
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
<package version="1.0">
  <name>Net_LMTP</name>
  <summary>Provides an implementation of the RFC2033 LMTP protocol</summary>
  <description>Provides an implementation of the RFC2033 LMTP using PEAR's Net_Socket and Auth_SASL class.</description>
  <maintainers>
    <maintainer>
      <user>damian</user>
      <name>Damian Alejandro Fernandez Sosa</name>
      <email>damlists at cnba.uba.ar</email>
      <role>lead</role>
    </maintainer>
  </maintainers>
  <release>
    <version>0.7.0-kolab</version>
    <date>2004-08-19</date>
    <license>PHP License</license>
    <state>stable</state>
    <notes>* Removed dependency on Auth_SASL, but if installed automatically uses it probiding DIGEST-MD5 and CRAM-MD5 auth methods
* Marked as stable. Kolab: Fixed bug related to SIZE, authors have been contacted.</notes>
    <deps>
      <dep type="pkg" rel="has">Net_Socket</dep>
    </deps>
    <filelist>
      <file role="php" baseinstalldir="Net" md5sum="efa14d485aae3e86c0af0a3249dafde7" name="LMTP.php"/>
      <file role="test" md5sum="d44f1ef2b3d4127bbec817435dc7cc01" name="test_lmtp.php"/>
    </filelist>
  </release>
  <changelog>
    <release>
      <version>0.6</version>
      <date>2003-03-27</date>
      <state>beta</state>
      <notes>- Fixed a bug in DIGEST-MD5 Auth Method.
- Now Uses defaults values in constructor.
      
</notes>
    </release>
    <release>
      <version>0.5</version>
      <date>2003-03-24</date>
      <state>beta</state>
      <notes>- All methods are implemmented based on Net_SMTP
      
</notes>
    </release>
  </changelog>
</package>

--- NEW FILE: test_lmtp.php ---
<?
//
// +----------------------------------------------------------------------+
// | PHP Version 4                                                        |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group                                |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license,      |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.php.net/license/2_02.txt.                                 |
// | If you did not receive a copy of the PHP license and are unable to   |
// | obtain it through the world-wide-web, please send a note to          |
// | license at php.net so we can mail you a copy immediately.               |
// +----------------------------------------------------------------------+
// | Authors: Chuck Hagenbuch <chuck at horde.org>                           |
// |          Jon Parise <jon at php.net>                                    |
// |          Damian Alejandro Fernandez Sosa <damlists at cnba.uba.ar>      |
// +----------------------------------------------------------------------+


require_once('Net/LMTP.php');



// The LMTP server
$host="localhost";
// The default LMTP port
$port="2003";
// The username to authenticate to the LMTP server
$user="cyrus";
// The password to authenticate to the LMTP server
$pwd="password";


//you can create a file called passwords.php and store your $user,$pass,$host and $port values in it
// or you can modify this script
@require_once("./passwords.php");



// The name we send to initiate the LMTP dialog
$localhost="localhost";

// The email as we send the email in the LMTP dialog
$from="damian at cnba.uba.ar";
// The email to send the email in the LMTP dialog
//$to="damian at fernandezsosa.com.ar";
$to="damian at 1aaafernandezsosa.com.ar";
//$to="damian";

// The email text (RFC822 format)
$email="From:damian at cnba.uba.ar\r\nTo:damian at cnba.uba.ar\r\nDate: Wed, 12 Feb 2004 21:07:35 -300\r\nSubject: testing LMTP\r\n\r\nthis is a test email\r\n";



// We create the Net_LMTP instance
$lmtp_conn= new Net_LMTP( $host ,  $port , $localhost);

$lmtp_conn->setDebug(true);
// Connect to the LMTP server
if (PEAR::isError( $error = $lmtp_conn->connect())) {
    echo "ERROR:" . $error->getMessage() . "\n";
    exit();
}
// Authenticates against the LMTP server using PLAIN method.
if (PEAR::isError( $error = $lmtp_conn->auth($user,$pwd,'PLAIN'))) {
    echo "ERROR:" . $error->getMessage() . "\n";
    exit();
}
// Send the MAIL FROM: LMTP command
if (PEAR::isError( $error = $lmtp_conn->mailFrom($from))) {
    echo "ERROR:" . $error->getMessage() . "\n";
    exit();
}

// Send the RCPT TO: LMTP command
if (PEAR::isError( $error = $lmtp_conn->rcptTo($to))) {
    echo "ERROR:" . $error->getMessage() . "\n";
    exit();
}

// Send the DATA: LMTP command (we send the email RFC822 encoded)
if (PEAR::isError( $error = $lmtp_conn->data($email))) {
    echo "ERROR:" . $error->getMessage() . "\n";
    exit();
}
// now the email was accepted by the LMTP server, so we close
// the connection


// Send the QUIT LMTP command and disconnect from the LMTP server
if (PEAR::isError( $error = $lmtp_conn->disconnect())) {
    echo "ERROR:" . $error->getMessage() . "\n";
    exit();
}


?>





More information about the commits mailing list