Reorganize Horde_Mail a bit to group the transport classes
authorChuck Hagenbuch <chuck@horde.org>
Sun, 18 Jul 2010 20:59:36 +0000 (16:59 -0400)
committerChuck Hagenbuch <chuck@horde.org>
Sun, 18 Jul 2010 21:21:58 +0000 (17:21 -0400)
20 files changed:
framework/Alarm/lib/Horde/Alarm/Handler/Mail.php
framework/Core/lib/Horde/Core/Binder/Mail.php
framework/Mail/lib/Horde/Mail.php
framework/Mail/lib/Horde/Mail/Driver.php [deleted file]
framework/Mail/lib/Horde/Mail/Mail.php [deleted file]
framework/Mail/lib/Horde/Mail/Mock.php [deleted file]
framework/Mail/lib/Horde/Mail/Null.php [deleted file]
framework/Mail/lib/Horde/Mail/Sendmail.php [deleted file]
framework/Mail/lib/Horde/Mail/Smtp.php [deleted file]
framework/Mail/lib/Horde/Mail/Smtpmx.php [deleted file]
framework/Mail/lib/Horde/Mail/Transport.php [new file with mode: 0644]
framework/Mail/lib/Horde/Mail/Transport/Mail.php [new file with mode: 0644]
framework/Mail/lib/Horde/Mail/Transport/Mock.php [new file with mode: 0644]
framework/Mail/lib/Horde/Mail/Transport/Null.php [new file with mode: 0644]
framework/Mail/lib/Horde/Mail/Transport/Sendmail.php [new file with mode: 0644]
framework/Mail/lib/Horde/Mail/Transport/Smtp.php [new file with mode: 0644]
framework/Mail/lib/Horde/Mail/Transport/Smtpmx.php [new file with mode: 0644]
framework/Mail/package.xml
framework/Mime/lib/Horde/Mime/Part.php
imp/lib/Injector/Binder/Mail.php

index d751054..3821cc4 100644 (file)
@@ -25,9 +25,9 @@ class Horde_Alarm_Handler_Mail extends Horde_Alarm_Handler
     protected $_identity;
 
     /**
-     * A Horde_Mail_Driver object.
+     * A Horde_Mail_Transport object.
      *
-     * @var Horde_Mail_Driver
+     * @var Horde_Mail_Transport
      */
     protected $_mail;
 
@@ -45,7 +45,7 @@ class Horde_Alarm_Handler_Mail extends Horde_Alarm_Handler
      *                       Required parameter:
      *                       - identity: An identity factory that implements
      *                                   getIdentity().
-     *                       - mail: A Horde_Mail_Driver instance.
+     *                       - mail: A Horde_Mail_Transport instance.
      *                       - charset: The charset of the messages.
      */
     public function __construct(array $params = null)
@@ -58,9 +58,8 @@ class Horde_Alarm_Handler_Mail extends Horde_Alarm_Handler
         if (!method_exists($params['identity'], 'getIdentity')) {
             throw new Horde_Alarm_Exception('Parameter \'identity\' does not implement getIdentity().');
         }
