package.xml0000664000175000017500000006536013122751204011306 0ustar janjan Horde_Mail pear.horde.org Horde Mail Library Provides interfaces for sending e-mail messages and parsing e-mail addresses. Michael Slusarz slusarz slusarz@horde.org yes 2017-06-22 2.6.4 2.6.0 stable stable BSD-2-Clause * [jan] Add Turkish translation (İTÜ BİDB <sistemdestek@itu.edu.tr>). 5.3.0 8.0.0alpha1 8.0.0alpha1 1.7.0 Horde_Exception pear.horde.org 2.0.0 3.0.0alpha1 3.0.0alpha1 Horde_Idna pear.horde.org 1.0.0 2.0.0alpha1 2.0.0alpha1 Horde_Mime pear.horde.org 2.0.0 3.0.0alpha1 3.0.0alpha1 Horde_Stream_Filter pear.horde.org 2.0.0 3.0.0alpha1 3.0.0alpha1 Horde_Translation pear.horde.org 2.2.0 3.0.0alpha1 3.0.0alpha1 Horde_Util pear.horde.org 2.0.0 3.0.0alpha1 3.0.0alpha1 Horde_Smtp pear.horde.org 1.7.0 2.0.0alpha1 2.0.0alpha1 Horde_Stream_Wrapper pear.horde.org 2.1.0 3.0.0alpha1 3.0.0alpha1 Horde_Test pear.horde.org 2.1.0 3.0.0alpha1 3.0.0alpha1 Net_DNS2 pear.php.net Net_SMTP pear.php.net 1.6.0 1.0.0alpha1 1.0.0 alpha alpha 2011-03-08 BSD-2-Clause * First alpha release for Horde 4. 1.0.0beta1 1.0.0 beta beta 2011-03-16 BSD-2-Clause * First beta release for Horde 4. 1.0.0RC1 1.0.0 beta beta 2011-03-22 BSD-2-Clause * First release candidate for Horde 4. * [jan] Fix passing arguments to sendmail binary (Gonçalo Queirós, Bug #9693). 1.0.0RC2 1.0.0 beta beta 2011-03-29 BSD-2-Clause * Second release candidate for Horde 4. 1.0.0 1.0.0 stable stable 2011-04-06 BSD-2-Clause * First stable release for Horde 4. 1.0.1 1.0.0 stable stable 2011-09-20 BSD-2-Clause * [mms] Fix parseAddressList() for empty address strings (Bug #10534). * [mms] Fix SMTP error codes/messages (Bug #10498). 1.0.2 1.0.0 stable stable 2011-11-18 BSD-2-Clause * [mms] Always use canonical line endings in sendmail driver (Bug #10696). 1.0.3 1.0.0 stable stable 2012-01-17 BSD-2-Clause * [mms] Fix line-endings for transport drivers that send messages using local tools/programs. 1.1.0 1.1.0 stable stable 2012-02-22 BSD-2-Clause * [mms] Created Horde_Mail_Rfc822_Address and Horde_Mail_Rfc822_Group objects to represent e-mail addresses. * [mms] Improved parser for e-mail addresses (Request #10949). 1.2.0 1.2.0 stable stable 2012-04-10 BSD-2-Clause * [mms] Added Horde_Mail_Rfc822_Address#encoded property. * [mms] Better support for IDN hosts in non-validate address parsing mode (Bug #11021). * [mms] Added Horde_Mail_Rfc822#trimAddress(). * [mms] Add optional arguments to the Horde_Mail_Rfc822_Group constructor. * [mms] Horde_Mail_Rfc822#parseAddressList() now accepts Horde_Mail_Rfc822_Objects within the first argument. * [mms] The address and group objects now extend the base Horde_Mail_Rfc822_Object class. * [mms] Add optional arguments to the Horde_Mail_Rfc822_Group constructor. * [mms] First argument to Horde_Mail_Rfc822#parseAddressList() can now be an array of addresses. * [mms] Add Horde_Mail_Rfc822#encode(). * [mms] Workaround unexpected return from PHP_EOL in Mail transport drivers. 1.2.1 1.2.0 stable stable 2012-04-10 BSD-2-Clause * 2012-07-05 2.0.0alpha1 2.0.0alpha1 alpha alpha BSD-2-Clause * First alpha release for Horde 5. * [mms] Implement new 2.0 API. See UPGRADING for full details of changes. 2.0.0beta1 2.0.0beta1 beta beta 2012-07-19 BSD-2-Clause * First beta release for Horde 5. 2.0.0beta2 2.0.0beta1 beta beta 2012-08-29 BSD-2-Clause * [mms] Add Horde_Mail_Rfc822_Address#matchDomain(). * [mms] Add Horde_Mail_Rfc822_Address#matchInsensitive(). * [mms] Fix parsing Return-Path header when using sendmail driver (Bug #11361). 2.0.0 2.0.0 stable stable 2012-10-30 BSD-2-Clause * First stable release for Horde 5. 2.0.1 2.0.0 stable stable 2012-11-16 BSD-2-Clause * [mms] Ensure bare address is output to SMTP MAIL command. 2.0.2 2.0.0 stable stable 2012-12-03 BSD-2-Clause * [mms] Fix default_domain parameter to Horde_Mail_Rfc822 (Bug #11804). 2.0.3 2.0.0 stable stable 2012-12-26 BSD-2-Clause * [mms] Fix behavior of 'persist' option in SMTP transport driver. 2.0.4 2.0.0 stable stable 2013-03-05 BSD-2-Clause * [mms] Improve unit tests. 2.0.5 2.0.0 stable stable 2013-04-08 BSD-2-Clause * [mms] Correctly encode IDN domains when sending mail (Bug #12116). 2.0.6 2.0.0 stable stable 2013-07-16 BSD-2-Clause * [mms] Honor 'pipelining' configuration option in SMTP transport driver. 2.1.0 2.1.0 stable stable 2013-08-22 BSD-2-Clause * [mms] Added the Horde_Mail_Transport_Smtphorde driver. * [mms] Added the 'bare_addresses_idn' property to Horde_Mail_Rfc822_List. * [mms] Added the 'bare_address_idn' property to Horde_Mail_Rfc822_Address. 2.1.1 2.1.0 stable stable 2013-08-26 BSD-2-Clause * [mms] Workaround broken Net_SMTP handling regarding the end of message data (Bug #12614). 2.1.2 2.1.0 stable stable 2013-10-15 BSD-2-Clause * [mms] Discard personal information when it is identical to e-mail address. 2.1.3 2.1.0 stable stable 2014-01-17 BSD-2-Clause * [mms] Correctly identify e-mail addresses without domain information when validating. 2.1.4 2.1.0 stable stable 2014-01-21 BSD-2-Clause * [mms] More thorough job trying to parse addresses that contain an @ but no domain information. 2.1.5 2.1.0 stable stable 2014-02-11 BSD-2-Clause * 2.1.6 2.1.0 stable stable 2014-04-03 BSD-2-Clause * [mms] Optimizations to address parsing. 2.2.0 2.2.0 stable stable 2014-05-02 BSD-2-Clause * [mms] Be more lenient in parsing RFC 5322 identification field values. * [mms] Add Horde_Mail_Rfc822_Identification class. 2.3.0 2.3.0 stable stable 2014-05-21 BSD-2-Clause * [mms] Add Horde_Mail_Transport_Lmtphorde driver. 2.4.0 2.4.0 stable stable 2014-08-04 BSD-2-Clause * [mms] Added the 'noquote' option to Horde_Mail_Rfc822_Object#writeAddress(). 2.5.0 2.5.0 stable stable 2014-11-23 BSD-2-Clause * [mms] Added Horde_Mail_Rfc822_List#first() function. * [mms] Add property to address object to indicate whether it is an EAI address. * [mms] Transport driver now indicates whether it handles EAI data. * [mms] Support validation of EAI addresses (RFC 6532). * [mms] Add Horde_Mail_Mbox_Parse. 2.5.1 2.5.0 stable stable 2015-01-07 BSD-2-Clause * [mms] IDN support no longer requires intl to be built-in to PHP. 2.6.0 2.6.0 stable stable 2015-04-28 BSD-2-Clause * [jan] Fix issues with certain locales like Turkish. * [mms] Add support for outputting comment information when writing an address. 2.6.1 2.6.0 stable stable 2015-06-24 BSD-2-Clause * [mjr] Fix sending mail via PHP's mail function (Steffen Lindner <mail@steffen-lindner.de>). 2.6.2 2.6.0 stable stable 2015-07-31 BSD-2-Clause * [mms] Fix validating sent messages if the driver supports EAI addresses. 2.6.3 2.6.0 stable stable 2016-02-01 BSD-2-Clause * [jan] Mark PHP 7 as supported. 2.6.4 2.6.0 stable stable 2017-06-22 BSD-2-Clause * [jan] Add Turkish translation (İTÜ BİDB <sistemdestek@itu.edu.tr>). Horde_Mail-2.6.4/doc/Horde/Mail/COPYING0000664000175000017500000000243013122751204015351 0ustar janjan Copyright 1999-2017 Horde LLC. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 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. 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 HORDE PROJECT 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. Horde_Mail-2.6.4/doc/Horde/Mail/UPGRADING0000664000175000017500000001112513122751204015562 0ustar janjan====================== Upgrading Horde_Mail ====================== :Contact: dev@lists.horde.org .. contents:: Contents .. section-numbering:: This lists the API changes between releases of the package. Upgrading to 2.5 ================ - Horde_Mail_Rfc822 - encode() Added the 'comment' option to the 'type' parameter. - Horde_Mail_Rfc822_Object - Added the 'comment' option to the writeAddress() method. Upgrading to 2.5 ================ - Horde_Mail_Rfc822 - ATEXT This constant is deprecated. - parseAddressList() Added the 'eai' option to the 'validate' optional parameter. - Horde_Mail_Rfc822_Address Added the 'eai' property. - Horde_Mail_Rfc822_List - first() This method has been added. - Horde_Mail_Mbox_Parse Added object to parse mbox format mailbox data. - Horde_Mail_Transport Added 'eai' property. - Horde_Mail_Transport_Smtp - Horde_Mail_Transport_Smtpmx These Transport drivers are deprecated. Use Horde_Mail_Transport_Hordesmtp instead. Upgrading to 2.4 ================ - Horde_Mail_Rfc822_Object - writeAddress() Added the 'noquote' option. Upgrading to 2.3 ================ - Horde_Mail_Transport_Lmtphorde This Transport driver has been added. Upgrading to 2.2 ================ - Horde_Mail_Rfc822_Identification This class has been added. Upgrading to 2.1 ================ - Horde_Mail_Rfc822_Address Added the 'bare_address_idn' property. - Horde_Mail_Rfc822_List Added the 'bare_addresses_idn' property. - Horde_Mail_Transport_Smtphorde This Transport driver has been added. Upgrading to 2.0 ================ - Horde_Mail This class has been removed (no more Horde_Mail#factory()). Directly instantiate a transport driver instead. - Horde_Mail_Rfc822 The 'num_groups' property has been removed. The validateMailbox() method has been removed. parseAddressList() now returns a Horde_Mail_Rfc822_List object. The 'group' parameter to parseAddressList() has been added. The 'nest_groups' parameter to parseAddressList() has been removed. parseAddressList() does not validate by default. - Horde_Mail_Rfc822_Address The object can no longer be accessed as an array. Removed the 'adl', 'route', and 'personal_decoded' properties. The 'personal' property now always returns the MIME decoded personal part. The 'host' property now always returns the IDN decoded host. The 'encode' and 'idn' parameters to writeAddress() have changed behavior. Added the 'host_idn' and 'valid' properties. Renamed the 'full_address' property to 'bare_address'. - Horde_Mail_Rfc822_Group The object can no longer be accessed as an array. Removed the 'groupname_decoded' property. The 'groupname' property now always returns the MIME decoded groupname. The 'encode' and 'idn' parameters to writeAddress() have changed behavior. Added the 'valid' property. - Horde_Mail_Rfc822_Object Added a match() method. Passing boolean true to writeAddress() now defaults to full encoding of the address. Upgrading To 1.2 ================ Method API additions -------------------- - Horde_Mail_Rfc822#parseAddressList() The first argument can now be a Horde_Mail_Rfc822_Object or an array of address strings and/or Horde_Mail_Rfc822_Objects. - Horde_Mail_Rfc822_Address#__construct() The constructor now takes 1 optional argument: address. - Horde_Mail_Rfc822_Group#__construct() The constructor now takes 2 optional arguments: groupname and group addresses. New Methods ----------- - Horde_Mail_Rfc822#encode() - Horde_Mail_Rfc822#trimAddress() New Objects ----------- - Horde_Mail_Rfc822_Object Horde_Mail_Rfc822_Address and Horde_Mail_Rfc822_Group now extend this class. Allows for easier determination if an object contains RFC 822 element information. Upgrading To 1.1 ================ New Objects ----------- Horde_Mail_Rfc822::parseAddressList() now returns an array of Horde_Mail_Rfc822_Address objects (and Horde_Mail_Rfc822_Group objects, if nest_groups is true). These objects are backward compatible with the former array representation. They also include additional functionality. - Horde_Mail_Rfc822_Address Anything other than accessing these properties is a new feature available only since 1.1.0: - adl - comment - host - mailbox - personal - Horde_Mail_Rfc822_Group Anything other than accessing these properties is a new feature available only since 1.1.0: - addresses - groupname Horde_Mail-2.6.4/lib/Horde/Mail/Mbox/Parse.php0000664000175000017500000001372113122751204017014 0ustar janjan * @category Horde * @copyright 2011-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * @since 2.5.0 */ class Horde_Mail_Mbox_Parse implements ArrayAccess, Countable, Iterator { /** * Data stream. * * @var resource */ protected $_data; /** * Parsed data. Each entry is an array containing 3 keys: * - date: (mixed) Date information, in DateTime object. Null if date * cannot be parsed. False if message is not MBOX data. * - start: (integer) Start boundary. * * @var array */ protected $_parsed = array(); /** * Constructor. * * @param mixed $data The mbox data. Either a resource or a filename * as interpreted by fopen() (string). * @param integer $limit Limit to this many messages; additional messages * will throw an exception. * * @throws Horde_Mail_Parse_Exception */ public function __construct($data, $limit = null) { $this->_data = is_resource($data) ? $data : @fopen($data, 'r'); if ($this->_data === false) { throw new Horde_Mail_Exception( Horde_Mail_Translation::t("Could not parse mailbox data.") ); } rewind($this->_data); $i = 0; $last_line = null; /* Is this a MBOX format file? */ $mbox = false; while (!feof($this->_data)) { if (is_null($last_line)) { $start = ftell($this->_data); } $line = fgets($this->_data); if (is_null($last_line)) { ltrim($line); } if (substr($line, 0, 5) == 'From ') { if (is_null($last_line)) { /* This file is in MBOX format. */ $mbox = true; } elseif (!$mbox || (trim($last_line) !== '')) { continue; } if ($limit && ($i++ > $limit)) { throw new Horde_Mail_Exception( sprintf( Horde_Mail_Translation::t("Imported mailbox contains more than enforced limit of %u messages."), $limit ) ); } $from_line = explode(' ', $line, 3); try { $date = new DateTime($from_line[2]); } catch (Exception $e) { $date = null; } $this->_parsed[] = array( 'date' => $date, 'start' => ftell($this->_data) ); } /* Strip all empty lines before first data. */ if (!is_null($last_line) || (trim($line) !== '')) { $last_line = $line; } } /* This was a single message, not a MBOX file. */ if (empty($this->_parsed)) { $this->_parsed[] = array( 'date' => false, 'start' => $start ); } } /* ArrayAccess methods. */ /** */ public function offsetExists($offset) { return isset($this->_parsed[$offset]); } /** */ public function offsetGet($offset) { if (!isset($this->_parsed[$offset])) { return null; } $p = $this->_parsed[$offset]; $end = isset($this->_parsed[$offset + 1]) ? $this->_parsed[$offset + 1]['start'] : null; $fd = fopen('php://temp', 'w+'); fseek($this->_data, $p['start']); while (!feof($this->_data)) { $line = fgets($this->_data); if ($end && (ftell($this->_data) >= $end)) { break; } fwrite( $fd, (($p['date'] !== false) && substr($line, 0, 6) == '>From ') ? substr($line, 1) : $line ); } $out = array( 'data' => $fd, 'date' => ($p['date'] === false) ? null : $p['date'], 'size' => intval(ftell($fd)) ); rewind($fd); return $out; } /** */ public function offsetSet($offset, $value) { // NOOP } /** */ public function offsetUnset($offset) { // NOOP } /* Countable methods. */ /** * Index count. * * @return integer The number of messages. */ public function count() { return count($this->_parsed); } /* Magic methods. */ /** * String representation of the object. * * @return string String representation. */ public function __toString() { rewind($this->_data); return stream_get_contents($this->_data); } /* Iterator methods. */ public function current() { $key = $this->key(); return is_null($key) ? null : $this[$key]; } public function key() { return key($this->_parsed); } public function next() { if ($this->valid()) { next($this->_parsed); } } public function rewind() { reset($this->_parsed); } public function valid() { return !is_null($this->key()); } } Horde_Mail-2.6.4/lib/Horde/Mail/Rfc822/Address.php0000664000175000017500000001576613122751204017403 0ustar janjan * @category Horde * @copyright 2012-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * * @property-read string $bare_address The bare mailbox@host address. * @property-read string $bare_address_idn The bare mailbox@host address (IDN * encoded). (@since 2.1.0) * @property-read boolean $eai Returns true if the local (mailbox) address * part requires EAI (UTF-8) support. * (@since 2.5.0) * @property-read string $encoded The full MIME/IDN encoded address (UTF-8). * @property string $host Returns the host part (UTF-8). * @property-read string $host_idn Returns the IDN encoded host part. * @property-read string $label The shorthand label for this address. * @property string $personal The personal part (UTF-8). * @property-read string $personal_encoded The MIME encoded personal part * (UTF-8). * @property-read boolean $valid Returns true if there is enough information * in object to create a valid address. */ class Horde_Mail_Rfc822_Address extends Horde_Mail_Rfc822_Object { /** * Comments associated with the personal phrase. * * @var array */ public $comment = array(); /** * Local-part of the address (UTF-8). * * @var string */ public $mailbox = null; /** * Hostname of the address. * * @var string */ protected $_host = null; /** * Personal part of the address. * * @var string */ protected $_personal = null; /** * Constructor. * * @param string $address If set, address is parsed and used as the * object address. Address is not validated; * first e-mail address parsed is used. */ public function __construct($address = null) { if (!is_null($address)) { $rfc822 = new Horde_Mail_Rfc822(); $addr = $rfc822->parseAddressList($address); if (count($addr)) { foreach ($addr[0] as $key => $val) { $this->$key = $val; } } } } /** */ public function __set($name, $value) { switch ($name) { case 'host': try { $value = Horde_Idna::decode($value); } catch (Horde_Idna_Exception $e) {} $this->_host = Horde_String::lower($value); break; case 'personal': $this->_personal = strlen($value) ? Horde_Mime::decode($value) : null; break; } } /** * @throws Horde_Idna_Exception */ public function __get($name) { switch ($name) { case 'bare_address': return is_null($this->host) ? $this->mailbox : $this->mailbox . '@' . $this->host; case 'bare_address_idn': $personal = $this->_personal; $this->_personal = null; $res = $this->encoded; $this->_personal = $personal; return $res; case 'eai': return is_null($this->mailbox) ? false : Horde_Mime::is8bit($this->mailbox); case 'encoded': return $this->writeAddress(true); case 'host': return $this->_host; case 'host_idn': return Horde_Idna::encode($this->_host); case 'label': return is_null($this->personal) ? $this->bare_address : $this->_personal; case 'personal': return (strcasecmp($this->_personal, $this->bare_address) === 0) ? null : $this->_personal; case 'personal_encoded': return Horde_Mime::encode($this->personal); case 'valid': return (bool)strlen($this->mailbox); } } /** */ protected function _writeAddress($opts) { $rfc822 = new Horde_Mail_Rfc822(); $address = $rfc822->encode($this->mailbox, 'address'); $host = empty($opts['idn']) ? $this->host : $this->host_idn; if (strlen($host)) { $address .= '@' . $host; } $personal = $this->personal; if (strlen($personal)) { if (!empty($opts['encode'])) { $personal = Horde_Mime::encode($this->personal, $opts['encode']); } if (empty($opts['noquote'])) { $personal = $rfc822->encode($personal, 'personal'); } } if (!empty($opts['comment']) && !empty($this->comment)) { foreach ($this->comment as $val) { $personal .= ' (' . $rfc822->encode($val, 'comment') . ')'; } } return (strlen($personal) && ($personal != $address)) ? ltrim($personal) . ' <' . $address . '>' : $address; } /** */ public function match($ob) { if (!($ob instanceof Horde_Mail_Rfc822_Address)) { $ob = new Horde_Mail_Rfc822_Address($ob); } return ($this->bare_address == $ob->bare_address); } /** * Do a case-insensitive match on the address. Per RFC 822/2822/5322, * although the host portion of an address is case-insensitive, the * mailbox portion is platform dependent. * * @param mixed $ob Address data. * * @return boolean True if the data reflects the same case-insensitive * address. */ public function matchInsensitive($ob) { if (!($ob instanceof Horde_Mail_Rfc822_Address)) { $ob = new Horde_Mail_Rfc822_Address($ob); } return (Horde_String::lower($this->bare_address) == Horde_String::lower($ob->bare_address)); } /** * Do a case-insensitive match on the address for a given domain. * Matches as many parts of the subdomain in the address as is given in * the input. * * @param string $domain Domain to match. * * @return boolean True if the address matches the given domain. */ public function matchDomain($domain) { $host = $this->host; if (is_null($host)) { return false; } $match_domain = explode('.', $domain); $match_host = array_slice(explode('.', $host), count($match_domain) * -1); return (strcasecmp($domain, implode('.', $match_host)) === 0); } } Horde_Mail-2.6.4/lib/Horde/Mail/Rfc822/Group.php0000664000175000017500000000761413122751204017103 0ustar janjan * @category Horde * @copyright 2012-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * * @property string $groupname Groupname (UTF-8). * @property-read string $groupname_encoded MIME encoded groupname (UTF-8). * @property-read string $label The shorthand label for this group. * @property-read boolean $valid Returns true if there is enough information * in object to create a valid address. */ class Horde_Mail_Rfc822_Group extends Horde_Mail_Rfc822_Object implements Countable { /** * List of group e-mail address objects. * * @var Horde_Mail_Rfc822_GroupList */ public $addresses; /** * Group name (MIME decoded). * * @var string */ protected $_groupname = 'Group'; /** * Constructor. * * @param string $groupname If set, used as the group name. * @param mixed $addresses If a GroupList object, used as the address * list. Any other non-null value is parsed and * used as the address list (addresses not * verified; sub-groups are ignored). */ public function __construct($groupname = null, $addresses = null) { if (!is_null($groupname)) { $this->groupname = $groupname; } if (is_null($addresses)) { $this->addresses = new Horde_Mail_Rfc822_GroupList(); } elseif ($addresses instanceof Horde_Mail_Rfc822_GroupList) { $this->addresses = clone $addresses; } else { $rfc822 = new Horde_Mail_Rfc822(); $this->addresses = $rfc822->parseAddressList($addresses, array( 'group' => true )); } } /** */ public function __set($name, $value) { switch ($name) { case 'groupname': $this->_groupname = Horde_Mime::decode($value); break; } } /** */ public function __get($name) { switch ($name) { case 'groupname': case 'label': return $this->_groupname; case 'groupname_encoded': return Horde_Mime::encode($this->_groupname); case 'valid': return (bool)strlen($this->_groupname); } } /** */ protected function _writeAddress($opts) { $addr = $this->addresses->writeAddress($opts); $groupname = $this->groupname; if (!empty($opts['encode'])) { $groupname = Horde_Mime::encode($groupname, $opts['encode']); } if (empty($opts['noquote'])) { $rfc822 = new Horde_Mail_Rfc822(); $groupname = $rfc822->encode($groupname, 'personal'); } if (!empty($opts['comment']) && !empty($this->comment)) { $rfc822 = new Horde_Mail_Rfc822(); foreach ($this->comment as $val) { $personal .= ' (' . $rfc822->encode($val, 'comment') . ')'; } } return ltrim($groupname) . ':' . (strlen($addr) ? (' ' . $addr) : '') . ';'; } /** */ public function match($ob) { return $this->addresses->match($ob); } /* Countable methods. */ /** * Address count. * * @return integer The number of addresses. */ public function count() { return count($this->addresses); } } Horde_Mail-2.6.4/lib/Horde/Mail/Rfc822/GroupList.php0000664000175000017500000000251213122751204017727 0ustar janjan * @category Horde * @copyright 2012-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ class Horde_Mail_Rfc822_GroupList extends Horde_Mail_Rfc822_List { /** * Add objects to the container. * * @param mixed $obs A RFC 822 object (or list of objects) to store in * this object. */ public function add($obs) { if ($obs instanceof Horde_Mail_Rfc822_Object) { $obs = array($obs); } foreach ($obs as $val) { /* Only allow addresses. */ if ($val instanceof Horde_Mail_Rfc822_Address) { parent::add($val); } } } /** * Group count. * * @return integer The number of groups in the list. */ public function groupCount() { return 0; } } Horde_Mail-2.6.4/lib/Horde/Mail/Rfc822/Identification.php0000664000175000017500000000611013122751204020726 0ustar janjan * @category Horde * @copyright 2012-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * @since 2.2.0 */ class Horde_Mail_Rfc822_Identification extends Horde_Mail_Rfc822 { /** * List of message IDs parsed. * * @var array */ public $ids = array(); /** * Constructor. * * @param string $value Identification field value to parse. */ public function __construct($value = null) { $this->parse($value); } /** * Parse an identification header. * * @param string $value Identification field value to parse. */ public function parse($value) { if (!strlen($value)) { return; } $this->_data = $value; $this->_datalen = strlen($value); $this->_params['validate'] = true; $this->_ptr = 0; $this->_rfc822SkipLwsp(); while ($this->_curr() !== false) { try { $this->ids[] = $this->_parseMessageId(); } catch (Horde_Mail_Exception $e) { break; } // Some mailers incorrectly insert commas between reference items if ($this->_curr() == ',') { $this->_rfc822SkipLwsp(true); } } } /** * Message IDs are defined in RFC 5322 [3.6.4]. In short, they can only * contain one '@' character. However, Outlook can produce invalid * Message-IDs containing multiple '@' characters, which will fail the * strict RFC checks. * * Since we don't care about the structure/details of the Message-ID, * just do a basic parse that considers all characters inside of angled * brackets to be valid. * * @return string A full Message-ID (enclosed in angled brackets). * * @throws Horde_Mail_Exception */ private function _parseMessageId() { $bracket = ($this->_curr(true) === '<'); $str = '<'; while (($chr = $this->_curr(true)) !== false) { if ($bracket) { $str .= $chr; if ($chr == '>') { $this->_rfc822SkipLwsp(); return $str; } } else { if (!strcspn($chr, " \n\r\t,")) { $this->_rfc822SkipLwsp(); return $str; } $str .= $chr; } } if (!$bracket) { return $str; } throw new Horde_Mail_Exception('Invalid Message-ID.'); } } Horde_Mail-2.6.4/lib/Horde/Mail/Rfc822/List.php0000664000175000017500000003121413122751204016713 0ustar janjan * @category Horde * @copyright 2012-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * * @property-read array $addresses The list of all addresses (address * w/personal parts). * @property-read array $bare_addresses The list of all addresses (mail@host). * @property-read array $bare_addresses_idn The list of all addresses * (mail@host; IDN encoded). * (@since 2.1.0) * @property-read array $base_addresses The list of ONLY base addresses * (Address objects). * @property-read array $raw_addresses The list of all addresses (Address * objects). */ class Horde_Mail_Rfc822_List extends Horde_Mail_Rfc822_Object implements ArrayAccess, Countable, SeekableIterator, Serializable { /** Filter masks. */ const HIDE_GROUPS = 1; const BASE_ELEMENTS = 2; /** * List data. * * @var array */ protected $_data = array(); /** * Current Iterator filter. * * @var array */ protected $_filter = array(); /** * Current Iterator pointer. * * @var array */ protected $_ptr; /** * Constructor. * * @param mixed $obs Address data to store in this object. */ public function __construct($obs = null) { if (!is_null($obs)) { $this->add($obs); } } /** */ public function __get($name) { switch ($name) { case 'addresses': case 'bare_addresses': case 'bare_addresses_idn': case 'base_addresses': case 'raw_addresses': $old = $this->_filter; $mask = ($name == 'base_addresses') ? self::BASE_ELEMENTS : self::HIDE_GROUPS; $this->setIteratorFilter($mask, empty($old['filter']) ? null : $old['filter']); $out = array(); foreach ($this as $val) { switch ($name) { case 'addresses': $out[] = strval($val); break; case 'bare_addresses': $out[] = $val->bare_address; break; case 'bare_addresses_idn': $out[] = $val->bare_address_idn; break; case 'base_addresses': case 'raw_addresses': $out[] = clone $val; break; } } $this->_filter = $old; return $out; } } /** * Add objects to the container. * * @param mixed $obs Address data to store in this object. */ public function add($obs) { foreach ($this->_normalize($obs) as $val) { $this->_data[] = $val; } } /** * Remove addresses from the container. This method ignores Group objects. * * @param mixed $obs Addresses to remove. */ public function remove($obs) { $old = $this->_filter; $this->setIteratorFilter(self::HIDE_GROUPS | self::BASE_ELEMENTS); foreach ($this->_normalize($obs) as $val) { $remove = array(); foreach ($this as $key => $val2) { if ($val2->match($val)) { $remove[] = $key; } } foreach (array_reverse($remove) as $key) { unset($this[$key]); } } $this->_filter = $old; } /** * Removes duplicate addresses from list. This method ignores Group * objects. */ public function unique() { $exist = $remove = array(); $old = $this->_filter; $this->setIteratorFilter(self::HIDE_GROUPS | self::BASE_ELEMENTS); // For duplicates, we use the first address that contains personal // information. foreach ($this as $key => $val) { $bare = $val->bare_address; if (isset($exist[$bare])) { if (($exist[$bare] == -1) || is_null($val->personal)) { $remove[] = $key; } else { $remove[] = $exist[$bare]; $exist[$bare] = -1; } } else { $exist[$bare] = is_null($val->personal) ? $key : -1; } } foreach (array_reverse($remove) as $key) { unset($this[$key]); } $this->_filter = $old; } /** * Group count. * * @return integer The number of groups in the list. */ public function groupCount() { $ret = 0; foreach ($this->_data as $val) { if ($val instanceof Horde_Mail_Rfc822_Group) { ++$ret; } } return $ret; } /** * Set the Iterator filter. * * @param integer $mask Filter masks. * @param mixed $filter An e-mail, or as list of e-mails, to filter by. */ public function setIteratorFilter($mask = 0, $filter = null) { $this->_filter = array(); if ($mask) { $this->_filter['mask'] = $mask; } if (!is_null($filter)) { $rfc822 = new Horde_Mail_Rfc822(); $this->_filter['filter'] = $rfc822->parseAddressList($filter); } } /** */ protected function _writeAddress($opts) { $out = array(); foreach ($this->_data as $val) { $out[] = $val->writeAddress($opts); } return implode(', ', $out); } /** */ public function match($ob) { if (!($ob instanceof Horde_Mail_Rfc822_List)) { $ob = new Horde_Mail_Rfc822_List($ob); } $a = $this->bare_addresses; sort($a); $b = $ob->bare_addresses; sort($b); return ($a == $b); } /** * Does this list contain the given e-mail address? * * @param mixed $address An e-mail address. * * @return boolean True if the e-mail address is contained in the list. */ public function contains($address) { $ob = new Horde_Mail_Rfc822_Address($address); foreach ($this->raw_addresses as $val) { if ($val->match($ob)) { return true; } } return false; } /** * Convenience method to return the first element in a list. * * Useful since it allows chaining; older PHP versions did not allow array * access dereferencing from the results of a function call. * * @since 2.5.0 * * @return Horde_Mail_Rfc822_Object Rfc822 object, or null if no object. */ public function first() { return $this[0]; } /** * Normalize objects to add to list. * * @param mixed $obs Address data to store in this object. * * @return array Entries to add. */ protected function _normalize($obs) { $add = array(); if (!($obs instanceof Horde_Mail_Rfc822_List) && !is_array($obs)) { $obs = array($obs); } foreach ($obs as $val) { if (is_string($val)) { $rfc822 = new Horde_Mail_Rfc822(); $val = $rfc822->parseAddressList($val); } if ($val instanceof Horde_Mail_Rfc822_List) { $val->setIteratorFilter(self::BASE_ELEMENTS); foreach ($val as $val2) { $add[] = $val2; } } elseif ($val instanceof Horde_Mail_Rfc822_Object) { $add[] = $val; } } return $add; } /* ArrayAccess methods. */ /** */ public function offsetExists($offset) { return !is_null($this[$offset]); } /** */ public function offsetGet($offset) { try { $this->seek($offset); return $this->current(); } catch (OutOfBoundsException $e) { return null; } } /** */ public function offsetSet($offset, $value) { if ($ob = $this[$offset]) { if (is_null($this->_ptr['subidx'])) { $tmp = $this->_normalize($value); if (isset($tmp[0])) { $this->_data[$this->_ptr['idx']] = $tmp[0]; } } else { $ob[$offset] = $value; } $this->_ptr = null; } } /** */ public function offsetUnset($offset) { if ($ob = $this[$offset]) { if (is_null($this->_ptr['subidx'])) { unset($this->_data[$this->_ptr['idx']]); $this->_data = array_values($this->_data); } else { unset($ob->addresses[$this->_ptr['subidx']]); } $this->_ptr = null; } } /* Countable methods. */ /** * Address count. * * @return integer The number of addresses. */ public function count() { return count($this->addresses); } /* Iterator methods. */ public function current() { if (!$this->valid()) { return null; } $ob = $this->_data[$this->_ptr['idx']]; return is_null($this->_ptr['subidx']) ? $ob : $ob->addresses[$this->_ptr['subidx']]; } public function key() { return $this->_ptr['key']; } public function next() { if (is_null($this->_ptr['subidx'])) { $curr = $this->current(); if (($curr instanceof Horde_Mail_Rfc822_Group) && count($curr)) { $this->_ptr['subidx'] = 0; } else { ++$this->_ptr['idx']; } $curr = $this->current(); } elseif (!($curr = $this->_data[$this->_ptr['idx']]->addresses[++$this->_ptr['subidx']])) { $this->_ptr['subidx'] = null; ++$this->_ptr['idx']; $curr = $this->current(); } if (!is_null($curr)) { if (!empty($this->_filter) && $this->_iteratorFilter($curr)) { $this->next(); } else { ++$this->_ptr['key']; } } } public function rewind() { $this->_ptr = array( 'idx' => 0, 'key' => 0, 'subidx' => null ); if ($this->valid() && !empty($this->_filter) && $this->_iteratorFilter($this->current())) { $this->next(); $this->_ptr['key'] = 0; } } public function valid() { return (!empty($this->_ptr) && isset($this->_data[$this->_ptr['idx']])); } public function seek($position) { if (!$this->valid() || ($position < $this->_ptr['key'])) { $this->rewind(); } for ($i = $this->_ptr['key']; ; ++$i) { if ($i == $position) { return; } $this->next(); if (!$this->valid()) { throw new OutOfBoundsException('Position not found.'); } } } protected function _iteratorFilter($ob) { if (!empty($this->_filter['mask'])) { if (($this->_filter['mask'] & self::HIDE_GROUPS) && ($ob instanceof Horde_Mail_Rfc822_Group)) { return true; } if (($this->_filter['mask'] & self::BASE_ELEMENTS) && !is_null($this->_ptr['subidx'])) { return true; } } if (!empty($this->_filter['filter']) && ($ob instanceof Horde_Mail_Rfc822_Address)) { foreach ($this->_filter['filter'] as $val) { if ($ob->match($val)) { return true; } } } return false; } /* Serializable methods. */ public function serialize() { return serialize($this->_data); } public function unserialize($data) { $this->_data = unserialize($data); } } Horde_Mail-2.6.4/lib/Horde/Mail/Rfc822/Object.php0000664000175000017500000000516413122751204017213 0ustar janjan * @category Horde * @copyright 2012-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ abstract class Horde_Mail_Rfc822_Object { /** * String representation of object. * * @return string Returns the full e-mail address. */ public function __toString() { return $this->writeAddress(); } /** * Write an address given information in this part. * * @param mixed $opts If boolean true, is equivalent to passing true for * both 'encode' and 'idn'. If an array, these * keys are supported: * - comment: (boolean) If true, include comment(s) in output? * @since 2.6.0 * DEFAULT: false * - encode: (mixed) MIME encode the personal/groupname parts? * If boolean true, encodes in 'UTF-8'. * If a string, encodes using this charset. * DEFAULT: false * - idn: (boolean) If true, encodes IDN domain names (RFC 3490). * DEFAULT: false * - noquote: (boolean) If true, don't quote personal part. [@since * 2.4.0] * DEFAULT: false * * @return string The correctly escaped/quoted address. */ public function writeAddress($opts = array()) { if ($opts === true) { $opts = array( 'encode' => 'UTF-8', 'idn' => true ); } elseif (!empty($opts['encode']) && ($opts['encode'] === true)) { $opts['encode'] = 'UTF-8'; } return $this->_writeAddress($opts); } /** * Class-specific implementation of writeAddress(). * * @see writeAddress() * * @param array $opts See writeAddress(). * * @return string The correctly escaped/quoted address. */ abstract protected function _writeAddress($opts); /** * Compare this object against other data. * * @param mixed $ob Address data. * * @return boolean True if the data reflects the same canonical address. */ abstract public function match($ob); } Horde_Mail-2.6.4/lib/Horde/Mail/Transport/Lmtphorde.php0000664000175000017500000000453313122751204020770 0ustar janjan * @category Horde * @copyright 2014-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ class Horde_Mail_Transport_Lmtphorde extends Horde_Mail_Transport_Smtphorde { /** */ public function getSMTPObject() { if (!$this->_smtp) { $this->_smtp = new Horde_Smtp_Lmtp($this->_params); try { $this->_smtp->login(); } catch (Horde_Smtp_Exception $e) { throw new Horde_Mail_Exception($e); } } return $this->_smtp; } } Horde_Mail-2.6.4/lib/Horde/Mail/Transport/Mail.php0000664000175000017500000001072113122751204017710 0ustar janjan * @author Michael Slusarz * @category Horde * @copyright 2010-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ class Horde_Mail_Transport_Mail extends Horde_Mail_Transport { /** * @param array $params Additional parameters: * - args: (string) Extra arguments for the mail() function. */ public function __construct(array $params = array()) { $this->_params = array_merge($this->_params, $params); } /** */ public function send($recipients, array $headers, $body) { $headers = $this->_sanitizeHeaders($headers); $recipients = implode(',', $this->parseRecipients($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 = ''; stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); stream_filter_append($body, 'horde_eol', STREAM_FILTER_READ, array('eol' => $this->sep)); rewind($body); while (!feof($body)) { $body_str .= fread($body, 8192); } $body = $body_str; } else { // Convert EOL characters in body. $body = $this->_normalizeEOL($body); } // 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.'); } } } Horde_Mail-2.6.4/lib/Horde/Mail/Transport/Mock.php0000664000175000017500000001035613122751204017723 0ustar janjan * @author Michael Slusarz * @category Horde * @copyright 2010-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @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; /** * @param array Optional parameters: * - postSendCallback: (callback) Called after an email would have been * sent. * - preSendCallback: (callback) Called before an email would be sent. */ 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']; } } /** */ 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($from, $text_headers) = $this->prepareHeaders($headers); if (is_resource($body)) { stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); stream_filter_append($body, 'horde_eol', STREAM_FILTER_READ, array('eol' => $this->sep)); rewind($body); $body_txt = stream_get_contents($body); } else { $body_txt = $this->_normalizeEOL($body); } $from = $this->_getFrom($from, $headers); $recipients = $this->parseRecipients($recipients); $this->sentMessages[] = array( 'body' => $body_txt, 'from' => $from, 'headers' => $headers, 'header_text' => $text_headers, 'recipients' => $recipients ); if ($this->_postSendCallback) { call_user_func_array($this->_postSendCallback, array($this, $recipients, $headers, $body_txt)); } } } Horde_Mail-2.6.4/lib/Horde/Mail/Transport/Null.php0000664000175000017500000000431313122751204017740 0ustar janjan * @author Michael Slusarz * @category Horde * @copyright 2010-2017 Horde LLC * @copyright 2010 Phil Kernick * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ class Horde_Mail_Transport_Null extends Horde_Mail_Transport { /** */ public function send($recipients, array $headers, $body) { } } Horde_Mail-2.6.4/lib/Horde/Mail/Transport/Sendmail.php0000664000175000017500000001414013122751204020561 0ustar janjan * @author Michael Slusarz * @category Horde * @copyright 2010-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @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: * - 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 */ 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']; } } /** */ 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); $from = $this->_getFrom($from, $headers); $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)) { stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); stream_filter_append($body, 'horde_eol', STREAM_FILTER_READ, array('eol' => $this->sep)); rewind($body); while (!feof($body)) { fputs($mail, fread($body, 8192)); } } else { fputs($mail, $this->_normalizeEOL($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 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); } } Horde_Mail-2.6.4/lib/Horde/Mail/Transport/Smtp.php0000664000175000017500000002726413122751204017763 0ustar janjan * @author Jon Parise * @author Michael Slusarz * @category Horde * @copyright 2010-2016 Horde LLC * @deprecated Use Horde_Mail_Transport_Hordesmtp instead * @license http://www.horde.org/licenses/bsd New BSD License * @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: * - 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 */ 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')); /* SMTP requires CRLF line endings. */ $this->sep = "\r\n"; } /** */ public function send($recipients, array $headers, $body) { /* If we don't already have an SMTP object, create one. */ $this->getSMTPObject(); $headers = $this->_sanitizeHeaders($headers); /* Make sure the message has a trailing newline. */ if (is_resource($body)) { fseek($body, -1, SEEK_END); switch (fgetc($body)) { case "\r": if (fgetc($body) != "\n") { fputs($body, "\n"); } break; default: fputs($body, "\r\n"); break; } rewind($body); } elseif (substr($body, -2, 0) != "\r\n") { $body .= "\r\n"; } try { list($from, $textHeaders) = $this->prepareHeaders($headers); } catch (Horde_Mail_Exception $e) { $this->_smtp->rset(); throw $e; } try { $from = $this->_getFrom($from, $headers); } catch (Horde_Mail_Exception $e) { $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->_error(sprintf("Failed to set sender: %s", $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->_error("Failed to add recipient: $recipient", $res, self::ERROR_RECIPIENT); } } /* Send the message's headers and the body as SMTP data. Net_SMTP does * the necessary EOL conversions. */ $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->_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'] ); /* Set pipelining. */ if ($this->_params['pipelining']) { $this->_smtp->pipelining = true; } /* 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->_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(); /* Abort current SMTP transaction. */ $this->_smtp->rset(); /* Build our standardized error string. */ throw new Horde_Mail_Exception($text . ' [SMTP: ' . $error->getMessage() . " (code: $code, response: $response)]", $e_code); } } Horde_Mail-2.6.4/lib/Horde/Mail/Transport/Smtphorde.php0000664000175000017500000001357413122751204021004 0ustar janjan * @category Horde * @copyright 2013-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ class Horde_Mail_Transport_Smtphorde extends Horde_Mail_Transport { /** * @deprecated */ public $send8bit = false; /** * SMTP object. * * @var Horde_Smtp */ protected $_smtp = null; /** * Constructor. * * @param array $params Additional parameters: * - chunk_size: (integer) If CHUNKING is supported on the server, the * chunk size (in octets) to send. 0 will disable chunking. * @since Horde_Smtp 1.7.0 * - context: (array) Any context parameters passed to * stream_create_context(). @since Horde_Smtp 1.9.0 * - debug: (string) If set, will output debug information to the stream * provided. The value can be any PHP supported wrapper that * can be opened via fopen(). * DEFAULT: No debug output * - host: (string) The SMTP server. * DEFAULT: localhost * - localhost: (string) The hostname of the localhost. (since Horde_Smtp 1.9.0) * DEFAULT: Auto-determined. * - password: (string) The SMTP password. * DEFAULT: NONE * - port: (string) The SMTP port. * DEFAULT: 587 * - secure: (string) Use SSL or TLS to connect. * DEFAULT: true (use 'tls' option, if available) * - false (No encryption) * - 'ssl' (Auto-detect SSL version) * - 'sslv2' (Force SSL version 2) * - 'sslv3' (Force SSL version 3) * - 'tls' (TLS; started via protocol-level negotation over * unencrypted channel; RECOMMENDED way of initiating secure * connection) * - 'tlsv1' (TLS direct version 1.x connection to server) [@since * Horde_Smtp .3.0] * - true (Use TLS, if available) [@since Horde_Smtp 1.2.0] * DEFAULT: No encryption * - timeout: (integer) Connection timeout, in seconds. * DEFAULT: 30 seconds * - username: (string) The SMTP username. * DEFAULT: NONE * - xoauth2_token: (string) If set, will authenticate via the XOAUTH2 * mechanism (if available) with this token. Either a * string or a Horde_Smtp_Password object (since * Horde_Smtp 1.1.0). */ public function __construct(array $params = array()) { $this->_params = $params; /* SMTP requires CRLF line endings. */ $this->sep = "\r\n"; } /** */ public function __get($name) { switch ($name) { case 'eai': $this->getSMTPObject(); return $this->_smtp->data_intl; } return parent::__get($name); } /** */ public function send($recipients, array $headers, $body) { /* If we don't already have an SMTP object, create one. */ $this->getSMTPObject(); $headers = $this->_sanitizeHeaders($headers); list($from, $textHeaders) = $this->prepareHeaders($headers); $from = $this->_getFrom($from, $headers); $combine = Horde_Stream_Wrapper_Combine::getStream(array( rtrim($textHeaders, $this->sep), $this->sep . $this->sep, $body )); try { $this->_smtp->send($from, $recipients, $combine); } catch (Horde_Smtp_Exception $e) { throw new Horde_Mail_Exception($e); } } /** * Connect to the SMTP server by instantiating a Horde_Smtp object. * * @return Horde_Smtp The SMTP object. * @throws Horde_Mail_Exception */ public function getSMTPObject() { if (!$this->_smtp) { $this->_smtp = new Horde_Smtp($this->_params); try { $this->_smtp->login(); } catch (Horde_Smtp_Exception $e) { throw new Horde_Mail_Exception($e); } } return $this->_smtp; } } Horde_Mail-2.6.4/lib/Horde/Mail/Transport/Smtpmx.php0000664000175000017500000002635413122751204020327 0ustar janjan * @author Michael Slusarz * @category Horde * @copyright 2010-2016 Horde LLC * @copyright 2010 Gerd Schaufelberger * @deprecated Use Horde_Mail_Transport_Hordesmtp instead * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ class Horde_Mail_Transport_Smtpmx extends Horde_Mail_Transport { /** * SMTP connection object. * * @var Net_SMTP */ protected $_smtp = null; /** * Net_DNS2_Resolver object. * * @var Net_DNS2_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_DNS2 or switch off "netdns"' ), 'failed_rset' => array( 'code' => 10, 'msg' => 'RSET command failed, SMTP-connection corrupt.' ) ); /** * @param array $params Additional options: * - debug: (boolean) Activate SMTP 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_DNS2 (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 */ 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); /* SMTP requires CRLF line endings. */ $this->sep = "\r\n"; } /** * 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; } } /** */ public function send($recipients, array $headers, $body) { $headers = $this->_sanitizeHeaders($headers); // Prepare headers list($from, $textHeaders) = $this->prepareHeaders($headers); try { $from = $this->_getFrom($from, $headers); } catch (Horde_Mail_Exception $e) { $this->_error('no_from'); } // Prepare recipients foreach ($this->parseRecipients($recipients) as $rcpt) { list(,$host) = explode('@', $rcpt); $mx = $this->_getMx($host); if (!$mx) { $this->_error('no_mx', array('rcpt' => $rcpt)); } $connected = false; foreach (array_keys($mx) as $mserver) { $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. Net_SMTP does necessary EOL conversions. $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(); try { $response = $this->_resolver->query($host, 'MX'); if (!$response) { return false; } } catch (Exception $e) { throw new Horde_Mail_Exception($e); } 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_DNS2_Resolver. */ protected function _loadNetDns() { if (!$this->_resolver) { if (!class_exists('Net_DNS2_Resolver')) { $this->_error('no_resolver'); } $this->_resolver = new Net_DNS2_Resolver(); } } /** * 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[] = '{' . Horde_String::upper($key) . '}'; $replace[] = $value; } $msg = str_replace($search, $replace, $msg); } throw new Horde_Mail_Exception($msg, $this->_errorCode[$id]['code']); } } Horde_Mail-2.6.4/lib/Horde/Mail/Exception.php0000664000175000017500000000122713122751204016771 0ustar janjan * @category Horde * @copyright 2010-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ class Horde_Mail_Exception extends Horde_Exception_Wrapped { } Horde_Mail-2.6.4/lib/Horde/Mail/Rfc822.php0000664000175000017500000006065113122751204016007 0ustar janjan * * @category Horde * @copyright 2001-2010 Richard Heyes * @copyright 2002-2011 Timo Sirainen * @copyright 2011-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ /** * RFC 822/2822/3490/5322 Email parser/validator. * * @author Richard Heyes * @author Chuck Hagenbuch * @author Michael Slusarz * @author Timo Sirainen * @category Horde * @copyright 2001-2010 Richard Heyes * @copyright 2002-2011 Timo Sirainen * @copyright 2011-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ class Horde_Mail_Rfc822 { /** * Valid atext characters. * * @deprecated * @since 2.0.3 */ const ATEXT = '!#$%&\'*+-./0123456789=?ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~'; /** * Excluded (in ASCII decimal): 0-8, 10-31, 34, 40-41, 44, 58-60, 62, 64, * 91-93, 127 * * @since 2.0.3 */ const ENCODE_FILTER = "\0\1\2\3\4\5\6\7\10\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\"(),:;<>@[\\]\177"; /** * The address string to parse. * * @var string */ protected $_data; /** * Length of the address string. * * @var integer */ protected $_datalen; /** * Comment cache. * * @var string */ protected $_comments = array(); /** * List object to return in parseAddressList(). * * @var Horde_Mail_Rfc822_List */ protected $_listob; /** * Configuration parameters. * * @var array */ protected $_params = array(); /** * Data pointer. * * @var integer */ protected $_ptr; /** * Starts the whole process. * * @param mixed $address The address(es) to validate. Either a string, * a Horde_Mail_Rfc822_Object, or an array of * strings and/or Horde_Mail_Rfc822_Objects. * @param array $params Optional parameters: * - default_domain: (string) Default domain/host. * DEFAULT: None * - group: (boolean) Return a GroupList object instead of a List object? * DEFAULT: false * - limit: (integer) Stop processing after this many addresses. * DEFAULT: No limit (0) * - validate: (mixed) Strict validation of personal part data? If * false, attempts to allow non-ASCII characters and * non-quoted strings in the personal data, and will * silently abort if an unparseable address is found. * If true, does strict RFC 5322 (ASCII-only) parsing. If * 'eai' (@since 2.5.0), allows RFC 6532 (EAI/UTF-8) * addresses. * DEFAULT: false * * @return Horde_Mail_Rfc822_List A list object. * * @throws Horde_Mail_Exception */ public function parseAddressList($address, array $params = array()) { if ($address instanceof Horde_Mail_Rfc822_List) { return $address; } if (empty($params['limit'])) { $params['limit'] = -1; } $this->_params = array_merge(array( 'default_domain' => null, 'validate' => false ), $params); $this->_listob = empty($this->_params['group']) ? new Horde_Mail_Rfc822_List() : new Horde_Mail_Rfc822_GroupList(); if (!is_array($address)) { $address = array($address); } $tmp = array(); foreach ($address as $val) { if ($val instanceof Horde_Mail_Rfc822_Object) { $this->_listob->add($val); } else { $tmp[] = rtrim(trim($val), ','); } } if (!empty($tmp)) { $this->_data = implode(',', $tmp); $this->_datalen = strlen($this->_data); $this->_ptr = 0; $this->_parseAddressList(); } $ret = $this->_listob; unset($this->_listob); return $ret; } /** * Quotes and escapes the given string if necessary using rules contained * in RFC 2822 [3.2.5]. * * @param string $str The string to be quoted and escaped. * @param string $type Either 'address', 'comment' (@since 2.6.0), or * 'personal'. * * @return string The correctly quoted and escaped string. */ public function encode($str, $type = 'address') { switch ($type) { case 'comment': // RFC 5322 [3.2.2]: Filter out non-printable US-ASCII and ( ) \ $filter = "\0\1\2\3\4\5\6\7\10\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\50\51\134\177"; break; case 'personal': // RFC 2822 [3.4]: Period not allowed in display name $filter = self::ENCODE_FILTER . '.'; break; case 'address': default: // RFC 2822 [3.4.1]: (HTAB, SPACE) not allowed in address $filter = self::ENCODE_FILTER . "\11\40"; break; } // Strip double quotes if they are around the string already. // If quoted, we know that the contents are already escaped, so // unescape now. $str = trim($str); if ($str && ($str[0] === '"') && (substr($str, -1) === '"')) { $str = stripslashes(substr($str, 1, -1)); } return (strcspn($str, $filter) != strlen($str)) ? '"' . addcslashes($str, '\\"') . '"' : $str; } /** * If an email address has no personal information, get rid of any angle * brackets (<>) around it. * * @param string $address The address to trim. * * @return string The trimmed address. */ public function trimAddress($address) { $address = trim($address); return (($address[0] == '<') && (substr($address, -1) == '>')) ? substr($address, 1, -1) : $address; } /* RFC 822 parsing methods. */ /** * address-list = (address *("," address)) / obs-addr-list */ protected function _parseAddressList() { $limit = $this->_params['limit']; while (($this->_curr() !== false) && ($limit-- !== 0)) { try { $this->_parseAddress(); } catch (Horde_Mail_Exception $e) { if ($this->_params['validate']) { throw $e; } ++$this->_ptr; } switch ($this->_curr()) { case ',': $this->_rfc822SkipLwsp(true); break; case false: // No-op break; default: if ($this->_params['validate']) { throw new Horde_Mail_Exception('Error when parsing address list.'); } break; } } } /** * address = mailbox / group */ protected function _parseAddress() { $start = $this->_ptr; if (!$this->_parseGroup()) { $this->_ptr = $start; if ($mbox = $this->_parseMailbox()) { $this->_listob->add($mbox); } } } /** * group = display-name ":" [mailbox-list / CFWS] ";" [CFWS] * display-name = phrase * * @return boolean True if a group was parsed. * * @throws Horde_Mail_Exception */ protected function _parseGroup() { $this->_rfc822ParsePhrase($groupname); if ($this->_curr(true) != ':') { return false; } $addresses = new Horde_Mail_Rfc822_GroupList(); $this->_rfc822SkipLwsp(); while (($chr = $this->_curr()) !== false) { if ($chr == ';') { ++$this->_ptr; if (count($addresses)) { $this->_listob->add(new Horde_Mail_Rfc822_Group($groupname, $addresses)); } return true; } /* mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list */ $addresses->add($this->_parseMailbox()); switch ($this->_curr()) { case ',': $this->_rfc822SkipLwsp(true); break; case ';': // No-op break; default: break 2; } } throw new Horde_Mail_Exception('Error when parsing group.'); } /** * mailbox = name-addr / addr-spec * * @return mixed Mailbox object if mailbox was parsed, or false. */ protected function _parseMailbox() { $this->_comments = array(); $start = $this->_ptr; if (!($ob = $this->_parseNameAddr())) { $this->_comments = array(); $this->_ptr = $start; $ob = $this->_parseAddrSpec(); } if ($ob) { $ob->comment = $this->_comments; } return $ob; } /** * name-addr = [display-name] angle-addr * display-name = phrase * * @return mixed Mailbox object, or false. */ protected function _parseNameAddr() { $this->_rfc822ParsePhrase($personal); if ($ob = $this->_parseAngleAddr()) { $ob->personal = $personal; return $ob; } return false; } /** * addr-spec = local-part "@" domain * * @return mixed Mailbox object. * * @throws Horde_Mail_Exception */ protected function _parseAddrSpec() { $ob = new Horde_Mail_Rfc822_Address(); $ob->mailbox = $this->_parseLocalPart(); if ($this->_curr() == '@') { try { $this->_rfc822ParseDomain($host); if (strlen($host)) { $ob->host = $host; } } catch (Horde_Mail_Exception $e) { if (!empty($this->_params['validate'])) { throw $e; } } } if (is_null($ob->host)) { if (!is_null($this->_params['default_domain'])) { $ob->host = $this->_params['default_domain']; } elseif (!empty($this->_params['validate'])) { throw new Horde_Mail_Exception('Address is missing domain.'); } } return $ob; } /** * local-part = dot-atom / quoted-string / obs-local-part * obs-local-part = word *("." word) * * @return string The local part. * * @throws Horde_Mail_Exception */ protected function _parseLocalPart() { if (($curr = $this->_curr()) === false) { throw new Horde_Mail_Exception('Error when parsing local part.'); } if ($curr == '"') { $this->_rfc822ParseQuotedString($str); } else { $this->_rfc822ParseDotAtom($str, ',;@'); } return $str; } /** * "<" [ "@" route ":" ] local-part "@" domain ">" * * @return mixed Mailbox object, or false. * * @throws Horde_Mail_Exception */ protected function _parseAngleAddr() { if ($this->_curr() != '<') { return false; } $this->_rfc822SkipLwsp(true); if ($this->_curr() == '@') { // Route information is ignored. $this->_parseDomainList(); if ($this->_curr() != ':') { throw new Horde_Mail_Exception('Invalid route.'); } $this->_rfc822SkipLwsp(true); } $ob = $this->_parseAddrSpec(); if ($this->_curr() != '>') { throw new Horde_Mail_Exception('Error when parsing angle address.'); } $this->_rfc822SkipLwsp(true); return $ob; } /** * obs-domain-list = "@" domain *(*(CFWS / "," ) [CFWS] "@" domain) * * @return array Routes. * * @throws Horde_Mail_Exception */ protected function _parseDomainList() { $route = array(); while ($this->_curr() !== false) { $this->_rfc822ParseDomain($str); $route[] = '@' . $str; $this->_rfc822SkipLwsp(); if ($this->_curr() != ',') { return $route; } ++$this->_ptr; } throw new Horde_Mail_Exception('Invalid domain list.'); } /* RFC 822 parsing methods. */ /** * phrase = 1*word / obs-phrase * word = atom / quoted-string * obs-phrase = word *(word / "." / CFWS) * * @param string &$phrase The phrase data. * * @throws Horde_Mail_Exception */ protected function _rfc822ParsePhrase(&$phrase) { $curr = $this->_curr(); if (($curr === false) || ($curr == '.')) { throw new Horde_Mail_Exception('Error when parsing a group.'); } do { if ($curr == '"') { $this->_rfc822ParseQuotedString($phrase); } else { $this->_rfc822ParseAtomOrDot($phrase); } $curr = $this->_curr(); if (($curr != '"') && ($curr != '.') && !$this->_rfc822IsAtext($curr)) { break; } $phrase .= ' '; } while ($this->_ptr < $this->_datalen); $this->_rfc822SkipLwsp(); } /** * @param string &$phrase The quoted string data. * * @throws Horde_Mail_Exception */ protected function _rfc822ParseQuotedString(&$str) { if ($this->_curr(true) != '"') { throw new Horde_Mail_Exception('Error when parsing a quoted string.'); } while (($chr = $this->_curr(true)) !== false) { switch ($chr) { case '"': $this->_rfc822SkipLwsp(); return; case "\n": /* Folding whitespace, remove the (CR)LF. */ if (substr($str, -1) == "\r") { $str = substr($str, 0, -1); } continue; case '\\': if (($chr = $this->_curr(true)) === false) { break 2; } break; } $str .= $chr; } /* Missing trailing '"', or partial quoted character. */ throw new Horde_Mail_Exception('Error when parsing a quoted string.'); } /** * dot-atom = [CFWS] dot-atom-text [CFWS] * dot-atom-text = 1*atext *("." 1*atext) * * atext = ; Any character except controls, SP, and specials. * * For RFC-822 compatibility allow LWSP around '.'. * * * @param string &$str The atom/dot data. * @param string $validate Use these characters as delimiter. * * @throws Horde_Mail_Exception */ protected function _rfc822ParseDotAtom(&$str, $validate = null) { $valid = false; while ($this->_ptr < $this->_datalen) { $chr = $this->_data[$this->_ptr]; /* TODO: Optimize by duplicating rfc822IsAtext code here */ if ($this->_rfc822IsAtext($chr, $validate)) { $str .= $chr; ++$this->_ptr; } elseif (!$valid) { throw new Horde_Mail_Exception('Error when parsing dot-atom.'); } else { $this->_rfc822SkipLwsp(); if ($this->_curr() != '.') { return; } $str .= $chr; $this->_rfc822SkipLwsp(true); } $valid = true; } } /** * atom = [CFWS] 1*atext [CFWS] * atext = ; Any character except controls, SP, and specials. * * This method doesn't just silently skip over WS. * * @param string &$str The atom/dot data. * * @throws Horde_Mail_Exception */ protected function _rfc822ParseAtomOrDot(&$str) { while ($this->_ptr < $this->_datalen) { $chr = $this->_data[$this->_ptr]; if (($chr != '.') && /* TODO: Optimize by duplicating rfc822IsAtext code here */ !$this->_rfc822IsAtext($chr, ',<:')) { $this->_rfc822SkipLwsp(); if (!$this->_params['validate']) { $str = trim($str); } return; } $str .= $chr; ++$this->_ptr; } } /** * domain = dot-atom / domain-literal / obs-domain * domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] * obs-domain = atom *("." atom) * * @param string &$str The domain string. * * @throws Horde_Mail_Exception */ protected function _rfc822ParseDomain(&$str) { if ($this->_curr(true) != '@') { throw new Horde_Mail_Exception('Error when parsing domain.'); } $this->_rfc822SkipLwsp(); if ($this->_curr() == '[') { $this->_rfc822ParseDomainLiteral($str); } else { $this->_rfc822ParseDotAtom($str, ';,> '); } } /** * domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] * dcontent = dtext / quoted-pair * dtext = NO-WS-CTL / ; Non white space controls * %d33-90 / ; The rest of the US-ASCII * %d94-126 ; characters not including "[", * ; "]", or "\" * * @param string &$str The domain string. * * @throws Horde_Mail_Exception */ protected function _rfc822ParseDomainLiteral(&$str) { if ($this->_curr(true) != '[') { throw new Horde_Mail_Exception('Error parsing domain literal.'); } while (($chr = $this->_curr(true)) !== false) { switch ($chr) { case '\\': if (($chr = $this->_curr(true)) === false) { break 2; } break; case ']': $this->_rfc822SkipLwsp(); return; } $str .= $chr; } throw new Horde_Mail_Exception('Error parsing domain literal.'); } /** * @param boolean $advance Advance cursor? * * @throws Horde_Mail_Exception */ protected function _rfc822SkipLwsp($advance = false) { if ($advance) { ++$this->_ptr; } while (($chr = $this->_curr()) !== false) { switch ($chr) { case ' ': case "\n": case "\r": case "\t": ++$this->_ptr; continue; case '(': $this->_rfc822SkipComment(); break; default: return; } } } /** * @throws Horde_Mail_Exception */ protected function _rfc822SkipComment() { if ($this->_curr(true) != '(') { throw new Horde_Mail_Exception('Error when parsing a comment.'); } $comment = ''; $level = 1; while (($chr = $this->_curr(true)) !== false) { switch ($chr) { case '(': ++$level; continue; case ')': if (--$level == 0) { $this->_comments[] = $comment; return; } break; case '\\': if (($chr = $this->_curr(true)) === false) { break 2; } break; } $comment .= $chr; } throw new Horde_Mail_Exception('Error when parsing a comment.'); } /** * Check if data is an atom. * * @param string $chr The character to check. * @param string $validate If in non-validate mode, use these characters * as the non-atom delimiters. * * @return boolean True if a valid atom. */ protected function _rfc822IsAtext($chr, $validate = null) { if (!$this->_params['validate'] && !is_null($validate)) { return strcspn($chr, $validate); } $ord = ord($chr); /* UTF-8 characters check. */ if ($ord > 127) { return ($this->_params['validate'] === 'eai'); } /* Check for DISALLOWED characters under both RFCs 5322 and 6532. */ /* Unprintable characters && [SPACE] */ if ($ord <= 32) { return false; } /* "(),:;<>@[\] [DEL] */ switch ($ord) { case 34: case 40: case 41: case 44: case 58: case 59: case 60: case 62: case 64: case 91: case 92: case 93: case 127: return false; } return true; } /* Helper methods. */ /** * Return current character. * * @param boolean $advance If true, advance the cursor. * * @return string The current character (false if EOF reached). */ protected function _curr($advance = false) { return ($this->_ptr >= $this->_datalen) ? false : $this->_data[$advance ? $this->_ptr++ : $this->_ptr]; } /* Other public methods. */ /** * Returns an approximate count of how many addresses are in the string. * This is APPROXIMATE as it only splits based on a comma which has no * preceding backslash. * * @param string $data Addresses to count. * * @return integer Approximate count. */ public function approximateCount($data) { return count(preg_split('/(?@. This can be sufficient for most people. * * Optional stricter mode can be utilized which restricts mailbox * characters allowed to: alphanumeric, full stop, hyphen, and underscore. * * @param string $data Address to check. * @param boolean $strict Strict check? * * @return mixed False if it fails, an indexed array username/domain if * it matches. */ public function isValidInetAddress($data, $strict = false) { $regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i'; return preg_match($regex, trim($data), $matches) ? array($matches[1], $matches[2]) : false; } } Horde_Mail-2.6.4/lib/Horde/Mail/Translation.php0000664000175000017500000000173713122751204017337 0ustar janjan * @category Horde * @copyright 2014-2017 Horde LLC * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * @since 2.5.0 */ class Horde_Mail_Translation extends Horde_Translation_Autodetect { /** * The translation domain * * @var string */ protected static $_domain = 'Horde_Mail'; /** * The absolute PEAR path to the translations for the default gettext handler. * * @var string */ protected static $_pearDirectory = '@data_dir@'; } Horde_Mail-2.6.4/lib/Horde/Mail/Transport.php0000664000175000017500000002322013122751204017024 0ustar janjan * @author Richard Heyes * @author Michael Slusarz * @category Horde * @copyright 1997-2017 Horde LLC (http://www.horde.org/) * @copyright 2002-2007 Richard Heyes * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * * @property-read boolean $eai Does the transport driver support EAI (RFC * 6532) headers? (@since 2.5.0) */ abstract class Horde_Mail_Transport { /** * Line terminator used for separating header lines. * * @var string */ public $sep = PHP_EOL; /** * Configuration parameters. * * @var array */ protected $_params = array(); /** */ public function __get($name) { switch ($name) { case 'eai': return false; } } /** * 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) { $from = null; $lines = array(); $raw = isset($headers['_raw']) ? $headers['_raw'] : null; foreach ($headers as $key => $value) { if (strcasecmp($key, 'From') === 0) { $parser = new Horde_Mail_Rfc822(); $addresses = $parser->parseAddressList($value, array( 'validate' => $this->eai ? 'eai' : true )); $from = $addresses[0]->bare_address; // Reject envelope From: addresses with spaces. if (strstr($from, ' ')) { return false; } $lines[] = $key . ': ' . $this->_normalizeEOL($value); } elseif (!$raw && (strcasecmp($key, 'Received') === 0)) { $received = array(); if (!is_array($value)) { $value = array($value); } foreach ($value as $line) { $received[] = $key . ': ' . $this->_normalizeEOL($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); } elseif (!$raw) { // 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 . ': ' . $this->_normalizeEOL($value); } } return array($from, $raw ? $raw : implode($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 $recipients Either a comma-separated list of recipients * (RFC822 compliant), or an array of * recipients, each RFC822 valid. * * @return array Forward paths (bare addresses, IDN encoded). * @throws Horde_Mail_Exception */ public function parseRecipients($recipients) { // Parse recipients, leaving out all personal info. This is // for smtp recipients, etc. All relevant personal information // should already be in the headers. $rfc822 = new Horde_Mail_Rfc822(); return $rfc822->parseAddressList($recipients, array( 'validate' => $this->eai ? 'eai' : true ))->bare_addresses_idn; } /** * 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. * * Raw headers are sent as-is. * * @param array $headers The associative array of headers to sanitize. * * @return array The sanitized headers. */ protected function _sanitizeHeaders($headers) { foreach (array_diff(array_keys($headers), array('_raw')) as $key) { $headers[$key] = preg_replace('=((||0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', null, $headers[$key]); } return $headers; } /** * Normalizes EOLs in string data. * * @param string $data Data. * * @return string Normalized data. */ protected function _normalizeEOL($data) { return strtr($data, array( "\r\n" => $this->sep, "\r" => $this->sep, "\n" => $this->sep )); } /** * Get the from address. * * @param string $from From address. * @param array $headers Headers array. * * @return string Address object. * @throws Horde_Mail_Exception */ protected function _getFrom($from, $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 provided.'); } $from = new Horde_Mail_Rfc822_Address($from); return $from->bare_address_idn; } } Horde_Mail-2.6.4/locale/tr/LC_MESSAGES/Horde_Mail.mo0000664000175000017500000000130413122751204017636 0ustar janjanÞ•4L`aBŽÂ$QMvCould not parse mailbox data.Imported mailbox contains more than enforced limit of %u messages.Project-Id-Version: Horde_Mail Report-Msgid-Bugs-To: dev@lists.horde.org POT-Creation-Date: 2017-06-09 16:08+0300 PO-Revision-Date: 2017-06-09 16:20+0300 Language-Team: İTÜ BİDB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Generator: Poedit 1.8.12 Last-Translator: Plural-Forms: nplurals=2; plural=(n != 1); Language: tr Dizin verileri ayrıştırılamadı.İçeri aktarılan dizin %u iletiden daha fazla zorunlu sınırlar içeriyor.Horde_Mail-2.6.4/locale/tr/LC_MESSAGES/Horde_Mail.po0000664000175000017500000000175013122751204017646 0ustar janjan# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Horde LLC (http://www.horde.org/) # This file is distributed under the same license as the Horde_Mail package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: Horde_Mail\n" "Report-Msgid-Bugs-To: dev@lists.horde.org\n" "POT-Creation-Date: 2017-06-09 16:08+0300\n" "PO-Revision-Date: 2017-06-09 16:20+0300\n" "Language-Team: İTÜ BİDB \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.12\n" "Last-Translator: \n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Language: tr\n" #: lib/Horde/Mail/Mbox/Parse.php:65 msgid "Could not parse mailbox data." msgstr "Dizin verileri ayrıştırılamadı." #: lib/Horde/Mail/Mbox/Parse.php:98 #, php-format msgid "Imported mailbox contains more than enforced limit of %u messages." msgstr "" "İçeri aktarılan dizin %u iletiden daha fazla zorunlu sınırlar içeriyor." Horde_Mail-2.6.4/locale/Horde_Mail.pot0000664000175000017500000000146713122751204015625 0ustar janjan# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Horde LLC (http://www.horde.org/) # This file is distributed under the same license as the Horde_Mail package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Horde_Mail\n" "Report-Msgid-Bugs-To: dev@lists.horde.org\n" "POT-Creation-Date: 2014-11-12 14:05+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: lib/Horde/Mail/Mbox/Parse.php:65 msgid "Could not parse mailbox data." msgstr "" #: lib/Horde/Mail/Mbox/Parse.php:98 #, php-format msgid "Imported mailbox contains more than enforced limit of %u messages." msgstr "" Horde_Mail-2.6.4/test/Horde/Mail/fixtures/test.eml0000664000175000017500000000314613122751204020064 0ustar janjanReturn-Path: X-Authentication-Warning: simon.horde.org: www-data set sender to bugs@horde.org using -f X-Whups-Generated: 1 User-Agent: Whups H4 (2.0-git) Precedence: bulk Auto-Submitted: auto-replied From: bugs@horde.org Subject: [Tickets #10390] Add "save to same folder" for sent messages Date: Wed, 27 Jul 2011 11:03:22 +0000 Content-Type: text/plain; charset=UTF-8; format=flowed; DelSp=Yes MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID: X-DSPAM-Result: Whitelisted X-DSPAM-Processed: Wed Jul 27 05:03:26 2011 X-DSPAM-Confidence: 0.9990 X-DSPAM-Probability: 0.0000 X-DSPAM-Signature: 4e2ff07e31264432239041 BITTE NICHT AUF DIESE NACHRICHT ANTWORTEN. NACHRICHTEN AN DIESE E-MAIL-ADRESSE WERDEN NICHT GELESEN. Ticket-URL: http://bugs.horde.org/ticket/10390 ---------------------------------------------------------------------------= --- Ticket | 10390 Erstellt Von | dirk@deimeke.net Zusammenfassung | Add "save to same folder" for sent messages Warteschlange | IMP Version | 5.0.8 Typ | Enhancement Status | New Priorit=C3=A4t | 1. Low Milestone | Patch | Zust=C3=A4ndige | ---------------------------------------------------------------------------= --- dirk@deimeke.net (2011-07-27 11:03) hat geschrieben: In case I write (or answer) a messages there should be an additional option "safe to same folder" and a possibility to make this the default behaviour. Horde_Mail-2.6.4/test/Horde/Mail/fixtures/test.mbox0000664000175000017500000000630713122751204020256 0ustar janjanFrom bugs@horde.org Wed Jul 27 05:03:26 2011 Return-Path: X-Authentication-Warning: simon.horde.org: www-data set sender to bugs@horde.org using -f X-Whups-Generated: 1 User-Agent: Whups H4 (2.0-git) Precedence: bulk Auto-Submitted: auto-replied From: bugs@horde.org Subject: [Tickets #10390] Add "save to same folder" for sent messages Date: Wed, 27 Jul 2011 11:03:22 +0000 Content-Type: text/plain; charset=UTF-8; format=flowed; DelSp=Yes MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID: X-DSPAM-Result: Whitelisted X-DSPAM-Processed: Wed Jul 27 05:03:26 2011 X-DSPAM-Confidence: 0.9990 X-DSPAM-Probability: 0.0000 X-DSPAM-Signature: 4e2ff07e31264432239041 BITTE NICHT AUF DIESE NACHRICHT ANTWORTEN. NACHRICHTEN AN DIESE E-MAIL-ADRESSE WERDEN NICHT GELESEN. Ticket-URL: http://bugs.horde.org/ticket/10390 ---------------------------------------------------------------------------= --- Ticket | 10390 Erstellt Von | dirk@deimeke.net Zusammenfassung | Add "save to same folder" for sent messages Warteschlange | IMP Version | 5.0.8 Typ | Enhancement Status | New Priorit=C3=A4t | 1. Low Milestone | Patch | Zust=C3=A4ndige | ---------------------------------------------------------------------------= --- dirk@deimeke.net (2011-07-27 11:03) hat geschrieben: In case I write (or answer) a messages there should be an additional option "safe to same folder" and a possibility to make this the default behaviour. From bugs@horde.org Mon Oct 31 12:42:48 2011 Return-Path: X-Authentication-Warning: simon.horde.org: www-data set sender to bugs@horde.org using -f X-Whups-Generated: 1 User-Agent: Whups H4 (2.0-git) Precedence: bulk Auto-Submitted: auto-replied From: bugs@horde.org Subject: [Tickets #10648] Re: predefined rights for acl Date: Mon, 31 Oct 2011 19:42:44 +0100 Message-ID: <20111031194245.Horde.XHryaRha3zhOruwldQojvaA@bugs.horde.org> In-Reply-To: References: Content-Type: text/plain; charset=UTF-8; format=flowed; DelSp=Yes MIME-Version: 1.0 X-DSPAM-Result: Whitelisted X-DSPAM-Processed: Mon Oct 31 12:42:48 2011 X-DSPAM-Confidence: 0.9996 X-DSPAM-Probability: 0.0000 X-DSPAM-Signature: 4eaeec28260831286917729 DO NOT REPLY TO THIS MESSAGE. THIS EMAIL ADDRESS IS NOT MONITORED. Ticket URL: http://bugs.horde.org/ticket/10648 ------------------------------------------------------------------------------ Ticket | 10648 Updated By | Jan Schneider Summary | predefined rights for acl Queue | IMP -Version | 5.0.13 +Version | Git master Type | Enhancement -State | New +State | Accepted Priority | 1. Low Milestone | Patch | Owners | ------------------------------------------------------------------------------ Horde_Mail-2.6.4/test/Horde/Mail/fixtures/test2.eml0000664000175000017500000000101113122751204020133 0ustar janjanReturn-Path: Delivered-To: foo@example.com Received: from test1.example.com (test1.example.com [192.168.10.10]) by test2.example.com (Postfix) with ESMTP id E6F7890AF for ; Sat, 26 Jul 2008 20:09:03 -0600 (MDT) Message-ID: Date: Sat, 26 Jul 2008 21:10:00 -0500 (CDT) From: Test To: foo@example.com Subject: Test e-mail 1 Mime-Version: 1.0 Content-Type: text/html From Me. Horde_Mail-2.6.4/test/Horde/Mail/AddressTest.php0000664000175000017500000001003213122751204017463 0ustar janjan * @category Horde * @license http://www.horde.org/licenses/bsd BSD * @package Mail * @subpackage UnitTests */ class Horde_Mail_AddressTest extends PHPUnit_Framework_TestCase { /** * @dataProvider domainMatchProvider */ public function testDomainMatch($addr, $tests) { $address = new Horde_Mail_Rfc822_Address($addr); foreach ($tests as $val) { $match = $address->matchDomain($val[0]); if ($val[1]) { $this->assertTrue($match); } else { $this->assertFalse($match); } } } public function domainMatchProvider() { return array( array( 'Test ', array( array('example.com', true), array('foo.example.com', false) ) ), array( 'Test ', array( array('example.com', true), array('foo.example.com', true) ) ), array( 'Test ', array( array('example.co.uk', true), array('foo.example.co.uk', false), array('co.uk', true) ) ), array( 'Test ', array( array('example.co.uk', true), array('foo.example.co.uk', true), array('co.uk', true) ) ) ); } /** * @dataProvider personalIsSameAsEmailProvider */ public function testPersonalIsSameAsEmail($addr, $expected) { $address = new Horde_Mail_Rfc822_Address($addr); $this->assertEquals( $expected, strval($address) ); } public function personalIsSameAsEmailProvider() { return array( array( '"test@example.com" ', 'test@example.com' ), array( '"TEST@EXAMPLE.COM" ', 'test@example.com' ) ); } /** * @dataProvider labelProvider */ public function testLabel($in, $expected) { $address = new Horde_Mail_Rfc822_Address($in); $this->assertEquals( $expected, $address->label ); } public function labelProvider() { return array( array('foo@example.com', 'foo@example.com'), array('Foo ', 'Foo') ); } /** * @dataProvider personalEncodedProvider */ public function testPersonalEncoded($in, $expected) { $address = new Horde_Mail_Rfc822_Address($in); $this->assertEquals( $expected, $address->personal_encoded ); $this->assertFalse($address->eai); } public function personalEncodedProvider() { return array( array('Foo ', 'Foo'), array('Aäb ', '=?utf-8?b?QcOkYg==?=') ); } /** * @dataProvider eaiAddressesProvider */ public function testEaiAddresses($in, $personal, $email) { $address = new Horde_Mail_Rfc822_Address($in); $this->assertEquals( $personal, $address->personal ); $this->assertEquals( $email, $address->bare_address ); $this->assertTrue($address->eai); } public function eaiAddressesProvider() { return array( /* Example from https://github.com/arnt/eai-test-messages */ array( 'Jøran ØygÃ¥rdvær ', 'Jøran ØygÃ¥rdvær', 'jøran@example.com' ) ); } } Horde_Mail-2.6.4/test/Horde/Mail/AllTests.php0000664000175000017500000000013213122751204016771 0ustar janjanrun(); Horde_Mail-2.6.4/test/Horde/Mail/bootstrap.php0000664000175000017500000000014313122751204017255 0ustar janjan * @category Horde * @license http://www.horde.org/licenses/bsd BSD * @package Mail * @subpackage UnitTests */ class Horde_Mail_GroupTest extends PHPUnit_Framework_TestCase { /** * @dataProvider writeAddressProvider */ public function testWriteAddress($addresses, $groupname, $encode, $expected) { $group_ob = new Horde_Mail_Rfc822_Group($groupname, $addresses); $this->assertEquals( $expected, $group_ob->writeAddress(array('encode' => $encode)) ); } public function writeAddressProvider() { return array( array( array( 'Test ', 'foo@example.com' ), 'Testing', false, 'Testing: Test , foo@example.com;' ), array( array( 'Fooã ', 'foo@example.com' ), 'Group "Foo"', true, '"Group \"Foo\"": =?utf-8?b?Rm9vw6M=?= , foo@example.com;' ) ); } public function testValid() { $group_ob = new Horde_Mail_Rfc822_Group(); $this->assertTrue($group_ob->valid); $group_ob->groupname = ''; $this->assertFalse($group_ob->valid); } public function testEmptyGroupCount() { $group_ob = new Horde_Mail_Rfc822_Group('Group'); $this->assertEquals( 0, count($group_ob) ); } /** * @dataProvider encodingGroupnameProvider */ public function testEncodingGroupname($in, $expected) { $group_ob = new Horde_Mail_Rfc822_Group($in); $this->assertEquals( $expected, $group_ob->groupname_encoded ); } public function encodingGroupnameProvider() { return array( array('Foo', 'Foo'), array('Aäb', '=?utf-8?b?QcOkYg==?=') ); } /** * @dataProvider matchProvider */ public function testMatch($compare, $result) { $ob = new Horde_Mail_Rfc822_Group( 'Testing', array( 'foo@example.com', 'bar@example.com' ) ); if ($result) { $this->assertTrue($ob->match($compare)); } else { $this->assertFalse($ob->match($compare)); } } public function matchProvider() { return array( array(array('foo@example.com'), false), array(array('bar@example.com'), false), array(array('foo@example.com', 'bar@example.com'), true), array(array('bar@example.com', 'foo@example.com'), true) ); } } Horde_Mail-2.6.4/test/Horde/Mail/IdentificationTest.php0000664000175000017500000000405113122751204021033 0ustar janjan * @category Horde * @copyright 2012-2016 Horde LLC * @ignore * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * @subpackage UnitTests */ class Horde_Mail_IdentificationTest extends PHPUnit_Framework_TestCase { /** * @dataProvider provider */ public function testParsing($value, $count) { $ob = new Horde_Mail_Rfc822_Identification($value); $this->assertEquals( $count, count($ob->ids) ); } public function provider() { return array( array( ' ', 3 ), array( '', 3 ), array( ', ,', 3 ), array( ', , ', 5 ), // Bug #11953 array( '', 1 ), // Parse non-compliant IDs array( 'foo@example.com', 1 ), array( 'foo@example.com ', 2 ), array( 'foo@example.com, ', 2 ) ); } } Horde_Mail-2.6.4/test/Horde/Mail/ListTest.php0000664000175000017500000003044113122751204017017 0ustar janjan * @category Horde * @license http://www.horde.org/licenses/bsd BSD * @package Mail * @subpackage UnitTests */ class Horde_Mail_ListTest extends PHPUnit_Framework_TestCase { private $rfc822; public function setUp() { $this->rfc822 = new Horde_Mail_Rfc822(); } public function testSingleAddress() { $email = 'Test '; $res = $this->rfc822->parseAddressList($email); $this->assertEquals( 1, count($res) ); $expected = array($email); foreach ($res as $key => $val) { $this->assertEquals( $expected[$key], strval($val) ); } $this->assertEquals( $expected, $res->addresses ); $expected = array( 'test@example.com' ); $this->assertEquals( $expected, $res->bare_addresses ); $this->assertEquals( 0, $res->groupCount() ); } public function testSingleAddressWithFilter() { $email = 'Test '; $res = $this->rfc822->parseAddressList($email); $res->setIteratorFilter(0, array('test@example.com')); $this->assertEquals( 0, count($res) ); foreach ($res as $val) { $this->fail('Results should be empty.'); } $this->assertEquals( array(), $res->addresses ); $this->assertEquals( array(), $res->bare_addresses ); $this->assertEquals( 0, $res->groupCount() ); } public function testSimpleAddressList() { $email = 'Test , Test2 '; $res = $this->rfc822->parseAddressList($email); $this->assertEquals( 2, count($res) ); $expected = array( 'Test ', 'Test2 ' ); foreach ($res as $key => $val) { $this->assertEquals( $expected[$key], strval($val) ); } $this->assertEquals( $expected, $res->addresses ); $expected = array( 'test@example.com', 'test2@example.com' ); $this->assertEquals( $expected, $res->bare_addresses ); $this->assertEquals( 0, $res->groupCount() ); } public function testSeekingInList() { $email = 'Test , Test2 '; $res = $this->rfc822->parseAddressList($email); try { $res->seek(1); } catch (OutOfBoundsException $e) { $this->fail('Unexpected Exception.'); } $this->assertEquals( 'test2', $res->current()->mailbox ); // Seek to current pointer value. try { $res->seek(1); } catch (OutOfBoundsException $e) { $this->fail('Unexpected Exception.'); } $this->assertEquals( 'test2', $res->current()->mailbox ); try { $res->seek(0); } catch (OutOfBoundsException $e) { $this->fail('Unexpected Exception.'); } $this->assertEquals( 'test', $res->current()->mailbox ); try { $res->seek(2); $this->fail('Expected Exception.'); } catch (OutOfBoundsException $e) {} } public function testArraySet() { $email = 'Test '; $res = $this->rfc822->parseAddressList($email); $res[0] = 'Test2 '; $this->assertTrue(isset($res[0])); $this->assertEquals( 1, count($res) ); $this->assertEquals( 'test2', $res[0]->mailbox ); } public function testArrayUnset() { $email = 'Test , Test2 '; $res = $this->rfc822->parseAddressList($email); unset($res[0]); $this->assertEquals( 1, count($res) ); $this->assertEquals( 'test2', $res[0]->mailbox ); } public function testSimpleAddressListWithFilter() { $email = 'Test , Test2 '; $res = $this->rfc822->parseAddressList($email); $res->setIteratorFilter(0, array('test@example.com')); $this->assertEquals( 1, count($res) ); $expected = array( 'Test2 ' ); foreach ($res as $key => $val) { $this->assertEquals( $expected[$key], strval($val) ); } $this->assertEquals( $expected, $res->addresses ); $expected = array( 'test2@example.com' ); $this->assertEquals( $expected, $res->bare_addresses ); $this->assertEquals( 0, $res->groupCount() ); } public function testAddressListWithGroup() { $email = 'Test , Group: foo@example.com, Foo 2 ;, Test2 '; $res = $this->rfc822->parseAddressList($email); $this->assertEquals( 4, count($res) ); $expected = array( 'Test ', 'Group: foo@example.com, Foo 2 ;', 'foo@example.com', 'Foo 2 ', 'Test2 ' ); foreach ($res as $key => $val) { $this->assertEquals( $expected[$key], strval($val) ); } unset($expected[1]); $this->assertEquals( array_values($expected), $res->addresses ); $expected = array( 'test@example.com', 'foo@example.com', 'foo2@example.com', 'test2@example.com' ); $this->assertEquals( $expected, $res->bare_addresses ); $this->assertEquals( 1, $res->groupCount() ); } public function testAddressListWithGroupWithFilter() { $email = 'Test , Group: foo@example.com, Foo 2 ;, Test2 '; $res = $this->rfc822->parseAddressList($email); $res->setIteratorFilter(0, array('foo@example.com')); $this->assertEquals( 3, count($res) ); $expected = array( 'Test ', 'Group: foo@example.com, Foo 2 ;', 'Foo 2 ', 'Test2 ' ); foreach ($res as $key => $val) { $this->assertEquals( $expected[$key], strval($val) ); } unset($expected[1]); $this->assertEquals( array_values($expected), $res->addresses ); $expected = array( 'test@example.com', 'foo2@example.com', 'test2@example.com' ); $this->assertEquals( $expected, $res->bare_addresses ); $res->setIteratorFilter(Horde_Mail_Rfc822_List::HIDE_GROUPS); $expected = array( 'Test ', 'foo@example.com', 'Foo 2 ', 'Test2 ' ); foreach ($res as $key => $val) { $this->assertEquals( $expected[$key], strval($val) ); } } public function testRemove() { $email = 'Test , Group: foo@example.com, Foo 2 ;, Test2 '; $res = $this->rfc822->parseAddressList($email); $res_clone = clone $res; $res_clone->remove('test2@example.com'); $this->assertEquals( 3, count($res_clone) ); $res_clone = clone $res; $res_clone->remove('foo@example.com'); $this->assertEquals( 4, count($res_clone) ); } public function testUnique() { $email = 'Test , test@example.com'; $res = $this->rfc822->parseAddressList($email); $res->unique(); $this->assertEquals( 1, count($res) ); $this->assertEquals( 'Test', $res[0]->personal ); $email = 'test@example.com, Test , test2@example.com'; $res = $this->rfc822->parseAddressList($email); $res->unique(); $this->assertEquals( 2, count($res) ); $this->assertEquals( 'Test', $res[0]->personal ); } public function testAddressesProperties() { $email = 'Test , Group: foo@example.com, Foo 2 ;, Test2 '; $res = $this->rfc822->parseAddressList($email); $ob = $res->addresses; $this->assertEquals( 4, count($ob) ); $this->assertInternalType('string', $ob[0]); $ob = $res->bare_addresses; $this->assertEquals( 4, count($ob) ); $this->assertInternalType('string', $ob[0]); $ob = $res->base_addresses; $this->assertEquals( 3, count($ob) ); $this->assertTrue($ob[0] instanceof Horde_Mail_Rfc822_Address); $this->assertTrue($ob[1] instanceof Horde_Mail_Rfc822_Group); $ob = $res->raw_addresses; $this->assertEquals( 4, count($ob) ); $this->assertTrue($ob[0] instanceof Horde_Mail_Rfc822_Address); $this->assertTrue($ob[1] instanceof Horde_Mail_Rfc822_Address); } public function testIterateEmptyArray() { $ob = new Horde_Mail_Rfc822_List(); foreach ($ob as $val) { $this->fail('Nothing to iterate.'); } $ob = new Horde_Mail_Rfc822_List( new Horde_Mail_Rfc822_Group() ); $ob->setIteratorFilter(Horde_Mail_Rfc822_List::HIDE_GROUPS); foreach ($ob as $val) { $this->fail('Nothing to iterate.'); } } public function testContains() { $email = 'Test , Group: foo@example.com, Foo 2 ;, Test2 '; $res = $this->rfc822->parseAddressList($email); $this->assertTrue($res->contains('test@example.com')); $this->assertTrue($res->contains('foo2@example.com')); $this->assertFalse($res->contains('foo4@example.com')); } /** * @dataProvider matchProvider */ public function testMatch($compare, $result) { $ob = new Horde_Mail_Rfc822_List(array( 'foo@example.com', 'bar@example.com' )); if ($result) { $this->assertTrue($ob->match($compare)); } else { $this->assertFalse($ob->match($compare)); } } public function matchProvider() { return array( array(array('foo@example.com'), false), array(array('bar@example.com'), false), array(array('foo@example.com', 'bar@example.com'), true), array(array('bar@example.com', 'foo@example.com'), true) ); } public function testSerialization() { $ob = new Horde_Mail_Rfc822_List('foo@example.com'); $ob2 = unserialize(serialize($ob)); $this->assertEquals( 1, count($ob2) ); $this->assertEquals( 'foo', $ob[0]->mailbox ); } } Horde_Mail-2.6.4/test/Horde/Mail/MatchTest.php0000664000175000017500000000451513122751204017143 0ustar janjan * @category Horde * @license http://www.horde.org/licenses/bsd BSD * @package Mail * @subpackage UnitTests */ class Horde_Mail_MatchTest extends PHPUnit_Framework_TestCase { /** * @dataProvider matchProvider */ public function testMatch($in, $match, $expected) { $address = new Horde_Mail_Rfc822_Address($in); $this->assertEquals( $expected, $address->match($match) ); } public function matchProvider() { $test1 = 'Test '; $test2 = 'Test '; return array( array( $test1, 'Foo ', true ), array( $test1, 'Foo ', true ), array( $test1, 'Foo ', false ), array( $test2, 'Foo ', false ), array( $test2, 'täst@example.com', true ) ); } /** * @dataProvider insensitiveMatchProvider */ public function testInsensitiveMatch($in, $match, $expected) { $address = new Horde_Mail_Rfc822_Address($in); $this->assertEquals( $expected, $address->matchInsensitive($match) ); } public function insensitiveMatchProvider() { $test1 = 'Test '; $test2 = 'Test '; return array( array( $test1, 'Foo ', true ), array( $test1, 'Foo ', true ), array( $test1, 'Foo ', true ), array( $test1, 'test1@example.com', false ), array( $test2, 'TäST@EXAMPLE.cOm', true ) ); } } Horde_Mail-2.6.4/test/Horde/Mail/MboxParseTest.php0000664000175000017500000000442113122751204020003 0ustar janjan * @category Horde * @copyright 2011-2016 Horde LLC * @ignore * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * @subpackage UnitTests */ class Horde_Mail_MboxParseTest extends PHPUnit_Framework_TestCase { public function testMboxParse() { $parse = new Horde_Mail_Mbox_Parse(__DIR__ . '/fixtures/test.mbox'); $this->assertEquals( 2, count($parse) ); $i = 0; foreach ($parse as $key => $val) { $this->assertEquals( $i++, $key ); $this->assertInternalType( 'array', $val ); $this->assertEquals( "Return-Path: \r\n", fgets($val['data']) ); } } /** * @dataProvider emlParseProvider */ public function testEmlParse($data, $first_line) { $parse = new Horde_Mail_Mbox_Parse($data); $this->assertEquals( 1, count($parse) ); $val = $parse[0]; $this->assertInternalType( 'array', $val ); $this->assertEquals( $first_line . "\r\n", fgets($val['data']) ); } public function emlParseProvider() { return array( array( __DIR__ . '/fixtures/test.eml', 'Return-Path: ' ), array( __DIR__ . '/fixtures/test2.eml', 'Return-Path: ' ) ); } /** * @expectedException Horde_Mail_Exception */ public function testBadData() { new Horde_Mail_Mbox_Parse(__DIR__ . '/noexist'); } } Horde_Mail-2.6.4/test/Horde/Mail/ObjectTest.php0000664000175000017500000001310213122751204017305 0ustar janjan * @category Horde * @license http://www.horde.org/licenses/bsd BSD * @package Mail * @subpackage UnitTests */ class Horde_Mail_ObjectTest extends PHPUnit_Framework_TestCase { public function testWriteAddress() { $address = 'Test '; $parser = new Horde_Mail_Rfc822(); $result = $parser->parseAddressList($address); $this->assertEquals( $address, $result[0]->writeAddress() ); } public function testEncoding() { $address = 'Fooã '; $parser = new Horde_Mail_Rfc822(); $result = $parser->parseAddressList($address); $this->assertEquals( $address, $result[0]->writeAddress() ); $this->assertEquals( '=?utf-8?b?Rm9vw6M=?= ', $result[0]->writeAddress(array('encode' => true)) ); $this->assertEquals( '=?iso-8859-1?b?Rm9v4w==?= ', $result[0]->writeAddress(array('encode' => 'iso-8859-1')) ); $email = 'ß '; $result = $parser->parseAddressList($email); $this->assertEquals( '=?utf-8?b?w58=?= ', $result[0]->writeAddress(array('encode' => true)) ); $email2 = 'ß X '; $result = $parser->parseAddressList($email2); $this->assertEquals( '=?utf-8?b?w58=?= X ', $result[0]->writeAddress(array('encode' => true)) ); $email3 = '"ß X" '; $result = $parser->parseAddressList($email3); $this->assertEquals( '=?utf-8?b?w58=?= X ', $result[0]->writeAddress(array('encode' => true)) ); } public function testAddressConstructor() { $address = 'Test '; $addr_ob = new Horde_Mail_Rfc822_Address($address); $this->assertEquals( 'Test', $addr_ob->personal ); $this->assertEquals( 'test', $addr_ob->mailbox ); $this->assertEquals( 'example.com', $addr_ob->host ); } public function testEncodedAddressWithIDNHost() { $ob = new Horde_Mail_Rfc822_Address(); $ob->personal = 'Aäb'; $ob->mailbox = 'test'; $ob->host = 'üexample.com'; $this->assertEquals( '=?utf-8?b?QcOkYg==?= ', $ob->encoded ); } public function testDecodedAddressWithIDNHost() { $ob = new Horde_Mail_Rfc822_Address(); $ob->personal = '=?utf-8?b?QcOkYg==?='; $ob->mailbox = 'test'; $ob->host = 'xn--example-m2a.com'; $this->assertEquals( 'Aäb ', strval($ob) ); } public function testBug4834() { // Bug #4834: Wrong encoding of email lists with groups. $addr = '"John Doe" , Group: peter@example.com, jane@example.com;'; $parser = new Horde_Mail_Rfc822(); $result = $parser->parseAddressList($addr); $this->assertEquals( 'John Doe , Group: peter@example.com, jane@example.com;', strval($result) ); } public function testValid() { $ob = new Horde_Mail_Rfc822_Address(); $this->assertFalse($ob->valid); $ob->mailbox = 'test'; $this->assertTrue($ob->valid); } /** * @dataProvider commentOutputProvider */ public function testCommentOutput($expected, $params) { $ob = new Horde_Mail_Rfc822_Address(); foreach ($params as $key => $val) { $ob->$key = $val; } $this->assertEquals( $expected, $ob->writeAddress(array('comment' => true)) ); } public function commentOutputProvider() { $base_addr = array( 'host' => 'example.com', 'mailbox' => 'foo', 'personal' => 'Foo' ); return array( array( 'Foo (Test Comment) ', array_merge($base_addr, array( 'comment' => array( 'Test Comment' ) )) ), array( 'Foo (Test Comment) (2nd Comment) ', array_merge($base_addr, array( 'comment' => array( 'Test Comment', '2nd Comment' ) )) ), array( 'Foo ("Test (( Comment") ', array_merge($base_addr, array( 'comment' => array( 'Test (( Comment' ) )) ), array( 'Foo ("Test \"( Comment") ', array_merge($base_addr, array( 'comment' => array( 'Test "( Comment' ) )) ), array( 'Foo (Test "Comment") ', array_merge($base_addr, array( 'comment' => array( 'Test "Comment"' ) )) ) ); } } Horde_Mail-2.6.4/test/Horde/Mail/ParseTest.php0000664000175000017500000004146013122751204017161 0ustar janjan * @license http://www.horde.org/licenses/bsd BSD * @category Horde * @package Mail * @subpackage UnitTests */ class Horde_Mail_ParseTest extends PHPUnit_Framework_TestCase { private $rfc822; public function setUp() { $this->rfc822 = new Horde_Mail_Rfc822(); } /* Test case for PEAR Mail:: bug #13659 */ public function testParseBug13659() { $address = '"Test Student" (test)'; $result = $this->rfc822->parseAddressList($address, array( 'default_domain' => 'anydomain.com' )); $this->assertTrue($result instanceof Horde_Mail_Rfc822_List); $ob = $result[0]; $this->assertTrue($ob instanceof Horde_Mail_Rfc822_Address); $this->assertEquals( 'Test Student', $ob->personal ); $this->assertEquals( 'test', $ob->mailbox ); $this->assertEquals( 'mydomain.com', $ob->host ); $this->assertInternalType( 'array', $ob->comment ); $this->assertEquals( 1, count($ob->comment) ); $this->assertEquals( 'test', $ob->comment[0] ); } /** * Test case for PEAR Mail:: bug #9137 * * @dataProvider parseBug9137Provider * */ public function testParseBug9137($name, $email) { /* Throws Exception on error. */ $this->rfc822->parseAddressList( '"' . addslashes($name) . '" <' . $email . '>' ); } public function parseBug9137Provider() { return array( array('John Doe', 'test@example.com'), array('John Doe\\', 'test@example.com'), array('John "Doe', 'test@example.com'), array('John "Doe\\', 'test@example.com') ); } /** * Test case for PEAR Mail:: bug #9137, take 2 * * @dataProvider parseBug9137Take2Provider */ public function testParseBug9137Take2($raw, $fail) { try { $this->rfc822->parseAddressList($raw, array( 'validate' => true )); if ($fail) { $this->fail('An expected exception was not raised.'); } } catch (Horde_Mail_Exception $e) { if (!$fail) { $this->fail('An unexpected exception was raised.'); } } } public function parseBug9137Take2Provider() { return array( array('"John Doe" ', false), array('"John Doe' . chr(92) . '" ', true), array('"John Doe' . chr(92) . chr(92) . '" ', false), array('"John Doe' . chr(92) . chr(92) . chr(92) . '" ', true), array('"John Doe' . chr(92) . chr(92) . chr(92) . chr(92) . '" ', false), array('"John Doe ', true) ); } public function testGeneralParsing() { /* A simple, bare address. */ $address = 'user@example.com'; $result = $this->rfc822->parseAddressList($address, array( 'default_domain' => null )); $this->assertTrue($result instanceof Horde_Mail_Rfc822_List); $this->assertTrue($result[0] instanceof Horde_Mail_Rfc822_Address); $this->assertEquals($result[0]->personal, ''); $this->assertInternalType('array', $result[0]->comment); $this->assertEquals($result[0]->comment, array()); $this->assertEquals($result[0]->mailbox, 'user'); $this->assertEquals($result[0]->host, 'example.com'); /* Address groups. */ $address = 'My Group: "Richard" (A comment), ted@example.com (Ted Bloggs), Barney;'; $result = $this->rfc822->parseAddressList($address, array( 'default_domain' => null )); $this->assertTrue($result instanceof Horde_Mail_Rfc822_List); $this->assertTrue($result[0] instanceof Horde_Mail_Rfc822_Group); $this->assertEquals($result[0]->groupname, 'My Group'); $this->assertTrue($result[0]->addresses instanceof Horde_Mail_Rfc822_GroupList); $this->assertEquals(0, $result[0]->addresses->groupCount()); $this->assertInternalType('object', $result[0]->addresses[0]); $this->assertEquals($result[0]->addresses[0]->personal, 'Richard'); $this->assertInternalType('array', $result[0]->addresses[0]->comment); $this->assertEquals($result[0]->addresses[0]->comment[0], 'A comment'); $this->assertEquals($result[0]->addresses[0]->mailbox, 'richard'); $this->assertEquals($result[0]->addresses[0]->host, 'example.com'); $this->assertInternalType('object', $result[0]->addresses[1]); $this->assertEquals($result[0]->addresses[1]->personal, ''); $this->assertInternalType('array', $result[0]->addresses[1]->comment); $this->assertEquals($result[0]->addresses[1]->comment[0], 'Ted Bloggs'); $this->assertEquals($result[0]->addresses[1]->mailbox, 'ted'); $this->assertEquals($result[0]->addresses[1]->host, 'example.com'); $this->assertInternalType('object', $result[0]->addresses[2]); $this->assertEquals($result[0]->addresses[2]->personal, ''); $this->assertInternalType('array', $result[0]->addresses[2]->comment); $this->assertEquals($result[0]->addresses[2]->comment, array()); $this->assertEquals($result[0]->addresses[2]->mailbox, 'Barney'); $this->assertEmpty($result[0]->addresses[2]->host); /* A valid address with spaces in the local part. */ $address = '<"Jon Parise"@php.net>'; $result = $this->rfc822->parseAddressList($address, array( 'default_domain' => null )); $this->assertTrue($result instanceof Horde_Mail_Rfc822_List); $this->assertTrue($result[0] instanceof Horde_Mail_Rfc822_Address); $this->assertEquals($result[0]->personal, ''); $this->assertInternalType('array', $result[0]->comment); $this->assertEquals($result[0]->comment, array()); $this->assertEquals($result[0]->mailbox, 'Jon Parise'); $this->assertEquals($result[0]->host, 'php.net'); /* An invalid address with spaces in the local part. */ $address = ''; try { $this->rfc822->parseAddressList($address, array( 'validate' => true )); $this->fail('An expected exception was not raised.'); } catch (Horde_Mail_Exception $e) {} /* A valid address with an uncommon TLD. */ $address = 'jon@host.longtld'; try { $this->rfc822->parseAddressList($address, array( 'validate' => true )); } catch (Horde_Mail_Exception $e) { $this->fail('An unexpected exception was raised.'); } } public function testValidateQuotedString() { $address_string = '"Joe Doe \(from Somewhere\)" , postmaster@example.com, root'; $res = $this->rfc822->parseAddressList($address_string, array( 'default_domain' => 'example.com' )); $this->assertTrue($res instanceof Horde_Mail_Rfc822_List); $this->assertEquals(count($res), 3); } public function testBug9525() { try { $ob = $this->rfc822->parseAddressList( 'ß ', array( 'default_domain' => 'example.com', 'validate' => true ) ); $this->fail('Expecting Exception.'); } catch (Horde_Mail_Exception $e) {} /* This technically shouldn't validate, but the parser is very liberal * about accepting characters within quotes. */ $ob = $this->rfc822->parseAddressList( '"ß" ', array( 'default_domain' => 'example.com' ) ); } public function testBug10534() { $ob = $this->rfc822->parseAddressList(''); $this->assertEquals( 0, count($ob) ); } public function testNoValidation() { $ob = $this->rfc822->parseAddressList( '"ß" ', array( 'default_domain' => 'example.com' ) ); $this->assertEquals( 'ß', $ob[0]->personal ); $ob = $this->rfc822->parseAddressList( 'ß ß ', array( 'default_domain' => 'example.com' ) ); $this->assertEquals( 'ß ß', $ob[0]->personal ); } public function testLimit() { $email = array_fill(0, 10, 'A '); $ob = $this->rfc822->parseAddressList( implode(', ', $email), array( 'limit' => 5 ) ); $this->assertEquals( 5, count($ob) ); } public function testMissingMailboxInNonValidateMode() { $email = 'A '; $ob = $this->rfc822->parseAddressList($email); /* This can't work even in non-validate mode; since there is no hope * that something like encoding will fix in the future. */ $this->assertEquals( 0, count($ob) ); } public function testMissingAddressWhenParsingGroupInNonValidateMode() { $email = 'Group: foo@example.com, A;'; $ob = $this->rfc822->parseAddressList($email); $this->assertEquals( 2, count($ob[0]->addresses) ); } public function testParseGroupWhenNotValidating() { $email = 'Group: foo@example.com, foo2@example.com;'; $ob = $this->rfc822->parseAddressList($email); $this->assertEquals( 2, count($ob[0]->addresses) ); } public function testLargeParse() { $email = array_fill(0, 1000, 'A , "A B" , foo@example.com, Group: A ;, Group2: "A B" ;'); $ob = $this->rfc822->parseAddressList(implode(', ', $email)); $this->assertEquals( 5000, count($ob) ); } public function testArrayAccess() { $ob = $this->rfc822->parseAddressList( 'A ', array( 'default_domain' => 'example.com' ) ); $this->assertEquals( 'A', $ob[0]->personal ); $this->assertEquals( 'example.com', $ob[0]->host ); $this->assertTrue( isset($ob[0]->mailbox) ); $this->assertFalse( isset($ob[0]->bar) ); } public function testEmailInDisplayPart() { $ob = $this->rfc822->parseAddressList( 'Foo Bar , "bad_email@example.com, Baz" , "Qux" ' ); $this->assertEquals( 3, count($ob) ); } public function testValidation() { $ob = $this->rfc822->parseAddressList( '"Tek-Diária - Newsletter" ' ); $this->assertEquals( 1, count($ob) ); } /** * @dataProvider utf8CharactersInAddressProvider */ public function testUtf8CharactersInAddress($address, $valid_eai) { $ob = $this->rfc822->parseAddressList($address); $this->assertEquals( 1, count($ob) ); try { $this->rfc822->parseAddressList($address, array( 'validate' => true )); $this->fail('Expected Exception.'); } catch (Horde_Mail_Exception $e) {} try { $this->rfc822->parseAddressList($address, array( 'validate' => 'eai' )); if (!$valid_eai) { $this->fail('Expected Exception.'); } } catch (Horde_Mail_Exception $e) { if ($valid_eai) { $this->fail('Not expecting Exception.'); } } } public function utf8CharactersInAddressProvider() { return array( array('fooççç@example.com', true), array('Jøran ØygÃ¥rdvær ', true), array('foo@üexample.com', true), array('foo"ççç@example.com', false), array('Jøran ØygÃ¥rdvær ', false), array('f\10oo@üexample.com', false) ); } public function testParsingNonValidateAddressWithBareAddressAtFront() { $address = 'test@example.com, Foo '; $ob = $this->rfc822->parseAddressList($address); $this->assertEquals( 2, count($ob) ); $this->assertEquals( 'example.com', $ob[0]->host ); } public function testParsingIDNHost() { $email = 'Aäb '; $ob = $this->rfc822->parseAddressList($email); $this->assertEquals( 1, count($ob) ); $this->assertEquals( 'üexample.com', $ob[0]->host ); try { $this->rfc822->parseAddressList($email, array( 'validate' => true )); $this->fail('Expected Exception'); } catch (Exception $e) {} } public function testParsingSimpleString() { $email = 'Test'; $ob = $this->rfc822->parseAddressList($email); $this->assertEquals( 1, count($ob) ); $this->assertEquals( $email, $ob[0]->mailbox ); $this->assertEquals( $email, (string)$ob[0] ); } public function testParsingPersonalPartWithQuotes() { $email = '"Test \\"F-oo\\" Bar" '; $ob = new Horde_Mail_Rfc822_Address($email); $this->assertEquals( '"Test \"F-oo\" Bar" ', $ob->writeAddress() ); $this->assertEquals( $email, $ob->writeAddress(true) ); } public function testParsingPersonalPartWithCommas() { $email = "\"Foo, Bar\" "; $ob = $this->rfc822->parseAddressList($email); $this->assertEquals( $email, $ob->writeAddress(true) ); $ob = $this->rfc822->parseAddressList($email, array( 'validate' => true )); $this->assertEquals( $email, $ob->writeAddress(true) ); } public function testParseOfGroupObject() { $email = 'Test: foo@example.com, bar@example.com;'; $ob = $this->rfc822->parseAddressList($email); $ob2 = $this->rfc822->parseAddressList($ob); $this->assertEquals( 2, count($ob2) ); } public function testDefaultDomain() { $address = 'foo@example2.com'; $result = $this->rfc822->parseAddressList($address, array( 'default_domain' => 'example.com' )); $this->assertEquals( 'foo@example2.com', strval($result) ); $address = 'foo'; $result = $this->rfc822->parseAddressList($address, array( 'default_domain' => 'example.com' )); $this->assertEquals( 'foo@example.com', strval($result) ); } /** * @dataProvider bareMailboxWithoutDefaultDomainProvider */ public function testBareMailboxWithoutDefaultDomainWithoutValidating($addr) { $res = $this->rfc822->parseAddressList($addr, array( 'default_domain' => null )); $this->assertEquals( 'foo', $res[0]->mailbox ); $this->assertNull($res[0]->host); } /** * @dataProvider bareMailboxWithoutDefaultDomainProvider */ public function testBareMailboxWithoutDefaultDomainWhenValidating($addr) { try { $this->rfc822->parseAddressList($addr, array( 'default_domain' => null, 'validate' => true )); $this->fail('An expected exception was not raised.'); } catch (Horde_Mail_Exception $e) {} } public function bareMailboxWithoutDefaultDomainProvider() { return array( array('foo'), array('foo@') ); } } Horde_Mail-2.6.4/test/Horde/Mail/phpunit.xml0000664000175000017500000000005613122751204016743 0ustar janjan Horde_Mail-2.6.4/test/Horde/Mail/SendTest.php0000664000175000017500000000452713122751204017003 0ustar janjan * @category Horde * @license http://www.horde.org/licenses/bsd BSD * @package Mail * @subpackage UnitTests */ class Horde_Mail_SendTest extends PHPUnit_Framework_TestCase { /* Test case for mixed EOLs. */ public function testMixedEOLs() { $ob = new Horde_Mail_Transport_Mock(); $ob->sep = "\n"; $recipients = 'Test '; $body = "Foo\r\nBar\nBaz\rTest"; $headers = array( 'To' => '', 'From' => '', 'Subject' => 'Test', 'X-Test' => 'Line 1\r\n\tLine 2\n\tLine 3\r\tLine 4', 'X-Truncated-Header' => $body ); $ob->send($recipients, $headers, $body); if (preg_match("/(?<=\r)\n/", $ob->sentMessages[0]['header_text'])) { $this->fail("Unexpected EOL in headers."); } if (preg_match("/(?<=\r)\n/", $ob->sentMessages[0]['body'])) { $this->fail("Unexpected EOL in body."); } $ob->sep = "\r\n"; $ob->send($recipients, $headers, $body); if (preg_match("/(?sentMessages[1]['header_text'])) { $this->fail("Unexpected EOL in headers."); } if (preg_match("/(?sentMessages[1]['body'])) { $this->fail("Unexpected EOL in body."); } } public function testBug12116() { $addr = new Horde_Mail_Rfc822_Address(); $addr->personal = 'Aäb'; $addr->mailbox = 'test'; $addr->host = 'üexample.com'; $ob = new Horde_Mail_Transport_Mock(); $ob->send( array($addr), array( 'Return-Path' => $addr ), 'Foo' ); $this->assertEquals( array('test@xn--example-m2a.com'), $ob->sentMessages[0]['recipients'] ); $this->assertEquals( 'test@xn--example-m2a.com', $ob->sentMessages[0]['from'] ); } public function testMissingFrom() { $ob = new Horde_Mail_Transport_Mock(); try { $ob->send(array('foo@example.com'), array(), 'Foo'); $this->fail('Expected Horde_Mail_Exception.'); } catch (Horde_Mail_Exception $e) { } } }