-        $r = new ReflectionObject($params['mail']);
-        if (!($params['mail'] instanceof Horde_Mail_Driver)) {
-            throw new Horde_Alarm_Exception('Parameter \'mail\' is not a Horde_Mail_Driver object.');
+        if (!($params['mail'] instanceof Horde_Mail_Transport)) {
+            throw new Horde_Alarm_Exception('Parameter \'mail\' is not a Horde_Mail_Transport object.');
         }
         $this->_identity = $params['identity'];
         $this->_mail     = $params['mail'];
index d2602a6..94fa3ab 100644 (file)
@@ -7,25 +7,25 @@ class Horde_Core_Binder_Mail implements Horde_Injector_Binder
 {
     public function create(Horde_Injector $injector)
     {
-        $driver = isset($GLOBALS['conf']['mailer']['type'])
+        $transport = isset($GLOBALS['conf']['mailer']['type'])
             ? $GLOBALS['conf']['mailer']['type']
             : 'null';
         $params = isset($GLOBALS['conf']['mailer']['params'])
             ? $GLOBALS['conf']['mailer']['params']
             : array();
 
-        if (($driver == 'smtp') &&
+        if (($transport == 'smtp') &&
             $params['auth'] &&
             empty($params['username'])) {
             $params['username'] = $GLOBALS['registry']->getAuth();
             $params['password'] = $GLOBALS['registry']->getAuthCredential('password');
         }
 
-        try {
-            return Horde_Mail::factory($driver, $params);
-        } catch (Horde_Mime_Exception $e) {
-            throw new Horde_Exception($e);
+        $class = 'Horde_Mail_Transport_' . ucfirst($transport);
+        if (class_exists($class)) {
+            return new $class($params);
         }
+        throw new Horde_Exception('Unable to find class for transport ' . $transport);
     }
 
     public function equals(Horde_Injector_Binder $binder)
index 44d1797..d3b6532 100644 (file)
 class Horde_Mail
 {
     /**
-     * Returns a Horde_Mail_Driver:: object.
+     * Returns a Horde_Mail_Transport:: object.
      *
-     * @param string $driver  The driver to instantiate.
-     * @param array $params   The parameters to pass to the object.
+     * @param string $transport  The transport to instantiate.
+     * @param array $params      The parameters to pass to the transport.
      *
-     * @return Horde_Mail_Driver  The driver instance.
+     * @return Horde_Mail_Transport  The transport instance.
      * @throws Horde_Mail_Exception
+     * @deprecated
      */
-    static public function factory($driver, $params = array())
+    static public function factory($transport, $params = array())
     {
-        $class = __CLASS__ . '_' . ucfirst($driver);
-
+        $class = 'Horde_Mail_Transport_' . ucfirst($transport);
         if (class_exists($class)) {
             return new $class($params);
         }
 
-        throw new Horde_Mail_Exception('Unable to find class for driver ' . $driver);
+        throw new Horde_Mail_Exception('Unable to find class for transport ' . $transport);
     }
-
 }
diff --git a/framework/Mail/lib/Horde/Mail/Driver.php b/framework/Mail/lib/Horde/Mail/Driver.php
deleted file mode 100644 (file)
index fb0f088..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-<?php
-/**
- * Mail driver base class.
- *
- * LICENSE:
- *
- * Copyright (c) 2002-2007, Richard Heyes
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * o Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * o The names of the authors may not be used to endorse or promote
- *   products derived from this software without specific prior written
- *   permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category    Mail
- * @package     Mail
- * @author      Chuck Hagenbuch <chuck@horde.org>
- * @author      Michael Slusarz <slusarz@horde.org>
- * @copyright   1997-2010 Chuck Hagenbuch
- * @copyright   2010 Michael Slusarz
- * @license     http://opensource.org/licenses/bsd-license.php New BSD License
- */
-
-/**
- * Mail driver base class.
- *
- * @access public
- * @version $Revision: 294747 $
- * @package Mail
- */
-abstract class Horde_Mail_Driver
-{
-    /**
-     * Line terminator used for separating header lines.
-     *
-     * @var string
-     */
-    public $sep = "\r\n";
-
-    /**
-     * Configuration parameters.
-     *
-     * @var array
-     */
-    protected $_params = array();
-
-    /**
-     * Send a message.
-     *
-     * @param mixed $recipients  Either a comma-seperated list of recipients
-     *                           (RFC822 compliant), or an array of
-     *                           recipients, each RFC822 valid. This may
-     *                           contain recipients not specified in the
-     *                           headers, for Bcc:, resending messages, etc.
-     * @param array $headers     The headers to send with the mail, in an
-     *                           associative array, where the array key is the
-     *                           header name (ie, 'Subject'), and the array
-     *                           value is the header value (ie, 'test'). The
-     *                           header produced from those values would be
-     *                           'Subject: test'.
-     *                           If the '_raw' key exists, the value of this
-     *                           key will be used as the exact text for
-     *                           sending the message.
-     * @param mixed $body        The full text of the message body, including
-     *                           any Mime parts, etc. Either a string or a
-     *                           stream resource.
-     *
-     * @throws Horde_Mail_Exception
-     */
-    abstract public function send($recipients, array $headers, $body);
-
-    /**
-     * Take an array of mail headers and return a string containing text
-     * usable in sending a message.
-     *
-     * @param array $headers  The array of headers to prepare, in an
-     *                        associative array, where the array key is the
-     *                        header name (ie, 'Subject'), and the array value
-     *                        is the header value (ie, 'test'). The header
-     *                        produced from those values would be 'Subject:
-     *                        test'.
-     *                        If the '_raw' key exists, the value of this key
-     *                        will be used as the exact text for sending the
-     *                        message.
-     *
-     * @return mixed  Returns false if it encounters a bad address; otherwise
-     *                returns an array containing two elements: Any From:
-     *                address found in the headers, and the plain text version
-     *                of the headers.
-     * @throws Horde_Mail_Exception
-     */
-    public function prepareHeaders(array $headers)
-    {
-        $lines = array();
-        $from = null;
-
-        $parser = new Horde_Mail_Rfc822();
-
-        foreach ($headers as $key => $value) {
-            if (strcasecmp($key, 'From') === 0) {
-                $addresses = $parser->parseAddressList($value, array(
-                    'nest_groups' => false,
-                ));
-                $from = $addresses[0]->mailbox . '@' . $addresses[0]->host;
-
-                // Reject envelope From: addresses with spaces.
-                if (strstr($from, ' ')) {
-                    return false;
-                }
-
-                $lines[] = $key . ': ' . $value;
-            } elseif (strcasecmp($key, 'Received') === 0) {
-                $received = array();
-                if (!is_array($value)) {
-                    $value = array($value);
-                }
-
-                foreach ($value as $line) {
-                    $received[] = $key . ': ' . $line;
-                }
-
-                // Put Received: headers at the top.  Spam detectors often
-                // flag messages with Received: headers after the Subject:
-                // as spam.
-                $lines = array_merge($received, $lines);
-            } else {
-                // If $value is an array (i.e., a list of addresses), convert
-                // it to a comma-delimited string of its elements (addresses).
-                if (is_array($value)) {
-                    $value = implode(', ', $value);
-                }
-                $lines[] = $key . ': ' . $value;
-            }
-        }
-
-        return array($from, isset($headers['_raw']) ? $headers['_raw'] : join($this->sep, $lines));
-    }
-
-    /**
-     * Take a set of recipients and parse them, returning an array of bare
-     * addresses (forward paths) that can be passed to sendmail or an SMTP
-     * server with the 'RCPT TO:' command.
-     *
-     * @param mixed  Either a comma-separated list of recipients (RFC822
-     *               compliant), or an array of recipients, each RFC822 valid.
-     *
-     * @return array  Forward paths (bare addresses).
-     * @throws Horde_Mail_Exception
-     */
-    public function parseRecipients($recipients)
-    {
-        // if we're passed an array, assume addresses are valid and
-        // implode them before parsing.
-        if (is_array($recipients)) {
-            $recipients = implode(', ', $recipients);
-        }
-
-        // Parse recipients, leaving out all personal info. This is
-        // for smtp recipients, etc. All relevant personal information
-        // should already be in the headers.
-        $parser = new Horde_Mail_Rfc822();
-        $addresses = $parser->parseAddressList($recipients, array(
-            'nest_groups' => false
-        ));
-
-        $recipients = array();
-        if (is_array($addresses)) {
-            foreach ($addresses as $ob) {
-                $recipients[] = $ob->mailbox . '@' . $ob->host;
-            }
-        }
-
-        return $recipients;
-    }
-
-    /**
-     * Sanitize an array of mail headers by removing any additional header
-     * strings present in a legitimate header's value.  The goal of this
-     * filter is to prevent mail injection attacks.
-     *
-     * @param array $headers  The associative array of headers to sanitize.
-     *
-     * @return array  The sanitized headers.
-     */
-    protected function _sanitizeHeaders($headers)
-    {
-        foreach (array_keys($headers) as $key) {
-            $headers[$key] = preg_replace('=((<CR>|<LF>|0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', null, $headers[$key]);
-        }
-
-        return $headers;
-    }
-
-}
diff --git a/framework/Mail/lib/Horde/Mail/Mail.php b/framework/Mail/lib/Horde/Mail/Mail.php
deleted file mode 100644 (file)
index 1fdd83c..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-<?php
-/**
- * Internal PHP-mail() interface.
- *
- * LICENSE:
- *
- * Copyright (c) 2010 Chuck Hagenbuch
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * o Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * o The names of the authors may not be used to endorse or promote
- *   products derived from this software without specific prior written
- *   permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category  Horde
- * @package   Mail
- * @author    Chuck Hagenbuch <chuck@horde.org>
- * @author    Michael Slusarz <slusarz@horde.org>
- * @copyright 2010 Chuck Hagenbuch
- * @copyright 2010 Michael Slusarz
- * @license   http://opensource.org/licenses/bsd-license.php New BSD License
- */
-
-/**
- * Internal PHP-mail() interface.
- *
- * @category Horde
- * @package  Mail
- */
-class Horde_Mail_Mail extends Horde_Mail_Driver
-{
-    /**
-     * Constructor.
-     *
-     * @param array $params  Additional parameters:
-     * <pre>
-     * 'args' - (string) Extra arguments for the mail() function.
-     * </pre>
-     */
-    public function __construct(array $params = array())
-    {
-        $this->_params = array_merge($this->_params, $params);
-
-        /* Because the mail() function may pass headers as command
-         * line arguments, we can't guarantee the use of the standard
-         * "\r\n" separator.  Instead, we use the system's native line
-         * separator. */
-        $this->sep = defined('PHP_EOL')
-            ? PHP_EOL
-            : (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n";
-    }
-
-    /**
-     * Send a message.
-     *
-     * @param mixed $recipients  Either a comma-seperated list of recipients
-     *                           (RFC822 compliant), or an array of
-     *                           recipients, each RFC822 valid. This may
-     *                           contain recipients not specified in the
-     *                           headers, for Bcc:, resending messages, etc.
-     * @param array $headers     The headers to send with the mail, in an
-     *                           associative array, where the array key is the
-     *                           header name (ie, 'Subject'), and the array
-     *                           value is the header value (ie, 'test'). The
-     *                           header produced from those values would be
-     *                           'Subject: test'.
-     *                           If the '_raw' key exists, the value of this
-     *                           key will be used as the exact text for
-     *                           sending the message.
-     * @param mixed $body        The full text of the message body, including
-     *                           any Mime parts, etc. Either a string or a
-     *                           stream resource.
-     *
-     * @throws Horde_Mail_Exception
-     */
-    public function send($recipients, array $headers, $body)
-    {
-        $headers = $this->_sanitizeHeaders($headers);
-
-        // If we're passed an array of recipients, implode it.
-        if (is_array($recipients)) {
-            $recipients = array_map('trim', implode(',', $recipients));
-        }
-
-        $subject = '';
-
-        foreach (array_keys($headers) as $hdr) {
-            if (strcasecmp($hdr, 'Subject') === 0) {
-                // Get the Subject out of the headers array so that we can
-                // pass it as a separate argument to mail().
-                $subject = $headers[$hdr];
-                unset($headers[$hdr]);
-            } elseif (strcasecmp($hdr, 'To') === 0) {
-                // Remove the To: header.  The mail() function will add its
-                // own To: header based on the contents of $recipients.
-                unset($headers[$hdr]);
-            }
-        }
-
-        // Flatten the headers out.
-        list(, $text_headers) = $this->prepareHeaders($headers);
-
-        // mail() requires a string for $body. If resource, need to convert
-        // to a string.
-        if (is_resource($body)) {
-            $body_str = '';
-            rewind($body);
-            while (!feof($body)) {
-                $body_str .= fread($body, 8192);
-            }
-            $body = $body_str;
-        }
-
-        // We only use mail()'s optional fifth parameter if the additional
-        // parameters have been provided and we're not running in safe mode.
-        if (empty($this->_params) || ini_get('safe_mode')) {
-            $result = mail($recipients, $subject, $body, $text_headers);
-        } else {
-            $result = mail($recipients, $subject, $body, $text_headers, isset($this->_params['args']) ? $this->_params['args'] : '');
-        }
-
-        // If the mail() function returned failure, we need to create an
-        // Exception and return it instead of the boolean result.
-        if ($result === false) {
-            throw new Horde_Mail_Exception('mail() returned failure.');
-        }
-    }
-
-}
diff --git a/framework/Mail/lib/Horde/Mail/Mock.php b/framework/Mail/lib/Horde/Mail/Mock.php
deleted file mode 100644 (file)
index 6e68c31..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-/**
- * Mock mail driver.
- *
- * LICENSE:
- *
- * Copyright (c) 2010 Chuck Hagenbuch
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * o Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * o The names of the authors may not be used to endorse or promote
- *   products derived from this software without specific prior written
- *   permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category  Horde
- * @package   Mail
- * @author    Chuck Hagenbuch <chuck@horde.org>
- * @copyright 2010 Chuck Hagenbuch
- * @license   http://opensource.org/licenses/bsd-license.php New BSD License
- */
-
-/**
- * Mock implementation, for testing.
- *
- * @category Horde
- * @package  Mail
- */
-class Horde_Mail_Mock extends Horde_Mail_Driver
-{
-    /**
-     * Array of messages that have been sent with the mock.
-     *
-     * @var array
-     */
-    public $sentMessages = array();
-
-    /**
-     * Callback before sending mail.
-     *
-     * @var callback
-     */
-    protected $_preSendCallback;
-
-    /**
-     * Callback after sending mai.
-     *
-     * @var callback
-     */
-    protected $_postSendCallback;
-
-    /**
-     * Constructor.
-     *
-     * @param array  Optional parameters:
-     * <pre>
-     * 'preSendCallback' - (callback) Called before an email would be sent.
-     * 'postSendCallback' - (callback) Called after an email would have been
-     *                      sent.
-     * </pre>
-     */
-    public function __construct(array $params = array())
-    {
-        if (isset($params['preSendCallback']) &&
-            is_callable($params['preSendCallback'])) {
-            $this->_preSendCallback = $params['preSendCallback'];
-        }
-
-        if (isset($params['postSendCallback']) &&
-            is_callable($params['postSendCallback'])) {
-            $this->_postSendCallback = $params['postSendCallback'];
-        }
-    }
-
-    /**
-     * Send a message. Silently discards all mail.
-     *
-     * @param mixed $recipients  Either a comma-seperated list of recipients
-     *                           (RFC822 compliant), or an array of
-     *                           recipients, each RFC822 valid. This may
-     *                           contain recipients not specified in the
-     *                           headers, for Bcc:, resending messages, etc.
-     * @param array $headers     The headers to send with the mail, in an
-     *                           associative array, where the array key is the
-     *                           header name (ie, 'Subject'), and the array
-     *                           value is the header value (ie, 'test'). The
-     *                           header produced from those values would be
-     *                           'Subject: test'.
-     *                           If the '_raw' key exists, the value of this
-     *                           key will be used as the exact text for
-     *                           sending the message.
-     * @param mixed $body        The full text of the message body, including
-     *                           any Mime parts, etc. Either a string or a
-     *                           stream resource.
-     *
-     * @throws Horde_Mail_Exception
-     */
-    public function send($recipients, array $headers, $body)
-    {
-        if ($this->_preSendCallback) {
-            call_user_func_array($this->_preSendCallback, array($this, $recipients, $headers, $body));
-        }
-
-        $headers = $this->_sanitizeHeaders($headers);
-        list(, $text_headers) = $this->prepareHeaders($headers);
-
-        $this->sentMessages[] = array(
-            'body' => $body,
-            'headers' => $headers,
-            'header_text' => $text_headers,
-            'recipients' => $recipients
-        );
-
-        if ($this->_postSendCallback) {
-            call_user_func_array($this->_postSendCallback, array($this, $recipients, $headers, $body));
-        }
-    }
-
-}
diff --git a/framework/Mail/lib/Horde/Mail/Null.php b/framework/Mail/lib/Horde/Mail/Null.php
deleted file mode 100644 (file)
index bf03470..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-/**
- * Null implementation of the mail interface.
- *
- * LICENSE:
- *
- * Copyright (c) 2010 Phil Kernick
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * o Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * o The names of the authors may not be used to endorse or promote
- *   products derived from this software without specific prior written
- *   permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category    Horde
- * @package     Mail
- * @author      Phil Kernick <philk@rotfl.com.au>
- * @copyright   2010 Phil Kernick
- * @license     http://opensource.org/licenses/bsd-license.php New BSD License
- */
-
-/**
- * Null implementation of the mail interface.
- *
- * @category Horde
- * @package  Mail
- */
-class Horde_Mail_Null extends Horde_Mail_Driver
-{
-    /**
-     * Send a message.
-     *
-     * @param mixed $recipients  Either a comma-seperated list of recipients
-     *                           (RFC822 compliant), or an array of
-     *                           recipients, each RFC822 valid. This may
-     *                           contain recipients not specified in the
-     *                           headers, for Bcc:, resending messages, etc.
-     * @param array $headers     The headers to send with the mail, in an
-     *                           associative array, where the array key is the
-     *                           header name (ie, 'Subject'), and the array
-     *                           value is the header value (ie, 'test'). The
-     *                           header produced from those values would be
-     *                           'Subject: test'.
-     *                           If the '_raw' key exists, the value of this
-     *                           key will be used as the exact text for
-     *                           sending the message.
-     * @param mixed $body        The full text of the message body, including
-     *                           any Mime parts, etc. Either a string or a
-     *                           stream resource.
-     *
-     * @throws Horde_Mail_Exception
-     */
-    public function send($recipients, array $headers, $body)
-    {
-    }
-
-}
diff --git a/framework/Mail/lib/Horde/Mail/Sendmail.php b/framework/Mail/lib/Horde/Mail/Sendmail.php
deleted file mode 100644 (file)
index 08c01a3..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-<?php
-/**
- * Sendmail interface.
- *
- * LICENSE:
- *
- * Copyright (c) 2010 Chuck Hagenbuch
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * o Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * o The names of the authors may not be used to endorse or promote
- *   products derived from this software without specific prior written
- *   permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category  Horde
- * @package   Mail
- * @author    Chuck Hagenbuch <chuck@horde.org>
- * @author    Michael Slusarz <slusarz@horde.org>
- * @copyright 2010 Chuck Hagenbuch
- * @copyright 2010 Michael Slusarz
- * @license   http://opensource.org/licenses/bsd-license.php New BSD License
- */
-
-/**
- * Sendmail interface.
- *
- * @category Horde
- * @package  Mail
- */
-class Horde_Mail_Sendmail extends Horde_Mail_Driver
-{
-    /**
-     * Any extra command-line parameters to pass to the sendmail or
-     * sendmail wrapper binary.
-     *
-     * @var string
-     */
-    protected $_sendmailArgs = '-i';
-
-    /**
-     * The location of the sendmail or sendmail wrapper binary on the
-     * filesystem.
-     *
-     * @var string
-     */
-    protected $_sendmailPath = '/usr/sbin/sendmail';
-
-    /**
-     * Constructor.
-     *
-     * @param array $params  Additional parameters:
-     * <pre>
-     * 'sendmail_args' - (string) Any extra parameters to pass to the sendmail
-     *                   or sendmail wrapper binary.
-     *                   DEFAULT: -i
-     * 'sendmail_path' - (string) The location of the sendmail binary on the
-     *                   filesystem.
-     *                   DEFAULT: /usr/sbin/sendmail
-     * </pre>
-     */
-    public function __construct(array $params = array())
-    {
-        if (isset($params['sendmail_args'])) {
-            $this->_sendmailArgs = $params['sendmail_args'];
-        }
-
-        if (isset($params['sendmail_path'])) {
-            $this->_sendmailPath = $params['sendmail_path'];
-        }
-
-        /* Because we need to pass message headers to the sendmail program on
-         * the commandline, we can't guarantee the use of the standard "\r\n"
-         * separator.  Instead, we use the system's native line separator. */
-        $this->sep = defined('PHP_EOL')
-            ? PHP_EOL
-            : (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n";
-    }
-
-    /**
-     * Send a message.
-     *
-     * @param mixed $recipients  Either a comma-seperated list of recipients
-     *                           (RFC822 compliant), or an array of
-     *                           recipients, each RFC822 valid. This may
-     *                           contain recipients not specified in the
-     *                           headers, for Bcc:, resending messages, etc.
-     * @param array $headers     The headers to send with the mail, in an
-     *                           associative array, where the array key is the
-     *                           header name (ie, 'Subject'), and the array
-     *                           value is the header value (ie, 'test'). The
-     *                           header produced from those values would be
-     *                           'Subject: test'.
-     *                           If the '_raw' key exists, the value of this
-     *                           key will be used as the exact text for
-     *                           sending the message.
-     * @param mixed $body        The full text of the message body, including
-     *                           any Mime parts, etc. Either a string or a
-     *                           stream resource.
-     *
-     * @throws Horde_Mail_Exception
-     */
-    public function send($recipients, array $headers, $body)
-    {
-        $recipients = implode(' ', array_map('escapeshellarg', $this->parseRecipients($recipients)));
-
-        $headers = $this->_sanitizeHeaders($headers);
-        list($from, $text_headers) = $this->prepareHeaders($headers);
-
-        /* Since few MTAs are going to allow this header to be forged
-         * unless it's in the MAIL FROM: exchange, we'll use Return-Path
-         * instead of From: if it's set. */
-        foreach (array_keys($headers) as $hdr) {
-            if (strcasecmp($hdr, 'Return-Path') === 0) {
-                $from = $headers[$hdr];
-                break;
-            }
-        }
-
-        if (!strlen($from)) {
-            throw new Horde_Mail_Exception('No From address given.');
-        } elseif ((strpos($from, ' ') !== false) ||
-                  (strpos($from, ';') !== false) ||
-                  (strpos($from, '&') !== false) ||
-                  (strpos($from, '`') !== false)) {
-            throw new Horde_Mail_Exception('From address specified with dangerous characters.');
-        }
-
-        $mail = @popen($this->_sendmailPath . (empty($this->_sendmailArgs) ? '' : ' ' . $this->_sendmailargs) . ' -f' . escapeshellarg($from) . ' -- ' . $recipients, 'w');
-        if (!$mail) {
-            throw new Horde_Mail_Exception('Failed to open sendmail [' . $this->_sendmailPath . '] for execution.');
-        }
-
-        // Write the headers following by two newlines: one to end the headers
-        // section and a second to separate the headers block from the body.
-        fputs($mail, $text_headers . $this->sep . $this->sep);
-
-        if (is_resource($body)) {
-            rewind($body);
-            while (!feof($body)) {
-                fputs($mail, fread($body, 8192));
-            }
-        } else {
-            fputs($mail, $body);
-        }
-        $result = pclose($mail);
-
-        if (!$result) {
-            return;
-        }
-
-        switch ($result) {
-        case 64: // EX_USAGE
-            $msg = 'command line usage error';
-            break;
-
-        case 65: // EX_DATAERR
-            $msg =  'data format error';
-            break;
-
-        case 66: // EX_NOINPUT
-            $msg = 'cannot open input';
-            break;
-
-        case 67: // EX_NOUSER
-            $msg = 'addressee unknown';
-            break;
-
-        case 68: // EX_NOHOST
-            $msg = 'host name unknown';
-            break;
-
-        case 69: // EX_UNAVAILABLE
-            $msg = 'service unavailable';
-            break;
-
-        case 70: // EX_SOFTWARE
-            $msg = 'internal software error';
-            break;
-
-        case 71: // EX_OSERR
-            $msg = 'system error';
-            break;
-
-        case 72: // EX_OSFILE
-            $msg = 'critical system file missing';
-            break;
-
-        case 73: // EX_CANTCREAT
-            $msg = 'cannot create output file';
-            break;
-
-        case 74: // EX_IOERR
-            $msg = 'input/output error';
-
-        case 75: // EX_TEMPFAIL
-            $msg = 'temporary failure';
-            break;
-
-        case 76: // EX_PROTOCOL
-            $msg = 'remote error in protocol';
-            break;
-
-        case 77: // EX_NOPERM
-            $msg = 'permission denied';
-            break;
-
-        case 77: // EX_NOPERM
-            $msg = 'permission denied';
-            break;
-
-        case 78: // EX_CONFIG
-            $msg = 'configuration error';
-            break;
-
-        case 79: // EX_NOTFOUND
-            $msg = 'entry not found';
-            break;
-
-        default:
-            $msg = 'unknown error';
-            break;
-        }
-
-        throw new Horde_Mail_Exception('sendmail: ' . $msg . ' (' . $result . ')', $result);
-    }
-
-}
diff --git a/framework/Mail/lib/Horde/Mail/Smtp.php b/framework/Mail/lib/Horde/Mail/Smtp.php
deleted file mode 100644 (file)
index 58b0d83..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-<?php
-/**
- * SMTP implementation.
- * Requires the Net_SMTP class.
- *
- * LICENSE:
- *
- * Copyright (c) 2010, Chuck Hagenbuch
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * o Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * o The names of the authors may not be used to endorse or promote
- *   products derived from this software without specific prior written
- *   permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category  Horde
- * @package   Mail
- * @author    Jon Parise <jon@php.net>
- * @author    Chuck Hagenbuch <chuck@horde.org>
- * @copyright 2010 Chuck Hagenbuch
- * @license   http://opensource.org/licenses/bsd-license.php New BSD License
- */
-
-/**
- * SMTP implementation.
- *
- * @category Horde
- * @package  Mail
- */
-class Horde_Mail_Smtp extends Horde_Mail_Driver
-{
-    /* Error: Failed to create a Net_SMTP object */
-    const ERROR_CREATE = 10000;
-
-    /* Error: Failed to connect to SMTP server */
-    const ERROR_CONNECT = 10001;
-
-    /* Error: SMTP authentication failure */
-    const ERROR_AUTH = 10002;
-
-    /* Error: No From: address has been provided */
-    const ERROR_FROM = 10003;
-
-    /* Error: Failed to set sender */
-    const ERROR_SENDER = 10004;
-
-    /* Error: Failed to add recipient */
-    const ERROR_RECIPIENT = 10005;
-
-    /* Error: Failed to send data */
-    const ERROR_DATA = 10006;
-
-    /**
-     * The SMTP greeting.
-     *
-     * @var string
-     */
-    public $greeting = null;
-
-    /**
-     * The SMTP queued response.
-     *
-     * @var string
-     */
-    public $queuedAs = null;
-
-    /**
-     * SMTP connection object.
-     *
-     * @var Net_SMTP
-     */
-    protected $_smtp = null;
-
-    /**
-     * The list of service extension parameters to pass to the Net_SMTP
-     * mailFrom() command.
-     *
-     * @var array
-     */
-    protected $_extparams = array();
-
-    /**
-     * Constructor.
-     *
-     * @param array $params  Additional parameters:
-     * <pre>
-     * 'auth' - (mixed) SMTP authentication.
-     *          This value may be set to true, false or the name of a specific
-     *          authentication method.
-     *          If the value is set to true, the Net_SMTP package will attempt
-     *          to use the best authentication method advertised by the remote
-     *          SMTP server.
-     *          DEFAULT: false.
-     * 'debug' - (boolean) Activate SMTP debug mode?
-     *           DEFAULT: false
-     * 'host' - (string) The server to connect to.
-     *          DEFAULT: localhost
-     * 'localhost' - (string) Hostname or domain that will be sent to the
-     *               remote SMTP server in the HELO / EHLO message.
-     *               DEFAULT: localhost
-     * 'password' - (string) The password to use for SMTP auth.
-     *              DEFAULT: NONE
-     * 'persist' - (boolean) Should the SMTP connection persist?
-     *             DEFAULT: false
-     * 'pipelining' - (boolean) Use SMTP command pipelining.
-     *                Use SMTP command pipelining (specified in RFC 2920) if
-     *                the SMTP server supports it. This speeds up delivery
-     *                over high-latency connections.
-     *                DEFAULT: false (use default value from Net_SMTP)
-     * 'port' - (integer) The port to connect to.
-     *          DEFAULT: 25
-     * 'timeout' - (integer) The SMTP connection timeout.
-     *             DEFAULT: NONE
-     * 'username' - (string) The username to use for SMTP auth.
-     *              DEFAULT: NONE
-     * </pre>
-     */
-    public function __construct(array $params = array())
-    {
-        $this->_params = array_merge(array(
-            'auth' => false,
-            'debug' => false,
-            'host' => 'localhost',
-            'localhost' => 'localhost',
-            'password' => '',
-            'persist' => false,
-            'pipelining' => false,
-            'port' => 25,
-            'timeout' => null,
-            'username' => ''
-        ), $params);
-
-        /* Destructor implementation to ensure that we disconnect from any
-         * potentially-alive persistent SMTP connections. */
-        register_shutdown_function(array($this, 'disconnect'));
-    }
-
-    /**
-     * Send a message.
-     *
-     * @param mixed $recipients  Either a comma-seperated list of recipients
-     *                           (RFC822 compliant), or an array of
-     *                           recipients, each RFC822 valid. This may
-     *                           contain recipients not specified in the
-     *                           headers, for Bcc:, resending messages, etc.
-     * @param array $headers     The headers to send with the mail, in an
-     *                           associative array, where the array key is the
-     *                           header name (ie, 'Subject'), and the array
-     *                           value is the header value (ie, 'test'). The
-     *                           header produced from those values would be
-     *                           'Subject: test'.
-     *                           If the '_raw' key exists, the value of this
-     *                           key will be used as the exact text for
-     *                           sending the message.
-     * @param mixed $body        The full text of the message body, including
-     *                           any Mime parts, etc. Either a string or a
-     *                           stream resource.
-     *
-     * @throws Horde_Mail_Exception
-     */
-    public function send($recipients, array $headers, $body)
-    {
-        /* If we don't already have an SMTP object, create one. */
-        $this->getSMTPObject();
-
-        $headers = $this->_sanitizeHeaders($headers);
-
-        try {
-            list($from, $textHeaders) = $this->prepareHeaders($headers);
-        } catch (Horde_Mail_Exception $e) {
-            $this->_smtp->rset();
-            throw $e;
-        }
-
-        /* Since few MTAs are going to allow this header to be forged unless
-         * it's in the MAIL FROM: exchange, we'll use Return-Path instead of
-         * From: if it's set. */
-        foreach (array_keys($headers) as $hdr) {
-            if (strcasecmp($hdr, 'Return-Path') === 0) {
-                $from = $headers[$hdr];
-                break;
-            }
-        }
-
-        if (!strlen($from)) {
-            $this->_smtp->rset();
-            throw new Horde_Mail_Exception('No From: address has been provided', self::ERROR_FROM);
-        }
-
-        $params = '';
-        foreach ($this->_extparams as $key => $val) {
-            $params .= ' ' . $key . (is_null($val) ? '' : '=' . $val);
-        }
-
-        $res = $this->_smtp->mailFrom($from, ltrim($params));
-        if ($res instanceof PEAR_Error) {
-            $this->_smtp->rset();
-            $this->_error("Failed to set sender: $from", $res, self::ERROR_SENDER);
-        }
-
-        try {
-            $recipients = $this->parseRecipients($recipients);
-        } catch (Horde_Mail_Exception $e) {
-            $this->_smtp->rset();
-            throw $e;
-        }
-
-        foreach ($recipients as $recipient) {
-            $res = $this->_smtp->rcptTo($recipient);
-            if ($res instanceof PEAR_Error) {
-                $this->_smtp->rset();
-                $this->_error("Failed to add recipient: $recipient", $res, self::ERROR_RECIPIENT);
-            }
-        }
-
-        /* Send the message's headers and the body as SMTP data. */
-        $res = $this->_smtp->data($body, $textHeaders);
-               list(,$args) = $this->_smtp->getResponse();
-
-               if (preg_match("/Ok: queued as (.*)/", $args, $queued)) {
-                       $this->queuedAs = $queued[1];
-               }
-
-        /* We need the greeting; from it we can extract the authorative name
-         * of the mail server we've really connected to. Ideal if we're
-         * connecting to a round-robin of relay servers and need to track
-         * which exact one took the email */
-               $this->greeting = $this->_smtp->getGreeting();
-
-        if ($res instanceof PEAR_Error) {
-            $this->_smtp->rset();
-            $this->_error('Failed to send data', $res, self::ERROR_DATA);
-        }
-
-        /* If persistent connections are disabled, destroy our SMTP object. */
-        if ($this->_params['persist']) {
-            $this->disconnect();
-        }
-    }
-
-    /**
-     * Connect to the SMTP server by instantiating a Net_SMTP object.
-     *
-     * @return Net_SMTP  The SMTP object.
-     * @throws Horde_Mail_Exception
-     */
-    public function getSMTPObject()
-    {
-        if ($this->_smtp) {
-            return $this->_smtp;
-        }
-
-        $this->_smtp = new Net_SMTP(
-            $this->_params['host'],
-            $this->_params['port'],
-            $this->_params['localhost']
-        );
-
-        /* If we still don't have an SMTP object at this point, fail. */
-        if (!($this->_smtp instanceof Net_SMTP)) {
-            throw new Horde_Mail_Exception('Failed to create a Net_SMTP object', self::ERROR_CREATE);
-        }
-
-        /* Configure the SMTP connection. */
-        if ($this->_params['debug']) {
-            $this->_smtp->setDebug(true);
-        }
-
-        /* Attempt to connect to the configured SMTP server. */
-        $res = $this->_smtp->connect($this->_params['timeout']);
-        if ($res instanceof PEAR_Error) {
-            $this->_error('Failed to connect to ' . $this->_params['host'] . ':' . $this->_params['port'], $res, self::ERROR_CONNECT);
-        }
-
-        /* Attempt to authenticate if authentication has been enabled. */
-        if ($this->_params['auth']) {
-            $method = is_string($this->_params['auth'])
-                ? $this->_params['auth']
-                : '';
-
-            $res = $this->_smtp->auth($this->_params['username'], $this->_params['password'], $method);
-            if ($res instanceof PEAR_Error) {
-                $this->_smtp->rset();
-                $this->_error("$method authentication failure", $res, self::ERROR_AUTH);
-            }
-        }
-
-        return $this->_smtp;
-    }
-
-    /**
-     * Add parameter associated with a SMTP service extension.
-     *
-     * @param string $keyword  Extension keyword.
-     * @param string $value    Any value the keyword needs.
-     */
-    public function addServiceExtensionParameter($keyword, $value = null)
-    {
-        $this->_extparams[$keyword] = $value;
-    }
-
-    /**
-     * Disconnect and destroy the current SMTP connection.
-     *
-     * @return boolean True if the SMTP connection no longer exists.
-     */
-    public function disconnect()
-    {
-        /* If we have an SMTP object, disconnect and destroy it. */
-        if (is_object($this->_smtp) && $this->_smtp->disconnect()) {
-            $this->_smtp = null;
-        }
-
-        /* We are disconnected if we no longer have an SMTP object. */
-        return ($this->_smtp === null);
-    }
-
-    /**
-     * Build a standardized string describing the current SMTP error.
-     *
-     * @param string $text       Custom string describing the error context.
-     * @param PEAR_Error $error  PEAR_Error object.
-     * @param integer $e_code    Error code.
-     *
-     * @throws Horde_Mail_Exception
-     */
-    protected function _error($text, $error, $e_code)
-    {
-        /* Split the SMTP response into a code and a response string. */
-        list($code, $response) = $this->_smtp->getResponse();
-
-        /* Build our standardized error string. */
-        throw new Horde_Mail_Exception($text . ' [SMTP: ' . $error->getMessage() . " (code: $code, response: $response)]", $e_code);
-    }
-
-}
diff --git a/framework/Mail/lib/Horde/Mail/Smtpmx.php b/framework/Mail/lib/Horde/Mail/Smtpmx.php
deleted file mode 100644 (file)
index 45966a9..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-<?PHP
-/**
- * SMTP MX implementation.
- * Requires the Net_SMTP class.
- *
- * LICENSE:
- *
- * Copyright (c) 2010, gERD Schaufelberger
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * o Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * o The names of the authors may not be used to endorse or promote
- *   products derived from this software without specific prior written
- *   permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category   Horde
- * @package    Mail
- * @author     gERD Schaufelberger <gerd@php-tools.net>
- * @copyright  2010 gERD Schaufelberger
- * @license    http://opensource.org/licenses/bsd-license.php New BSD License
- */
-
-/**
- * SMTP MX implementation.
- *
- * @author   gERD Schaufelberger <gerd@php-tools.net>
- * @category Horde
- * @package  Mail
- */
-class Horde_Mail_Smtpmx extends Horde_Mail_Driver
-{
-    /**
-     * SMTP connection object.
-     *
-     * @var Net_SMTP
-     */
-    protected $_smtp = null;
-
-    /**
-     * Net_DNS_Resolver object.
-     *
-     * @var Net_DNS_Resolver
-     */
-    protected $_resolver;
-
-    /**
-     * Internal error codes.
-     * Translate internal error identifier to human readable messages.
-     *
-     * @var array
-     */
-    protected $_errorCode = array(
-        'not_connected' => array(
-            'code' => 1,
-            'msg' => 'Could not connect to any mail server ({HOST}) at port {PORT} to send mail to {RCPT}.'
-        ),
-        'failed_vrfy_rcpt' => array(
-            'code' => 2,
-            'msg' => 'Recipient "{RCPT}" could not be veryfied.'
-        ),
-        'failed_set_from' => array(
-            'code' => 3,
-            'msg' => 'Failed to set sender: {FROM}.'
-        ),
-        'failed_set_rcpt' => array(
-            'code' => 4,
-            'msg' => 'Failed to set recipient: {RCPT}.'
-        ),
-        'failed_send_data' => array(
-            'code' => 5,
-            'msg' => 'Failed to send mail to: {RCPT}.'
-        ),
-        'no_from' => array(
-            'code' => 5,
-            'msg' => 'No from address has be provided.'
-        ),
-        'send_data' => array(
-            'code' => 7,
-            'msg' => 'Failed to create Net_SMTP object.'
-        ),
-        'no_mx' => array(
-            'code' => 8,
-            'msg' => 'No MX-record for {RCPT} found.'
-        ),
-        'no_resolver' => array(
-            'code' => 9,
-            'msg' => 'Could not start resolver! Install PEAR:Net_DNS or switch off "netdns"'
-        ),
-        'failed_rset' => array(
-            'code' => 10,
-            'msg' => 'RSET command failed, SMTP-connection corrupt.'
-        )
-    );
-
-    /**
-     * Constructor.
-     *
-     * @param array $params  Additional options:
-     * <pre>
-     * 'debug' - (boolean) Activate SMTP and Net_DNS debug mode?
-     *           DEFAULT: false
-     * 'mailname' - (string) The name of the local mail system (a valid
-     *              hostname which matches the reverse lookup)
-     *              DEFAULT: Auto-determined
-     * 'netdns' - (boolean) Use PEAR:Net_DNS (true) or the PHP builtin
-     *            getmxrr().
-     *            DEFAULT: true
-     * 'port' - (integer) Port.
-     *          DEFAULT: Auto-determined
-     * 'test' - (boolean) Activate test mode?
-     *          DEFAULT: false
-     * 'timeout' - (integer) The SMTP connection timeout (in seconds).
-     *             DEFAULT: 10
-     * 'verp' - (boolean) Whether to use VERP.
-     *          If not a boolean, the string value will be used as the VERP
-     *          separators.
-     *          DEFAULT: false
-     * 'vrfy' - (boolean) Whether to use VRFY.
-     *          DEFAULT: false
-     * </pre>
-     */
-    public function __construct(array $params = array())
-    {
-        /* Try to find a valid mailname. */
-        if (!isset($params['mailname']) && function_exists('posix_uname')) {
-            $uname = posix_uname();
-            $params['mailname'] = $uname['nodename'];
-        }
-
-        if (!isset($params['port'])) {
-            $params['port'] = getservbyname('smtp', 'tcp');
-        }
-
-        $this->_params = array_merge(array(
-            'debug' => false,
-            'mailname' => 'localhost',
-            'netdns' => true,
-            'port' => 25,
-            'test' => false,
-            'timeout' => 10,
-            'verp' => false,
-            'vrfy' => false
-        ), $params);
-    }
-
-    /**
-     * Destructor implementation to ensure that we disconnect from any
-     * potentially-alive persistent SMTP connections.
-     */
-    public function __destruct()
-    {
-        if (is_object($this->_smtp)) {
-            $this->_smtp->disconnect();
-            $this->_smtp = null;
-        }
-    }
-
-    /**
-     * Send a message.
-     *
-     * @param mixed $recipients  Either a comma-seperated list of recipients
-     *                           (RFC822 compliant), or an array of
-     *                           recipients, each RFC822 valid. This may
-     *                           contain recipients not specified in the
-     *                           headers, for Bcc:, resending messages, etc.
-     * @param array $headers     The headers to send with the mail, in an
-     *                           associative array, where the array key is the
-     *                           header name (ie, 'Subject'), and the array
-     *                           value is the header value (ie, 'test'). The
-     *                           header produced from those values would be
-     *                           'Subject: test'.
-     *                           If the '_raw' key exists, the value of this
-     *                           key will be used as the exact text for
-     *                           sending the message.
-     * @param mixed $body        The full text of the message body, including
-     *                           any Mime parts, etc. Either a string or a
-     *                           stream resource.
-     *
-     * @throws Horde_Mail_Exception
-     */
-    public function send($recipients, array $headers, $body)
-    {
-        $headers = $this->_sanitizeHeaders($headers);
-
-        // Prepare headers
-        list($from, $textHeaders) = $this->prepareHeaders($headers);
-
-        // Use 'Return-Path' if possible
-        foreach (array_keys($headers) as $hdr) {
-            if (strcasecmp($hdr, 'Return-Path') === 0) {
-                $from = $headers['Return-Path'];
-                break;
-            }
-        }
-
-        if (!strlen($from)) {
-            $this->_error('no_from');
-        }
-
-        // Prepare recipients
-        foreach ($this->parseRecipients($recipients) as $rcpt) {
-            list($user, $host) = explode('@', $rcpt);
-
-            $mx = $this->_getMx($host);
-            if (!$mx) {
-                $this->_error('no_mx', array('rcpt' => $rcpt));
-            }
-
-            $connected = false;
-            foreach ($mx as $mserver => $mpriority) {
-                $this->_smtp = new Net_SMTP($mserver, $this->_params['port'], $this->_params['mailname']);
-
-                // configure the SMTP connection.
-                if ($this->_params['debug']) {
-                    $this->_smtp->setDebug(true);
-                }
-
-                // attempt to connect to the configured SMTP server.
-                $res = $this->_smtp->connect($this->_params['timeout']);
-                if ($res instanceof PEAR_Error) {
-                    $this->_smtp = null;
-                    continue;
-                }
-
-                // connection established
-                if ($res) {
-                    $connected = true;
-                    break;
-                }
-            }
-
-            if (!$connected) {
-                $this->_error('not_connected', array(
-                    'host' => implode(', ', array_keys($mx)),
-                    'port' => $this->_params['port'],
-                    'rcpt' => $rcpt
-                ));
-            }
-
-            // Verify recipient
-            if ($this->_params['vrfy']) {
-                $res = $this->_smtp->vrfy($rcpt);
-                if ($res instanceof PEAR_Error) {
-                    $this->_error('failed_vrfy_rcpt', array('rcpt' => $rcpt));
-                }
-            }
-
-            // mail from:
-            $args['verp'] = $this->_params['verp'];
-            $res = $this->_smtp->mailFrom($from, $args);
-            if ($res instanceof PEAR_Error) {
-                $this->_error('failed_set_from', array('from' => $from));
-            }
-
-            // rcpt to:
-            $res = $this->_smtp->rcptTo($rcpt);
-            if ($res instanceof PEAR_Error) {
-                $this->_error('failed_set_rcpt', array('rcpt' => $rcpt));
-            }
-
-            // Don't send anything in test mode
-            if ($this->_params['test']) {
-                $res = $this->_smtp->rset();
-                if ($res instanceof PEAR_Error) {
-                    $this->_error('failed_rset');
-                }
-
-                $this->_smtp->disconnect();
-                $this->_smtp = null;
-                return;
-            }
-
-            // Send data
-            $res = $this->_smtp->data($body, $textHeaders);
-            if ($res instanceof PEAR_Error) {
-                $this->_error('failed_send_data', array('rcpt' => $rcpt));
-            }
-
-            $this->_smtp->disconnect();
-            $this->_smtp = null;
-        }
-    }
-
-    /**
-     * Recieve MX records for a host.
-     *
-     * @param string $host  Mail host.
-     *
-     * @return mixed  Sorted MX list or false on error.
-     */
-    protected function _getMx($host)
-    {
-        $mx = array();
-
-        if ($this->params['netdns']) {
-            $this->_loadNetDns();
-
-            $response = $this->_resolver->query($host, 'MX');
-            if (!$response) {
-                return false;
-            }
-
-            foreach ($response->answer as $rr) {
-                if ($rr->type == 'MX') {
-                    $mx[$rr->exchange] = $rr->preference;
-                }
-            }
-        } else {
-            $mxHost = $mxWeight = array();
-
-            if (!getmxrr($host, $mxHost, $mxWeight)) {
-                return false;
-            }
-
-            for ($i = 0; $i < count($mxHost); ++$i) {
-                $mx[$mxHost[$i]] = $mxWeight[$i];
-            }
-        }
-
-        asort($mx);
-
-        return $mx;
-    }
-
-    /**
-     * Initialize Net_DNS_Resolver.
-     */
-    protected function _loadNetDns()
-    {
-        if (!$this->_resolver) {
-            if (!class_exists('Net_DNS_Resolver')) {
-                $this->_error('no_resolver');
-            }
-
-            $this->_resolver = new Net_DNS_Resolver();
-            if ($this->_params['debug']) {
-                $this->_resolver->test = 1;
-            }
-        }
-    }
-
-    /**
-     * Format error message.
-     *
-     * @param string $id   Maps error ids to codes and message.
-     * @param array $info  Optional information in associative array.
-     *
-     * @throws Horde_Mail_Exception
-     */
-    protected function _error($id, $info = array())
-    {
-        $msg = $this->_errorCode[$id]['msg'];
-
-        // include info to messages
-        if (!empty($info)) {
-            $replace = $search = array();
-
-            foreach ($info as $key => $value) {
-                $search[] = '{' . strtoupper($key) . '}';
-                $replace[] = $value;
-            }
-
-            $msg = str_replace($search, $replace, $msg);
-        }
-
-        throw new Horde_Mail_Exception($msg, $this->_errorCode[$id]['code']);
-    }
-
-}
diff --git a/framework/Mail/lib/Horde/Mail/Transport.php b/framework/Mail/lib/Horde/Mail/Transport.php
new file mode 100644 (file)
index 0000000..23edadf
--- /dev/null
@@ -0,0 +1,213 @@
+<?php
+/**
+ * Mail transport base class.
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2002-2007, Richard Heyes
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * o The names of the authors may not be used to endorse or promote
+ *   products derived from this software without specific prior written
+ *   permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category    Mail
+ * @package     Mail
+ * @author      Chuck Hagenbuch <chuck@horde.org>
+ * @author      Michael Slusarz <slusarz@horde.org>
+ * @copyright   1997-2010 Chuck Hagenbuch
+ * @copyright   2010 Michael Slusarz
+ * @license     http://opensource.org/licenses/bsd-license.php New BSD License
+ */
+
+/**
+ * Mail transport base class.
+ *
+ * @access public
+ * @version $Revision: 294747 $
+ * @package Mail
+ */
+abstract class Horde_Mail_Transport
+{
+    /**
+     * Line terminator used for separating header lines.
+     *
+     * @var string
+     */
+    public $sep = "\r\n";
+
+    /**
+     * Configuration parameters.
+     *
+     * @var array
+     */
+    protected $_params = array();
+
+    /**
+     * Send a message.
+     *
+     * @param mixed $recipients  Either a comma-seperated list of recipients
+     *                           (RFC822 compliant), or an array of
+     *                           recipients, each RFC822 valid. This may
+     *                           contain recipients not specified in the
+     *                           headers, for Bcc:, resending messages, etc.
+     * @param array $headers     The headers to send with the mail, in an
+     *                           associative array, where the array key is the
+     *                           header name (ie, 'Subject'), and the array
+     *                           value is the header value (ie, 'test'). The
+     *                           header produced from those values would be
+     *                           'Subject: test'.
+     *                           If the '_raw' key exists, the value of this
+     *                           key will be used as the exact text for
+     *                           sending the message.
+     * @param mixed $body        The full text of the message body, including
+     *                           any Mime parts, etc. Either a string or a
+     *                           stream resource.
+     *
+     * @throws Horde_Mail_Exception
+     */
+    abstract public function send($recipients, array $headers, $body);
+
+    /**
+     * Take an array of mail headers and return a string containing text
+     * usable in sending a message.
+     *
+     * @param array $headers  The array of headers to prepare, in an
+     *                        associative array, where the array key is the
+     *                        header name (ie, 'Subject'), and the array value
+     *                        is the header value (ie, 'test'). The header
+     *                        produced from those values would be 'Subject:
+     *                        test'.
+     *                        If the '_raw' key exists, the value of this key
+     *                        will be used as the exact text for sending the
+     *                        message.
+     *
+     * @return mixed  Returns false if it encounters a bad address; otherwise
+     *                returns an array containing two elements: Any From:
+     *                address found in the headers, and the plain text version
+     *                of the headers.
+     * @throws Horde_Mail_Exception
+     */
+    public function prepareHeaders(array $headers)
+    {
+        $lines = array();
+        $from = null;
+
+        $parser = new Horde_Mail_Rfc822();
+
+        foreach ($headers as $key => $value) {
+            if (strcasecmp($key, 'From') === 0) {
+                $addresses = $parser->parseAddressList($value, array(
+                    'nest_groups' => false,
+                ));
+                $from = $addresses[0]->mailbox . '@' . $addresses[0]->host;
+
+                // Reject envelope From: addresses with spaces.
+                if (strstr($from, ' ')) {
+                    return false;
+                }
+
+                $lines[] = $key . ': ' . $value;
+            } elseif (strcasecmp($key, 'Received') === 0) {
+                $received = array();
+                if (!is_array($value)) {
+                    $value = array($value);
+                }
+
+                foreach ($value as $line) {
+                    $received[] = $key . ': ' . $line;
+                }
+
+                // Put Received: headers at the top.  Spam detectors often
+                // flag messages with Received: headers after the Subject:
+                // as spam.
+                $lines = array_merge($received, $lines);
+            } else {
+                // If $value is an array (i.e., a list of addresses), convert
+                // it to a comma-delimited string of its elements (addresses).
+                if (is_array($value)) {
+                    $value = implode(', ', $value);
+                }
+                $lines[] = $key . ': ' . $value;
+            }
+        }
+
+        return array($from, isset($headers['_raw']) ? $headers['_raw'] : join($this->sep, $lines));
+    }
+
+    /**
+     * Take a set of recipients and parse them, returning an array of bare
+     * addresses (forward paths) that can be passed to sendmail or an SMTP
+     * server with the 'RCPT TO:' command.
+     *
+     * @param mixed  Either a comma-separated list of recipients (RFC822
+     *               compliant), or an array of recipients, each RFC822 valid.
+     *
+     * @return array  Forward paths (bare addresses).
+     * @throws Horde_Mail_Exception
+     */
+    public function parseRecipients($recipients)
+    {
+        // if we're passed an array, assume addresses are valid and
+        // implode them before parsing.
+        if (is_array($recipients)) {
+            $recipients = implode(', ', $recipients);
+        }
+
+        // Parse recipients, leaving out all personal info. This is
+        // for smtp recipients, etc. All relevant personal information
+        // should already be in the headers.
+        $parser = new Horde_Mail_Rfc822();
+        $addresses = $parser->parseAddressList($recipients, array(
+            'nest_groups' => false
+        ));
+
+        $recipients = array();
+        if (is_array($addresses)) {
+            foreach ($addresses as $ob) {
+                $recipients[] = $ob->mailbox . '@' . $ob->host;
+            }
+        }
+
+        return $recipients;
+    }
+
+    /**
+     * Sanitize an array of mail headers by removing any additional header
+     * strings present in a legitimate header's value.  The goal of this
+     * filter is to prevent mail injection attacks.
+     *
+     * @param array $headers  The associative array of headers to sanitize.
+     *
+     * @return array  The sanitized headers.
+     */
+    protected function _sanitizeHeaders($headers)
+    {
+        foreach (array_keys($headers) as $key) {
+            $headers[$key] = preg_replace('=((<CR>|<LF>|0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', null, $headers[$key]);
+        }
+
+        return $headers;
+    }
+}
diff --git a/framework/Mail/lib/Horde/Mail/Transport/Mail.php b/framework/Mail/lib/Horde/Mail/Transport/Mail.php
new file mode 100644 (file)
index 0000000..a8300d3
--- /dev/null
@@ -0,0 +1,148 @@
+<?php
+/**
+ * Internal PHP-mail() interface.
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2010 Chuck Hagenbuch
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * o The names of the authors may not be used to endorse or promote
+ *   products derived from this software without specific prior written
+ *   permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category  Horde
+ * @package   Mail
+ * @author    Chuck Hagenbuch <chuck@horde.org>
+ * @author    Michael Slusarz <slusarz@horde.org>
+ * @copyright 2010 Chuck Hagenbuch
+ * @copyright 2010 Michael Slusarz
+ * @license   http://opensource.org/licenses/bsd-license.php New BSD License
+ */
+
+/**
+ * Internal PHP-mail() interface.
+ *
+ * @category Horde
+ * @package  Mail
+ */
+class Horde_Mail_Transport_Mail extends Horde_Mail_Transport
+{
+    /**
+     * Constructor.
+     *
+     * @param array $params  Additional parameters:
+     * <pre>
+     * 'args' - (string) Extra arguments for the mail() function.
+     * </pre>
+     */
+    public function __construct(array $params = array())
+    {
+        $this->_params = array_merge($this->_params, $params);
+
+        /* Because the mail() function may pass headers as command
+         * line arguments, we can't guarantee the use of the standard
+         * "\r\n" separator.  Instead, we use the system's native line
+         * separator. */
+        $this->sep = defined('PHP_EOL')
+            ? PHP_EOL
+            : (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n";
+    }
+
+    /**
+     * Send a message.
+     *
+     * @param mixed $recipients  Either a comma-seperated list of recipients
+     *                           (RFC822 compliant), or an array of
+     *                           recipients, each RFC822 valid. This may
+     *                           contain recipients not specified in the
+     *                           headers, for Bcc:, resending messages, etc.
+     * @param array $headers     The headers to send with the mail, in an
+     *                           associative array, where the array key is the
+     *                           header name (ie, 'Subject'), and the array
+     *                           value is the header value (ie, 'test'). The
+     *                           header produced from those values would be
+     *                           'Subject: test'.
+     *                           If the '_raw' key exists, the value of this
+     *                           key will be used as the exact text for
+     *                           sending the message.
+     * @param mixed $body        The full text of the message body, including
+     *                           any Mime parts, etc. Either a string or a
+     *                           stream resource.
+     *
+     * @throws Horde_Mail_Exception
+     */
+    public function send($recipients, array $headers, $body)
+    {
+        $headers = $this->_sanitizeHeaders($headers);
+
+        // If we're passed an array of recipients, implode it.
+        if (is_array($recipients)) {
+            $recipients = array_map('trim', implode(',', $recipients));
+        }
+
+        $subject = '';
+
+        foreach (array_keys($headers) as $hdr) {
+            if (strcasecmp($hdr, 'Subject') === 0) {
+                // Get the Subject out of the headers array so that we can
+                // pass it as a separate argument to mail().
+                $subject = $headers[$hdr];
+                unset($headers[$hdr]);
+            } elseif (strcasecmp($hdr, 'To') === 0) {
+                // Remove the To: header.  The mail() function will add its
+                // own To: header based on the contents of $recipients.
+                unset($headers[$hdr]);
+            }
+        }
+
+        // Flatten the headers out.
+        list(, $text_headers) = $this->prepareHeaders($headers);
+
+        // mail() requires a string for $body. If resource, need to convert
+        // to a string.
+        if (is_resource($body)) {
+            $body_str = '';
+            rewind($body);
+            while (!feof($body)) {
+                $body_str .= fread($body, 8192);
+            }
+            $body = $body_str;
+        }
+
+        // We only use mail()'s optional fifth parameter if the additional
+        // parameters have been provided and we're not running in safe mode.
+        if (empty($this->_params) || ini_get('safe_mode')) {
+            $result = mail($recipients, $subject, $body, $text_headers);
+        } else {
+            $result = mail($recipients, $subject, $body, $text_headers, isset($this->_params['args']) ? $this->_params['args'] : '');
+        }
+
+        // If the mail() function returned failure, we need to create an
+        // Exception and return it instead of the boolean result.
+        if ($result === false) {
+            throw new Horde_Mail_Exception('mail() returned failure.');
+        }
+    }
+}
diff --git a/framework/Mail/lib/Horde/Mail/Transport/Mock.php b/framework/Mail/lib/Horde/Mail/Transport/Mock.php
new file mode 100644 (file)
index 0000000..4b1de5d
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+/**
+ * Mock mail transport.
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2010 Chuck Hagenbuch
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * o The names of the authors may not be used to endorse or promote
+ *   products derived from this software without specific prior written
+ *   permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category  Horde
+ * @package   Mail
+ * @author    Chuck Hagenbuch <chuck@horde.org>
+ * @copyright 2010 Chuck Hagenbuch
+ * @license   http://opensource.org/licenses/bsd-license.php New BSD License
+ */
+
+/**
+ * Mock implementation, for testing.
+ *
+ * @category Horde
+ * @package  Mail
+ */
+class Horde_Mail_Transport_Mock extends Horde_Mail_Transport
+{
+    /**
+     * Array of messages that have been sent with the mock.
+     *
+     * @var array
+     */
+    public $sentMessages = array();
+
+    /**
+     * Callback before sending mail.
+     *
+     * @var callback
+     */
+    protected $_preSendCallback;
+
+    /**
+     * Callback after sending mai.
+     *
+     * @var callback
+     */
+    protected $_postSendCallback;
+
+    /**
+     * Constructor.
+     *
+     * @param array  Optional parameters:
+     * <pre>
+     * 'preSendCallback' - (callback) Called before an email would be sent.
+     * 'postSendCallback' - (callback) Called after an email would have been
+     *                      sent.
+     * </pre>
+     */
+    public function __construct(array $params = array())
+    {
+        if (isset($params['preSendCallback']) &&
+            is_callable($params['preSendCallback'])) {
+            $this->_preSendCallback = $params['preSendCallback'];
+        }
+
+        if (isset($params['postSendCallback']) &&
+            is_callable($params['postSendCallback'])) {
+            $this->_postSendCallback = $params['postSendCallback'];
+        }
+    }
+
+    /**
+     * Send a message. Silently discards all mail.
+     *
+     * @param mixed $recipients  Either a comma-seperated list of recipients
+     *                           (RFC822 compliant), or an array of
+     *                           recipients, each RFC822 valid. This may
+     *                           contain recipients not specified in the
+     *                           headers, for Bcc:, resending messages, etc.
+     * @param array $headers     The headers to send with the mail, in an
+     *                           associative array, where the array key is the
+     *                           header name (ie, 'Subject'), and the array
+     *                           value is the header value (ie, 'test'). The
+     *                           header produced from those values would be
+     *                           'Subject: test'.
+     *                           If the '_raw' key exists, the value of this
+     *                           key will be used as the exact text for
+     *                           sending the message.
+     * @param mixed $body        The full text of the message body, including
+     *                           any Mime parts, etc. Either a string or a
+     *                           stream resource.
+     *
+     * @throws Horde_Mail_Exception
+     */
+    public function send($recipients, array $headers, $body)
+    {
+        if ($this->_preSendCallback) {
+            call_user_func_array($this->_preSendCallback, array($this, $recipients, $headers, $body));
+        }
+
+        $headers = $this->_sanitizeHeaders($headers);
+        list(, $text_headers) = $this->prepareHeaders($headers);
+
+        $this->sentMessages[] = array(
+            'body' => $body,
+            'headers' => $headers,
+            'header_text' => $text_headers,
+            'recipients' => $recipients
+        );
+
+        if ($this->_postSendCallback) {
+            call_user_func_array($this->_postSendCallback, array($this, $recipients, $headers, $body));
+        }
+    }
+}
diff --git a/framework/Mail/lib/Horde/Mail/Transport/Null.php b/framework/Mail/lib/Horde/Mail/Transport/Null.php
new file mode 100644 (file)
index 0000000..b397462
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Null implementation of the mail transport interface.
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2010 Phil Kernick
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * o The names of the authors may not be used to endorse or promote
+ *   products derived from this software without specific prior written
+ *   permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category    Horde
+ * @package     Mail
+ * @author      Phil Kernick <philk@rotfl.com.au>
+ * @copyright   2010 Phil Kernick
+ * @license     http://opensource.org/licenses/bsd-license.php New BSD License
+ */
+
+/**
+ * Null implementation of the mail transport interface.
+ *
+ * @category Horde
+ * @package  Mail
+ */
+class Horde_Mail_Transport_Null extends Horde_Mail_Transport
+{
+    /**
+     * Send a message.
+     *
+     * @param mixed $recipients  Either a comma-seperated list of recipients
+     *                           (RFC822 compliant), or an array of
+     *                           recipients, each RFC822 valid. This may
+     *                           contain recipients not specified in the
+     *                           headers, for Bcc:, resending messages, etc.
+     * @param array $headers     The headers to send with the mail, in an
+     *                           associative array, where the array key is the
+     *                           header name (ie, 'Subject'), and the array
+     *                           value is the header value (ie, 'test'). The
+     *                           header produced from those values would be
+     *                           'Subject: test'.
+     *                           If the '_raw' key exists, the value of this
+     *                           key will be used as the exact text for
+     *                           sending the message.
+     * @param mixed $body        The full text of the message body, including
+     *                           any Mime parts, etc. Either a string or a
+     *                           stream resource.
+     *
+     * @throws Horde_Mail_Exception
+     */
+    public function send($recipients, array $headers, $body)
+    {
+    }
+}
diff --git a/framework/Mail/lib/Horde/Mail/Transport/Sendmail.php b/framework/Mail/lib/Horde/Mail/Transport/Sendmail.php
new file mode 100644 (file)
index 0000000..cf7f624
--- /dev/null
@@ -0,0 +1,246 @@
+<?php
+/**
+ * Sendmail interface.
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2010 Chuck Hagenbuch
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * o The names of the authors may not be used to endorse or promote
+ *   products derived from this software without specific prior written
+ *   permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category  Horde
+ * @package   Mail
+ * @author    Chuck Hagenbuch <chuck@horde.org>
+ * @author    Michael Slusarz <slusarz@horde.org>
+ * @copyright 2010 Chuck Hagenbuch
+ * @copyright 2010 Michael Slusarz
+ * @license   http://opensource.org/licenses/bsd-license.php New BSD License
+ */
+
+/**
+ * Sendmail interface.
+ *
+ * @category Horde
+ * @package  Mail
+ */
+class Horde_Mail_Transport_Sendmail extends Horde_Mail_Transport
+{
+    /**
+     * Any extra command-line parameters to pass to the sendmail or
+     * sendmail wrapper binary.
+     *
+     * @var string
+     */
+    protected $_sendmailArgs = '-i';
+
+    /**
+     * The location of the sendmail or sendmail wrapper binary on the
+     * filesystem.
+     *
+     * @var string
+     */
+    protected $_sendmailPath = '/usr/sbin/sendmail';
+
+    /**
+     * Constructor.
+     *
+     * @param array $params  Additional parameters:
+     * <pre>
+     * 'sendmail_args' - (string) Any extra parameters to pass to the sendmail
+     *                   or sendmail wrapper binary.
+     *                   DEFAULT: -i
+     * 'sendmail_path' - (string) The location of the sendmail binary on the
+     *                   filesystem.
+     *                   DEFAULT: /usr/sbin/sendmail
+     * </pre>
+     */
+    public function __construct(array $params = array())
+    {
+        if (isset($params['sendmail_args'])) {
+            $this->_sendmailArgs = $params['sendmail_args'];
+        }
+
+        if (isset($params['sendmail_path'])) {
+            $this->_sendmailPath = $params['sendmail_path'];
+        }
+
+        /* Because we need to pass message headers to the sendmail program on
+         * the commandline, we can't guarantee the use of the standard "\r\n"
+         * separator.  Instead, we use the system's native line separator. */
+        $this->sep = defined('PHP_EOL')
+            ? PHP_EOL
+            : (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n";
+    }
+
+    /**
+     * Send a message.
+     *
+     * @param mixed $recipients  Either a comma-seperated list of recipients
+     *                           (RFC822 compliant), or an array of
+     *                           recipients, each RFC822 valid. This may
+     *                           contain recipients not specified in the
+     *                           headers, for Bcc:, resending messages, etc.
+     * @param array $headers     The headers to send with the mail, in an
+     *                           associative array, where the array key is the
+     *                           header name (ie, 'Subject'), and the array
+     *                           value is the header value (ie, 'test'). The
+     *                           header produced from those values would be
+     *                           'Subject: test'.
+     *                           If the '_raw' key exists, the value of this
+     *                           key will be used as the exact text for
+     *                           sending the message.
+     * @param mixed $body        The full text of the message body, including
+     *                           any Mime parts, etc. Either a string or a
+     *                           stream resource.
+     *
+     * @throws Horde_Mail_Exception
+     */
+    public function send($recipients, array $headers, $body)
+    {
+        $recipients = implode(' ', array_map('escapeshellarg', $this->parseRecipients($recipients)));
+
+        $headers = $this->_sanitizeHeaders($headers);
+        list($from, $text_headers) = $this->prepareHeaders($headers);
+
+        /* Since few MTAs are going to allow this header to be forged
+         * unless it's in the MAIL FROM: exchange, we'll use Return-Path
+         * instead of From: if it's set. */
+        foreach (array_keys($headers) as $hdr) {
+            if (strcasecmp($hdr, 'Return-Path') === 0) {
+                $from = $headers[$hdr];
+                break;
+            }
+        }
+
+        if (!strlen($from)) {
+            throw new Horde_Mail_Exception('No From address given.');
+        } elseif ((strpos($from, ' ') !== false) ||
+                  (strpos($from, ';') !== false) ||
+                  (strpos($from, '&') !== false) ||
+                  (strpos($from, '`') !== false)) {
+            throw new Horde_Mail_Exception('From address specified with dangerous characters.');
+        }
+
+        $mail = @popen($this->_sendmailPath . (empty($this->_sendmailArgs) ? '' : ' ' . $this->_sendmailargs) . ' -f' . escapeshellarg($from) . ' -- ' . $recipients, 'w');
+        if (!$mail) {
+            throw new Horde_Mail_Exception('Failed to open sendmail [' . $this->_sendmailPath . '] for execution.');
+        }
+
+        // Write the headers following by two newlines: one to end the headers
+        // section and a second to separate the headers block from the body.
+        fputs($mail, $text_headers . $this->sep . $this->sep);
+
+        if (is_resource($body)) {
+            rewind($body);
+            while (!feof($body)) {
+                fputs($mail, fread($body, 8192));
+            }
+        } else {
+            fputs($mail, $body);
+        }
+        $result = pclose($mail);
+
+        if (!$result) {
+            return;
+        }
+
+        switch ($result) {
+        case 64: // EX_USAGE
+            $msg = 'command line usage error';
+            break;
+
+        case 65: // EX_DATAERR
+            $msg =  'data format error';
+            break;
+
+        case 66: // EX_NOINPUT
+            $msg = 'cannot open input';
+            break;
+
+        case 67: // EX_NOUSER
+            $msg = 'addressee unknown';
+            break;
+
+        case 68: // EX_NOHOST
+            $msg = 'host name unknown';
+            break;
+
+        case 69: // EX_UNAVAILABLE
+            $msg = 'service unavailable';
+            break;
+
+        case 70: // EX_SOFTWARE
+            $msg = 'internal software error';
+            break;
+
+        case 71: // EX_OSERR
+            $msg = 'system error';
+            break;
+
+        case 72: // EX_OSFILE
+            $msg = 'critical system file missing';
+            break;
+
+        case 73: // EX_CANTCREAT
+            $msg = 'cannot create output file';
+            break;
+
+        case 74: // EX_IOERR
+            $msg = 'input/output error';
+
+        case 75: // EX_TEMPFAIL
+            $msg = 'temporary failure';
+            break;
+
+        case 76: // EX_PROTOCOL
+            $msg = 'remote error in protocol';
+            break;
+
+        case 77: // EX_NOPERM
+            $msg = 'permission denied';
+            break;
+
+        case 77: // EX_NOPERM
+            $msg = 'permission denied';
+            break;
+
+        case 78: // EX_CONFIG
+            $msg = 'configuration error';
+            break;
+
+        case 79: // EX_NOTFOUND
+            $msg = 'entry not found';
+            break;
+
+        default:
+            $msg = 'unknown error';
+            break;
+        }
+
+        throw new Horde_Mail_Exception('sendmail: ' . $msg . ' (' . $result . ')', $result);
+    }
+}
diff --git a/framework/Mail/lib/Horde/Mail/Transport/Smtp.php b/framework/Mail/lib/Horde/Mail/Transport/Smtp.php
new file mode 100644 (file)
index 0000000..a43b2c2
--- /dev/null
@@ -0,0 +1,355 @@
+<?php
+/**
+ * SMTP implementation.
+ * Requires the Net_SMTP class.
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2010, Chuck Hagenbuch
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * o The names of the authors may not be used to endorse or promote
+ *   products derived from this software without specific prior written
+ *   permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category  Horde
+ * @package   Mail
+ * @author    Jon Parise <jon@php.net>
+ * @author    Chuck Hagenbuch <chuck@horde.org>
+ * @copyright 2010 Chuck Hagenbuch
+ * @license   http://opensource.org/licenses/bsd-license.php New BSD License
+ */
+
+/**
+ * SMTP implementation.
+ *
+ * @category Horde
+ * @package  Mail
+ */
+class Horde_Mail_Transport_Smtp extends Horde_Mail_Transport
+{
+    /* Error: Failed to create a Net_SMTP object */
+    const ERROR_CREATE = 10000;
+
+    /* Error: Failed to connect to SMTP server */
+    const ERROR_CONNECT = 10001;
+
+    /* Error: SMTP authentication failure */
+    const ERROR_AUTH = 10002;
+
+    /* Error: No From: address has been provided */
+    const ERROR_FROM = 10003;
+
+    /* Error: Failed to set sender */
+    const ERROR_SENDER = 10004;
+
+    /* Error: Failed to add recipient */
+    const ERROR_RECIPIENT = 10005;
+
+    /* Error: Failed to send data */
+    const ERROR_DATA = 10006;
+
+    /**
+     * The SMTP greeting.
+     *
+     * @var string
+     */
+    public $greeting = null;
+
+    /**
+     * The SMTP queued response.
+     *
+     * @var string
+     */
+    public $queuedAs = null;
+
+    /**
+     * SMTP connection object.
+     *
+     * @var Net_SMTP
+     */
+    protected $_smtp = null;
+
+    /**
+     * The list of service extension parameters to pass to the Net_SMTP
+     * mailFrom() command.
+     *
+     * @var array
+     */
+    protected $_extparams = array();
+
+    /**
+     * Constructor.
+     *
+     * @param array $params  Additional parameters:
+     * <pre>
+     * 'auth' - (mixed) SMTP authentication.
+     *          This value may be set to true, false or the name of a specific
+     *          authentication method.
+     *          If the value is set to true, the Net_SMTP package will attempt
+     *          to use the best authentication method advertised by the remote
+     *          SMTP server.
+     *          DEFAULT: false.
+     * 'debug' - (boolean) Activate SMTP debug mode?
+     *           DEFAULT: false
+     * 'host' - (string) The server to connect to.
+     *          DEFAULT: localhost
+     * 'localhost' - (string) Hostname or domain that will be sent to the
+     *               remote SMTP server in the HELO / EHLO message.
+     *               DEFAULT: localhost
+     * 'password' - (string) The password to use for SMTP auth.
+     *              DEFAULT: NONE
+     * 'persist' - (boolean) Should the SMTP connection persist?
+     *             DEFAULT: false
+     * 'pipelining' - (boolean) Use SMTP command pipelining.
+     *                Use SMTP command pipelining (specified in RFC 2920) if
+     *                the SMTP server supports it. This speeds up delivery
+     *                over high-latency connections.
+     *                DEFAULT: false (use default value from Net_SMTP)
+     * 'port' - (integer) The port to connect to.
+     *          DEFAULT: 25
+     * 'timeout' - (integer) The SMTP connection timeout.
+     *             DEFAULT: NONE
+     * 'username' - (string) The username to use for SMTP auth.
+     *              DEFAULT: NONE
+     * </pre>
+     */
+    public function __construct(array $params = array())
+    {
+        $this->_params = array_merge(array(
+            'auth' => false,
+            'debug' => false,
+            'host' => 'localhost',
+            'localhost' => 'localhost',
+            'password' => '',
+            'persist' => false,
+            'pipelining' => false,
+            'port' => 25,
+            'timeout' => null,
+            'username' => ''
+        ), $params);
+
+        /* Destructor implementation to ensure that we disconnect from any
+         * potentially-alive persistent SMTP connections. */
+        register_shutdown_function(array($this, 'disconnect'));
+    }
+
+    /**
+     * Send a message.
+     *
+     * @param mixed $recipients  Either a comma-seperated list of recipients
+     *                           (RFC822 compliant), or an array of
+     *                           recipients, each RFC822 valid. This may
+     *                           contain recipients not specified in the
+     *                           headers, for Bcc:, resending messages, etc.
+     * @param array $headers     The headers to send with the mail, in an
+     *                           associative array, where the array key is the
+     *                           header name (ie, 'Subject'), and the array
+     *                           value is the header value (ie, 'test'). The
+     *                           header produced from those values would be
+     *                           'Subject: test'.
+     *                           If the '_raw' key exists, the value of this
+     *                           key will be used as the exact text for
+     *                           sending the message.
+     * @param mixed $body        The full text of the message body, including
+     *                           any Mime parts, etc. Either a string or a
+     *                           stream resource.
+     *
+     * @throws Horde_Mail_Exception
+     */
+    public function send($recipients, array $headers, $body)
+    {
+        /* If we don't already have an SMTP object, create one. */
+        $this->getSMTPObject();
+
+        $headers = $this->_sanitizeHeaders($headers);
+
+        try {
+            list($from, $textHeaders) = $this->prepareHeaders($headers);
+        } catch (Horde_Mail_Exception $e) {
+            $this->_smtp->rset();
+            throw $e;
+        }
+
+        /* Since few MTAs are going to allow this header to be forged unless
+         * it's in the MAIL FROM: exchange, we'll use Return-Path instead of
+         * From: if it's set. */
+        foreach (array_keys($headers) as $hdr) {
+            if (strcasecmp($hdr, 'Return-Path') === 0) {
+                $from = $headers[$hdr];
+                break;
+            }
+        }
+
+        if (!strlen($from)) {
+            $this->_smtp->rset();
+            throw new Horde_Mail_Exception('No From: address has been provided', self::ERROR_FROM);
+        }
+
+        $params = '';
+        foreach ($this->_extparams as $key => $val) {
+            $params .= ' ' . $key . (is_null($val) ? '' : '=' . $val);
+        }
+
+        $res = $this->_smtp->mailFrom($from, ltrim($params));
+        if ($res instanceof PEAR_Error) {
+            $this->_smtp->rset();
+            $this->_error("Failed to set sender: $from", $res, self::ERROR_SENDER);
+        }
+
+        try {
+            $recipients = $this->parseRecipients($recipients);
+        } catch (Horde_Mail_Exception $e) {
+            $this->_smtp->rset();
+            throw $e;
+        }
+
+        foreach ($recipients as $recipient) {
+            $res = $this->_smtp->rcptTo($recipient);
+            if ($res instanceof PEAR_Error) {
+                $this->_smtp->rset();
+                $this->_error("Failed to add recipient: $recipient", $res, self::ERROR_RECIPIENT);
+            }
+        }
+
+        /* Send the message's headers and the body as SMTP data. */
+        $res = $this->_smtp->data($body, $textHeaders);
+               list(,$args) = $this->_smtp->getResponse();
+
+               if (preg_match("/Ok: queued as (.*)/", $args, $queued)) {
+                       $this->queuedAs = $queued[1];
+               }
+
+        /* We need the greeting; from it we can extract the authorative name
+         * of the mail server we've really connected to. Ideal if we're
+         * connecting to a round-robin of relay servers and need to track
+         * which exact one took the email */
+               $this->greeting = $this->_smtp->getGreeting();
+
+        if ($res instanceof PEAR_Error) {
+            $this->_smtp->rset();
+            $this->_error('Failed to send data', $res, self::ERROR_DATA);
+        }
+
+        /* If persistent connections are disabled, destroy our SMTP object. */
+        if ($this->_params['persist']) {
+            $this->disconnect();
+        }
+    }
+
+    /**
+     * Connect to the SMTP server by instantiating a Net_SMTP object.
+     *
+     * @return Net_SMTP  The SMTP object.
+     * @throws Horde_Mail_Exception
+     */
+    public function getSMTPObject()
+    {
+        if ($this->_smtp) {
+            return $this->_smtp;
+        }
+
+        $this->_smtp = new Net_SMTP(
+            $this->_params['host'],
+            $this->_params['port'],
+            $this->_params['localhost']
+        );
+
+        /* If we still don't have an SMTP object at this point, fail. */
+        if (!($this->_smtp instanceof Net_SMTP)) {
+            throw new Horde_Mail_Exception('Failed to create a Net_SMTP object', self::ERROR_CREATE);
+        }
+
+        /* Configure the SMTP connection. */
+        if ($this->_params['debug']) {
+            $this->_smtp->setDebug(true);
+        }
+
+        /* Attempt to connect to the configured SMTP server. */
+        $res = $this->_smtp->connect($this->_params['timeout']);
+        if ($res instanceof PEAR_Error) {
+            $this->_error('Failed to connect to ' . $this->_params['host'] . ':' . $this->_params['port'], $res, self::ERROR_CONNECT);
+        }
+
+        /* Attempt to authenticate if authentication has been enabled. */
+        if ($this->_params['auth']) {
+            $method = is_string($this->_params['auth'])
+                ? $this->_params['auth']
+                : '';
+
+            $res = $this->_smtp->auth($this->_params['username'], $this->_params['password'], $method);
+            if ($res instanceof PEAR_Error) {
+                $this->_smtp->rset();
+                $this->_error("$method authentication failure", $res, self::ERROR_AUTH);
+            }
+        }
+
+        return $this->_smtp;
+    }
+
+    /**
+     * Add parameter associated with a SMTP service extension.
+     *
+     * @param string $keyword  Extension keyword.
+     * @param string $value    Any value the keyword needs.
+     */
+    public function addServiceExtensionParameter($keyword, $value = null)
+    {
+        $this->_extparams[$keyword] = $value;
+    }
+
+    /**
+     * Disconnect and destroy the current SMTP connection.
+     *
+     * @return boolean True if the SMTP connection no longer exists.
+     */
+    public function disconnect()
+    {
+        /* If we have an SMTP object, disconnect and destroy it. */
+        if (is_object($this->_smtp) && $this->_smtp->disconnect()) {
+            $this->_smtp = null;
+        }
+
+        /* We are disconnected if we no longer have an SMTP object. */
+        return ($this->_smtp === null);
+    }
+
+    /**
+     * Build a standardized string describing the current SMTP error.
+     *
+     * @param string $text       Custom string describing the error context.
+     * @param PEAR_Error $error  PEAR_Error object.
+     * @param integer $e_code    Error code.
+     *
+     * @throws Horde_Mail_Exception
+     */
+    protected function _error($text, $error, $e_code)
+    {
+        /* Split the SMTP response into a code and a response string. */
+        list($code, $response) = $this->_smtp->getResponse();
+
+        /* Build our standardized error string. */
+        throw new Horde_Mail_Exception($text . ' [SMTP: ' . $error->getMessage() . " (code: $code, response: $response)]", $e_code);
+    }
+}
diff --git a/framework/Mail/lib/Horde/Mail/Transport/Smtpmx.php b/framework/Mail/lib/Horde/Mail/Transport/Smtpmx.php
new file mode 100644 (file)
index 0000000..235795c
--- /dev/null
@@ -0,0 +1,388 @@
+<?PHP
+/**
+ * SMTP MX implementation.
+ * Requires the Net_SMTP class.
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2010, gERD Schaufelberger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * o The names of the authors may not be used to endorse or promote
+ *   products derived from this software without specific prior written
+ *   permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Horde
+ * @package    Mail
+ * @author     gERD Schaufelberger <gerd@php-tools.net>
+ * @copyright  2010 gERD Schaufelberger
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ */
+
+/**
+ * SMTP MX implementation.
+ *
+ * @author   gERD Schaufelberger <gerd@php-tools.net>
+ * @category Horde
+ * @package  Mail
+ */
+class Horde_Mail_Transport_Smtpmx extends Horde_Mail_Transport
+{
+    /**
+     * SMTP connection object.
+     *
+     * @var Net_SMTP
+     */
+    protected $_smtp = null;
+
+    /**
+     * Net_DNS_Resolver object.
+     *
+     * @var Net_DNS_Resolver
+     */
+    protected $_resolver;
+
+    /**
+     * Internal error codes.
+     * Translate internal error identifier to human readable messages.
+     *
+     * @var array
+     */
+    protected $_errorCode = array(
+        'not_connected' => array(
+            'code' => 1,
+            'msg' => 'Could not connect to any mail server ({HOST}) at port {PORT} to send mail to {RCPT}.'
+        ),
+        'failed_vrfy_rcpt' => array(
+            'code' => 2,
+            'msg' => 'Recipient "{RCPT}" could not be veryfied.'
+        ),
+        'failed_set_from' => array(
+            'code' => 3,
+            'msg' => 'Failed to set sender: {FROM}.'
+        ),
+        'failed_set_rcpt' => array(
+            'code' => 4,
+            'msg' => 'Failed to set recipient: {RCPT}.'
+        ),
+        'failed_send_data' => array(
+            'code' => 5,
+            'msg' => 'Failed to send mail to: {RCPT}.'
+        ),
+        'no_from' => array(
+            'code' => 5,
+            'msg' => 'No from address has be provided.'
+        ),
+        'send_data' => array(
+            'code' => 7,
+            'msg' => 'Failed to create Net_SMTP object.'
+        ),
+        'no_mx' => array(
+            'code' => 8,
+            'msg' => 'No MX-record for {RCPT} found.'
+        ),
+        'no_resolver' => array(
+            'code' => 9,
+            'msg' => 'Could not start resolver! Install PEAR:Net_DNS or switch off "netdns"'
+        ),
+        'failed_rset' => array(
+            'code' => 10,
+            'msg' => 'RSET command failed, SMTP-connection corrupt.'
+        )
+    );
+
+    /**
+     * Constructor.
+     *
+     * @param array $params  Additional options:
+     * <pre>
+     * 'debug' - (boolean) Activate SMTP and Net_DNS debug mode?
+     *           DEFAULT: false
+     * 'mailname' - (string) The name of the local mail system (a valid
+     *              hostname which matches the reverse lookup)
+     *              DEFAULT: Auto-determined
+     * 'netdns' - (boolean) Use PEAR:Net_DNS (true) or the PHP builtin
+     *            getmxrr().
+     *            DEFAULT: true
+     * 'port' - (integer) Port.
+     *          DEFAULT: Auto-determined
+     * 'test' - (boolean) Activate test mode?
+     *          DEFAULT: false
+     * 'timeout' - (integer) The SMTP connection timeout (in seconds).
+     *             DEFAULT: 10
+     * 'verp' - (boolean) Whether to use VERP.
+     *          If not a boolean, the string value will be used as the VERP
+     *          separators.
+     *          DEFAULT: false
+     * 'vrfy' - (boolean) Whether to use VRFY.
+     *          DEFAULT: false
+     * </pre>
+     */
+    public function __construct(array $params = array())
+    {
+        /* Try to find a valid mailname. */
+        if (!isset($params['mailname']) && function_exists('posix_uname')) {
+            $uname = posix_uname();
+            $params['mailname'] = $uname['nodename'];
+        }
+
+        if (!isset($params['port'])) {
+            $params['port'] = getservbyname('smtp', 'tcp');
+        }
+
+        $this->_params = array_merge(array(
+            'debug' => false,
+            'mailname' => 'localhost',
+            'netdns' => true,
+            'port' => 25,
+            'test' => false,
+            'timeout' => 10,
+            'verp' => false,
+            'vrfy' => false
+        ), $params);
+    }
+
+    /**
+     * Destructor implementation to ensure that we disconnect from any
+     * potentially-alive persistent SMTP connections.
+     */
+    public function __destruct()
+    {
+        if (is_object($this->_smtp)) {
+            $this->_smtp->disconnect();
+            $this->_smtp = null;
+        }
+    }
+
+    /**
+     * Send a message.
+     *
+     * @param mixed $recipients  Either a comma-seperated list of recipients
+     *                           (RFC822 compliant), or an array of
+     *                           recipients, each RFC822 valid. This may
+     *                           contain recipients not specified in the
+     *                           headers, for Bcc:, resending messages, etc.
+     * @param array $headers     The headers to send with the mail, in an
+     *                           associative array, where the array key is the
+     *                           header name (ie, 'Subject'), and the array
+     *                           value is the header value (ie, 'test'). The
+     *                           header produced from those values would be
+     *                           'Subject: test'.
+     *                           If the '_raw' key exists, the value of this
+     *                           key will be used as the exact text for
+     *                           sending the message.
+     * @param mixed $body        The full text of the message body, including
+     *                           any Mime parts, etc. Either a string or a
+     *                           stream resource.
+     *
+     * @throws Horde_Mail_Exception
+     */
+    public function send($recipients, array $headers, $body)
+    {
+        $headers = $this->_sanitizeHeaders($headers);
+
+        // Prepare headers
+        list($from, $textHeaders) = $this->prepareHeaders($headers);
+
+        // Use 'Return-Path' if possible
+        foreach (array_keys($headers) as $hdr) {
+            if (strcasecmp($hdr, 'Return-Path') === 0) {
+                $from = $headers['Return-Path'];
+                break;
+            }
+        }
+
+        if (!strlen($from)) {
+            $this->_error('no_from');
+        }
+
+        // Prepare recipients
+        foreach ($this->parseRecipients($recipients) as $rcpt) {
+            list($user, $host) = explode('@', $rcpt);
+
+            $mx = $this->_getMx($host);
+            if (!$mx) {
+                $this->_error('no_mx', array('rcpt' => $rcpt));
+            }
+
+            $connected = false;
+            foreach ($mx as $mserver => $mpriority) {
+                $this->_smtp = new Net_SMTP($mserver, $this->_params['port'], $this->_params['mailname']);
+
+                // configure the SMTP connection.
+                if ($this->_params['debug']) {
+                    $this->_smtp->setDebug(true);
+                }
+
+                // attempt to connect to the configured SMTP server.
+                $res = $this->_smtp->connect($this->_params['timeout']);
+                if ($res instanceof PEAR_Error) {
+                    $this->_smtp = null;
+                    continue;
+                }
+
+                // connection established
+                if ($res) {
+                    $connected = true;
+                    break;
+                }
+            }
+
+            if (!$connected) {
+                $this->_error('not_connected', array(
+                    'host' => implode(', ', array_keys($mx)),
+                    'port' => $this->_params['port'],
+                    'rcpt' => $rcpt
+                ));
+            }
+
+            // Verify recipient
+            if ($this->_params['vrfy']) {
+                $res = $this->_smtp->vrfy($rcpt);
+                if ($res instanceof PEAR_Error) {
+                    $this->_error('failed_vrfy_rcpt', array('rcpt' => $rcpt));
+                }
+            }
+
+            // mail from:
+            $args['verp'] = $this->_params['verp'];
+            $res = $this->_smtp->mailFrom($from, $args);
+            if ($res instanceof PEAR_Error) {
+                $this->_error('failed_set_from', array('from' => $from));
+            }
+
+            // rcpt to:
+            $res = $this->_smtp->rcptTo($rcpt);
+            if ($res instanceof PEAR_Error) {
+                $this->_error('failed_set_rcpt', array('rcpt' => $rcpt));
+            }
+
+            // Don't send anything in test mode
+            if ($this->_params['test']) {
+                $res = $this->_smtp->rset();
+                if ($res instanceof PEAR_Error) {
+                    $this->_error('failed_rset');
+                }
+
+                $this->_smtp->disconnect();
+                $this->_smtp = null;
+                return;
+            }
+
+            // Send data
+            $res = $this->_smtp->data($body, $textHeaders);
+            if ($res instanceof PEAR_Error) {
+                $this->_error('failed_send_data', array('rcpt' => $rcpt));
+            }
+
+            $this->_smtp->disconnect();
+            $this->_smtp = null;
+        }
+    }
+
+    /**
+     * Recieve MX records for a host.
+     *
+     * @param string $host  Mail host.
+     *
+     * @return mixed  Sorted MX list or false on error.
+     */
+    protected function _getMx($host)
+    {
+        $mx = array();
+
+        if ($this->params['netdns']) {
+            $this->_loadNetDns();
+
+            $response = $this->_resolver->query($host, 'MX');
+            if (!$response) {
+                return false;
+            }
+
+            foreach ($response->answer as $rr) {
+                if ($rr->type == 'MX') {
+                    $mx[$rr->exchange] = $rr->preference;
+                }
+            }
+        } else {
+            $mxHost = $mxWeight = array();
+
+            if (!getmxrr($host, $mxHost, $mxWeight)) {
+                return false;
+            }
+
+            for ($i = 0; $i < count($mxHost); ++$i) {
+                $mx[$mxHost[$i]] = $mxWeight[$i];
+            }
+        }
+
+        asort($mx);
+
+        return $mx;
+    }
+
+    /**
+     * Initialize Net_DNS_Resolver.
+     */
+    protected function _loadNetDns()
+    {
+        if (!$this->_resolver) {
+            if (!class_exists('Net_DNS_Resolver')) {
+                $this->_error('no_resolver');
+            }
+
+            $this->_resolver = new Net_DNS_Resolver();
+            if ($this->_params['debug']) {
+                $this->_resolver->test = 1;
+            }
+        }
+    }
+
+    /**
+     * Format error message.
+     *
+     * @param string $id   Maps error ids to codes and message.
+     * @param array $info  Optional information in associative array.
+     *
+     * @throws Horde_Mail_Exception
+     */
+    protected function _error($id, $info = array())
+    {
+        $msg = $this->_errorCode[$id]['msg'];
+
+        // include info to messages
+        if (!empty($info)) {
+            $replace = $search = array();
+
+            foreach ($info as $key => $value) {
+                $search[] = '{' . strtoupper($key) . '}';
+                $replace[] = $value;
+            }
+
+            $msg = str_replace($search, $replace, $msg);
+        }
+
+        throw new Horde_Mail_Exception($msg, $this->_errorCode[$id]['code']);
+    }
+}
index 835cd21..af2099a 100644 (file)
@@ -38,15 +38,17 @@ http://pear.php.net/dtd/package-2.0.xsd">
    <dir name="lib">
     <dir name="Horde">
      <dir name="Mail">
-      <file name="Driver.php" role="php" />
+      <dir name="Transport">
+       <file name="Mail.php" role="php" />
+       <file name="Mock.php" role="php" />
+       <file name="Null.php" role="php" />
+       <file name="Sendmail.php" role="php" />
+       <file name="Smtp.php" role="php" />
+       <file name="Smtpmx.php" role="php" />
+      </dir> <!-- /lib/Horde/Mail/Transport -->
       <file name="Exception.php" role="php" />
-      <file name="Mail.php" role="php" />
-      <file name="Mock.php" role="php" />
-      <file name="Null.php" role="php" />
       <file name="Rfc822.php" role="php" />
-      <file name="Sendmail.php" role="php" />
-      <file name="Smtp.php" role="php" />
-      <file name="Smtpmx.php" role="php" />
+      <file name="Transport.php" role="php" />
      </dir> <!-- /lib/Horde/Mail -->
      <file name="Mail.php" role="php" />
     </dir> <!-- /lib/Horde -->
@@ -84,18 +86,16 @@ http://pear.php.net/dtd/package-2.0.xsd">
  </dependencies>
  <phprelease>
   <filelist>
-   <install name="lib/Horde/Mail/Driver.php" as="Horde/Mail/Driver.php" />
+   <install name="lib/Horde/Mail/Transport/Mail.php" as="Horde/Mail/Transport/Mail.php" />
+   <install name="lib/Horde/Mail/Transport/Mock.php" as="Horde/Mail/Transport/Mock.php" />
+   <install name="lib/Horde/Mail/Transport/Null.php" as="Horde/Mail/Transport/Null.php" />
+   <install name="lib/Horde/Mail/Transport/Sendmail.php" as="Horde/Mail/Transport/Sendmail.php" />
+   <install name="lib/Horde/Mail/Transport/Smtp.php" as="Horde/Mail/Transport/Smtp.php" />
+   <install name="lib/Horde/Mail/Transport/Smtpmx.php" as="Horde/Mail/Transport/Smtpmx.php" />
    <install name="lib/Horde/Mail/Exception.php" as="Horde/Mail/Exception.php" />
-   <install name="lib/Horde/Mail/Mail.php" as="Horde/Mail/Mail.php" />
-   <install name="lib/Horde/Mail/Mock.php" as="Horde/Mail/Mock.php" />
-   <install name="lib/Horde/Mail/Null.php" as="Horde/Mail/Null.php" />
    <install name="lib/Horde/Mail/Rfc822.php" as="Horde/Mail/Rfc822.php" />
-   <install name="lib/Horde/Mail/Sendmail.php" as="Horde/Mail/Sendmail.php" />
-   <install name="lib/Horde/Mail/Smtp.php" as="Horde/Mail/Smtp.php" />
-   <install name="lib/Horde/Mail/Smtpmx.php" as="Horde/Mail/Smtpmx.php" />
+   <install name="lib/Horde/Mail/Transport.php" as="Horde/Mail/Transport.php" />
    <install name="lib/Horde/Mail.php" as="Horde/Mail.php" />
-   <install name="test/Horde/Mail/AllTests.php" as="test/Horde/Mail/AllTests.php" />
-   <install name="test/Horde/Mail/ParseTest.php" as="test/Horde/Mail/ParseTest.php" />
   </filelist>
  </phprelease>
 </package>
index 3cf296f..66ad8ea 100644 (file)
@@ -1471,17 +1471,13 @@ class Horde_Mime_Part
      * @param string $email                The address list to send to.
      * @param Horde_Mime_Headers $headers  The Horde_Mime_Headers object
      *                                     holding this message's headers.
-     * @param Horde_Mail_Driver $mailer    A Horde_Mail_Driver object.
+     * @param Horde_Mail_Transport $mailer A Horde_Mail_Transport object.
      *
      * @throws Horde_Mime_Exception
      * @throws InvalidArgumentException
      */
-    public function send($email, $headers, $mailer)
+    public function send($email, $headers, Horde_Mail_Transport $mailer)
     {
-        if (!($mailer instanceof Horde_Mail_Driver)) {
-            throw new InvalidArgumentException('Invalid Horde_Mail_Driver object passed to send().');
-        }
-
         $old_basepart = $this->_basepart;
         $this->_basepart = true;
 
index 92c8a83..265b38b 100644 (file)
@@ -41,7 +41,12 @@ class IMP_Injector_Binder_Mail implements Horde_Injector_Binder
             $params['password'] = $imap_ob->getParam('password');
         }
 
-        return Horde_Mail::factory($GLOBALS['conf']['mailer']['type'], $params);
+        $transport = $GLOBALS['conf']['mailer']['type'];
+        $class = 'Horde_Mail_Transport_' . ucfirst($transport);
+        if (class_exists($class)) {
+            return new $class($params);
+        }
+        throw new Horde_Exception('Unable to find class for transport ' . $transport);
     }
 
     /**
@@ -50,5 +55,4 @@ class IMP_Injector_Binder_Mail implements Horde_Injector_Binder
     {
         return false;
     }
-
 }