added google xoauth2 support + fixed a journaling issue

This commit is contained in:
SJ
2012-09-28 10:34:04 +02:00
parent f930aacc84
commit 55de53bb26
111 changed files with 38812 additions and 4 deletions

96
webui/Zend/Exception.php Normal file
View File

@ -0,0 +1,96 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Exception extends Exception
{
/**
* @var null|Exception
*/
private $_previous = null;
/**
* Construct the exception
*
* @param string $msg
* @param int $code
* @param Exception $previous
* @return void
*/
public function __construct($msg = '', $code = 0, Exception $previous = null)
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
parent::__construct($msg, (int) $code);
$this->_previous = $previous;
} else {
parent::__construct($msg, (int) $code, $previous);
}
}
/**
* Overloading
*
* For PHP < 5.3.0, provides access to the getPrevious() method.
*
* @param string $method
* @param array $args
* @return mixed
*/
public function __call($method, array $args)
{
if ('getprevious' == strtolower($method)) {
return $this->_getPrevious();
}
return null;
}
/**
* String representation of the exception
*
* @return string
*/
public function __toString()
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
if (null !== ($e = $this->getPrevious())) {
return $e->__toString()
. "\n\nNext "
. parent::__toString();
}
}
return parent::__toString();
}
/**
* Returns previous Exception
*
* @return Exception|null
*/
protected function _getPrevious()
{
return $this->_previous;
}
}

1276
webui/Zend/Mail.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Exception
*/
require_once 'Zend/Exception.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Exception extends Zend_Exception
{}

112
webui/Zend/Mail/Message.php Normal file
View File

@ -0,0 +1,112 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Message.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Mail_Part
*/
require_once 'Zend/Mail/Part.php';
/**
* Zend_Mail_Message_Interface
*/
require_once 'Zend/Mail/Message/Interface.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Message extends Zend_Mail_Part implements Zend_Mail_Message_Interface
{
/**
* flags for this message
* @var array
*/
protected $_flags = array();
/**
* Public constructor
*
* In addition to the parameters of Zend_Mail_Part::__construct() this constructor supports:
* - file filename or file handle of a file with raw message content
* - flags array with flags for message, keys are ignored, use constants defined in Zend_Mail_Storage
*
* @param string $rawMessage full message with or without headers
* @throws Zend_Mail_Exception
*/
public function __construct(array $params)
{
if (isset($params['file'])) {
if (!is_resource($params['file'])) {
$params['raw'] = @file_get_contents($params['file']);
if ($params['raw'] === false) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('could not open file');
}
} else {
$params['raw'] = stream_get_contents($params['file']);
}
}
if (!empty($params['flags'])) {
// set key and value to the same value for easy lookup
$this->_flags = array_merge($this->_flags, array_combine($params['flags'],$params['flags']));
}
parent::__construct($params);
}
/**
* return toplines as found after headers
*
* @return string toplines
*/
public function getTopLines()
{
return $this->_topLines;
}
/**
* check if flag is set
*
* @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage
* @return bool true if set, otherwise false
*/
public function hasFlag($flag)
{
return isset($this->_flags[$flag]);
}
/**
* get all set flags
*
* @return array array with flags, key and value are the same for easy lookup
*/
public function getFlags()
{
return $this->_flags;
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: File.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Mail_Part
*/
require_once 'Zend/Mail/Part/File.php';
/**
* Zend_Mail_Message_Interface
*/
require_once 'Zend/Mail/Message/Interface.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Message_File extends Zend_Mail_Part_File implements Zend_Mail_Message_Interface
{
/**
* flags for this message
* @var array
*/
protected $_flags = array();
/**
* Public constructor
*
* In addition to the parameters of Zend_Mail_Part::__construct() this constructor supports:
* - flags array with flags for message, keys are ignored, use constants defined in Zend_Mail_Storage
*
* @param string $rawMessage full message with or without headers
* @throws Zend_Mail_Exception
*/
public function __construct(array $params)
{
if (!empty($params['flags'])) {
// set key and value to the same value for easy lookup
$this->_flags = array_combine($params['flags'], $params['flags']);
}
parent::__construct($params);
}
/**
* return toplines as found after headers
*
* @return string toplines
*/
public function getTopLines()
{
return $this->_topLines;
}
/**
* check if flag is set
*
* @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage
* @return bool true if set, otherwise false
*/
public function hasFlag($flag)
{
return isset($this->_flags[$flag]);
}
/**
* get all set flags
*
* @return array array with flags, key and value are the same for easy lookup
*/
public function getFlags()
{
return $this->_flags;
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Mail_Message_Interface
{
/**
* return toplines as found after headers
*
* @return string toplines
*/
public function getTopLines();
/**
* check if flag is set
*
* @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage
* @return bool true if set, otherwise false
*/
public function hasFlag($flag);
/**
* get all set flags
*
* @return array array with flags, key and value are the same for easy lookup
*/
public function getFlags();
}

569
webui/Zend/Mail/Part.php Normal file
View File

@ -0,0 +1,569 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Part.php 24759 2012-05-05 02:58:55Z adamlundrigan $
*/
/**
* @see Zend_Mime_Decode
*/
require_once 'Zend/Mime/Decode.php';
/**
* @see Zend_Mail_Part_Interface
*/
require_once 'Zend/Mail/Part/Interface.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Part implements RecursiveIterator, Zend_Mail_Part_Interface
{
/**
* headers of part as array
* @var null|array
*/
protected $_headers;
/**
* raw part body
* @var null|string
*/
protected $_content;
/**
* toplines as fetched with headers
* @var string
*/
protected $_topLines = '';
/**
* parts of multipart message
* @var array
*/
protected $_parts = array();
/**
* count of parts of a multipart message
* @var null|int
*/
protected $_countParts;
/**
* current position of iterator
* @var int
*/
protected $_iterationPos = 1;
/**
* mail handler, if late fetch is active
* @var null|Zend_Mail_Storage_Abstract
*/
protected $_mail;
/**
* message number for mail handler
* @var int
*/
protected $_messageNum = 0;
/**
* Class to use when creating message parts
* @var string
*/
protected $_partClass;
/**
* Public constructor
*
* Zend_Mail_Part supports different sources for content. The possible params are:
* - handler a instance of Zend_Mail_Storage_Abstract for late fetch
* - id number of message for handler
* - raw raw content with header and body as string
* - headers headers as array (name => value) or string, if a content part is found it's used as toplines
* - noToplines ignore content found after headers in param 'headers'
* - content content as string
*
* @param array $params full message with or without headers
* @throws Zend_Mail_Exception
*/
public function __construct(array $params)
{
if (isset($params['handler'])) {
if (!$params['handler'] instanceof Zend_Mail_Storage_Abstract) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('handler is not a valid mail handler');
}
if (!isset($params['id'])) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('need a message id with a handler');
}
$this->_mail = $params['handler'];
$this->_messageNum = $params['id'];
}
if (isset($params['partclass'])) {
$this->setPartClass($params['partclass']);
}
if (isset($params['raw'])) {
Zend_Mime_Decode::splitMessage($params['raw'], $this->_headers, $this->_content);
} else if (isset($params['headers'])) {
if (is_array($params['headers'])) {
$this->_headers = $params['headers'];
} else {
if (!empty($params['noToplines'])) {
Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $null);
} else {
Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $this->_topLines);
}
}
if (isset($params['content'])) {
$this->_content = $params['content'];
}
}
}
/**
* Set name pf class used to encapsulate message parts
* @param string $class
* @return Zend_Mail_Part
*/
public function setPartClass($class)
{
if ( !class_exists($class) ) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception("Class '{$class}' does not exist");
}
if ( !is_subclass_of($class, 'Zend_Mail_Part_Interface') ) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception("Class '{$class}' must implement Zend_Mail_Part_Interface");
}
$this->_partClass = $class;
return $this;
}
/**
* Retrieve the class name used to encapsulate message parts
* @return string
*/
public function getPartClass()
{
if ( !$this->_partClass ) {
$this->_partClass = __CLASS__;
}
return $this->_partClass;
}
/**
* Check if part is a multipart message
*
* @return bool if part is multipart
*/
public function isMultipart()
{
try {
return stripos($this->contentType, 'multipart/') === 0;
} catch(Zend_Mail_Exception $e) {
return false;
}
}
/**
* Body of part
*
* If part is multipart the raw content of this part with all sub parts is returned
*
* @return string body
* @throws Zend_Mail_Exception
*/
public function getContent()
{
if ($this->_content !== null) {
return $this->_content;
}
if ($this->_mail) {
return $this->_mail->getRawContent($this->_messageNum);
} else {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('no content');
}
}
/**
* Return size of part
*
* Quite simple implemented currently (not decoding). Handle with care.
*
* @return int size
*/
public function getSize() {
return strlen($this->getContent());
}
/**
* Cache content and split in parts if multipart
*
* @return null
* @throws Zend_Mail_Exception
*/
protected function _cacheContent()
{
// caching content if we can't fetch parts
if ($this->_content === null && $this->_mail) {
$this->_content = $this->_mail->getRawContent($this->_messageNum);
}
if (!$this->isMultipart()) {
return;
}
// split content in parts
$boundary = $this->getHeaderField('content-type', 'boundary');
if (!$boundary) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('no boundary found in content type to split message');
}
$parts = Zend_Mime_Decode::splitMessageStruct($this->_content, $boundary);
if ($parts === null) {
return;
}
$partClass = $this->getPartClass();
$counter = 1;
foreach ($parts as $part) {
$this->_parts[$counter++] = new $partClass(array('headers' => $part['header'], 'content' => $part['body']));
}
}
/**
* Get part of multipart message
*
* @param int $num number of part starting with 1 for first part
* @return Zend_Mail_Part wanted part
* @throws Zend_Mail_Exception
*/
public function getPart($num)
{
if (isset($this->_parts[$num])) {
return $this->_parts[$num];
}
if (!$this->_mail && $this->_content === null) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('part not found');
}
if ($this->_mail && $this->_mail->hasFetchPart) {
// TODO: fetch part
// return
}
$this->_cacheContent();
if (!isset($this->_parts[$num])) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('part not found');
}
return $this->_parts[$num];
}
/**
* Count parts of a multipart part
*
* @return int number of sub-parts
*/
public function countParts()
{
if ($this->_countParts) {
return $this->_countParts;
}
$this->_countParts = count($this->_parts);
if ($this->_countParts) {
return $this->_countParts;
}
if ($this->_mail && $this->_mail->hasFetchPart) {
// TODO: fetch part
// return
}
$this->_cacheContent();
$this->_countParts = count($this->_parts);
return $this->_countParts;
}
/**
* Get all headers
*
* The returned headers are as saved internally. All names are lowercased. The value is a string or an array
* if a header with the same name occurs more than once.
*
* @return array headers as array(name => value)
*/
public function getHeaders()
{
if ($this->_headers === null) {
if (!$this->_mail) {
$this->_headers = array();
} else {
$part = $this->_mail->getRawHeader($this->_messageNum);
Zend_Mime_Decode::splitMessage($part, $this->_headers, $null);
}
}
return $this->_headers;
}
/**
* Get a header in specificed format
*
* Internally headers that occur more than once are saved as array, all other as string. If $format
* is set to string implode is used to concat the values (with Zend_Mime::LINEEND as delim).
*
* @param string $name name of header, matches case-insensitive, but camel-case is replaced with dashes
* @param string $format change type of return value to 'string' or 'array'
* @return string|array value of header in wanted or internal format
* @throws Zend_Mail_Exception
*/
public function getHeader($name, $format = null)
{
if ($this->_headers === null) {
$this->getHeaders();
}
$lowerName = strtolower($name);
if ($this->headerExists($name) == false) {
$lowerName = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $name));
if($this->headerExists($lowerName) == false) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception("no Header with Name $name or $lowerName found");
}
}
$name = $lowerName;
$header = $this->_headers[$name];
switch ($format) {
case 'string':
if (is_array($header)) {
$header = implode(Zend_Mime::LINEEND, $header);
}
break;
case 'array':
$header = (array)$header;
default:
// do nothing
}
return $header;
}
/**
* Check wheater the Mail part has a specific header.
*
* @param string $name
* @return boolean
*/
public function headerExists($name)
{
$name = strtolower($name);
if(isset($this->_headers[$name])) {
return true;
} else {
return false;
}
}
/**
* Get a specific field from a header like content type or all fields as array
*
* If the header occurs more than once, only the value from the first header
* is returned.
*
* Throws a Zend_Mail_Exception if the requested header does not exist. If
* the specific header field does not exist, returns null.
*
* @param string $name name of header, like in getHeader()
* @param string $wantedPart the wanted part, default is first, if null an array with all parts is returned
* @param string $firstName key name for the first part
* @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
* @throws Zend_Exception, Zend_Mail_Exception
*/
public function getHeaderField($name, $wantedPart = 0, $firstName = 0) {
return Zend_Mime_Decode::splitHeaderField(current($this->getHeader($name, 'array')), $wantedPart, $firstName);
}
/**
* Getter for mail headers - name is matched in lowercase
*
* This getter is short for Zend_Mail_Part::getHeader($name, 'string')
*
* @see Zend_Mail_Part::getHeader()
*
* @param string $name header name
* @return string value of header
* @throws Zend_Mail_Exception
*/
public function __get($name)
{
return $this->getHeader($name, 'string');
}
/**
* Isset magic method proxy to hasHeader
*
* This method is short syntax for Zend_Mail_Part::hasHeader($name);
*
* @see Zend_Mail_Part::hasHeader
*
* @param string
* @return boolean
*/
public function __isset($name)
{
return $this->headerExists($name);
}
/**
* magic method to get content of part
*
* @return string content
*/
public function __toString()
{
return $this->getContent();
}
/**
* implements RecursiveIterator::hasChildren()
*
* @return bool current element has children/is multipart
*/
public function hasChildren()
{
$current = $this->current();
return $current && $current instanceof Zend_Mail_Part && $current->isMultipart();
}
/**
* implements RecursiveIterator::getChildren()
*
* @return Zend_Mail_Part same as self::current()
*/
public function getChildren()
{
return $this->current();
}
/**
* implements Iterator::valid()
*
* @return bool check if there's a current element
*/
public function valid()
{
if ($this->_countParts === null) {
$this->countParts();
}
return $this->_iterationPos && $this->_iterationPos <= $this->_countParts;
}
/**
* implements Iterator::next()
*
* @return null
*/
public function next()
{
++$this->_iterationPos;
}
/**
* implements Iterator::key()
*
* @return string key/number of current part
*/
public function key()
{
return $this->_iterationPos;
}
/**
* implements Iterator::current()
*
* @return Zend_Mail_Part current part
*/
public function current()
{
return $this->getPart($this->_iterationPos);
}
/**
* implements Iterator::rewind()
*
* @return null
*/
public function rewind()
{
$this->countParts();
$this->_iterationPos = 1;
}
}

View File

@ -0,0 +1,198 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: File.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime_Decode
*/
require_once 'Zend/Mime/Decode.php';
/**
* @see Zend_Mail_Part
*/
require_once 'Zend/Mail/Part.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Part_File extends Zend_Mail_Part
{
protected $_contentPos = array();
protected $_partPos = array();
protected $_fh;
/**
* Public constructor
*
* This handler supports the following params:
* - file filename or open file handler with message content (required)
* - startPos start position of message or part in file (default: current position)
* - endPos end position of message or part in file (default: end of file)
*
* @param array $params full message with or without headers
* @throws Zend_Mail_Exception
*/
public function __construct(array $params)
{
if (empty($params['file'])) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('no file given in params');
}
if (!is_resource($params['file'])) {
$this->_fh = fopen($params['file'], 'r');
} else {
$this->_fh = $params['file'];
}
if (!$this->_fh) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('could not open file');
}
if (isset($params['startPos'])) {
fseek($this->_fh, $params['startPos']);
}
$header = '';
$endPos = isset($params['endPos']) ? $params['endPos'] : null;
while (($endPos === null || ftell($this->_fh) < $endPos) && trim($line = fgets($this->_fh))) {
$header .= $line;
}
Zend_Mime_Decode::splitMessage($header, $this->_headers, $null);
$this->_contentPos[0] = ftell($this->_fh);
if ($endPos !== null) {
$this->_contentPos[1] = $endPos;
} else {
fseek($this->_fh, 0, SEEK_END);
$this->_contentPos[1] = ftell($this->_fh);
}
if (!$this->isMultipart()) {
return;
}
$boundary = $this->getHeaderField('content-type', 'boundary');
if (!$boundary) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('no boundary found in content type to split message');
}
$part = array();
$pos = $this->_contentPos[0];
fseek($this->_fh, $pos);
while (!feof($this->_fh) && ($endPos === null || $pos < $endPos)) {
$line = fgets($this->_fh);
if ($line === false) {
if (feof($this->_fh)) {
break;
}
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('error reading file');
}
$lastPos = $pos;
$pos = ftell($this->_fh);
$line = trim($line);
if ($line == '--' . $boundary) {
if ($part) {
// not first part
$part[1] = $lastPos;
$this->_partPos[] = $part;
}
$part = array($pos);
} else if ($line == '--' . $boundary . '--') {
$part[1] = $lastPos;
$this->_partPos[] = $part;
break;
}
}
$this->_countParts = count($this->_partPos);
}
/**
* Body of part
*
* If part is multipart the raw content of this part with all sub parts is returned
*
* @return string body
* @throws Zend_Mail_Exception
*/
public function getContent($stream = null)
{
fseek($this->_fh, $this->_contentPos[0]);
if ($stream !== null) {
return stream_copy_to_stream($this->_fh, $stream, $this->_contentPos[1] - $this->_contentPos[0]);
}
$length = $this->_contentPos[1] - $this->_contentPos[0];
return $length < 1 ? '' : fread($this->_fh, $length);
}
/**
* Return size of part
*
* Quite simple implemented currently (not decoding). Handle with care.
*
* @return int size
*/
public function getSize() {
return $this->_contentPos[1] - $this->_contentPos[0];
}
/**
* Get part of multipart message
*
* @param int $num number of part starting with 1 for first part
* @return Zend_Mail_Part wanted part
* @throws Zend_Mail_Exception
*/
public function getPart($num)
{
--$num;
if (!isset($this->_partPos[$num])) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('part not found');
}
return new self(array('file' => $this->_fh, 'startPos' => $this->_partPos[$num][0],
'endPos' => $this->_partPos[$num][1]));
}
}

View File

@ -0,0 +1,136 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Mail_Part_Interface extends RecursiveIterator
{
/**
* Check if part is a multipart message
*
* @return bool if part is multipart
*/
public function isMultipart();
/**
* Body of part
*
* If part is multipart the raw content of this part with all sub parts is returned
*
* @return string body
* @throws Zend_Mail_Exception
*/
public function getContent();
/**
* Return size of part
*
* @return int size
*/
public function getSize();
/**
* Get part of multipart message
*
* @param int $num number of part starting with 1 for first part
* @return Zend_Mail_Part wanted part
* @throws Zend_Mail_Exception
*/
public function getPart($num);
/**
* Count parts of a multipart part
*
* @return int number of sub-parts
*/
public function countParts();
/**
* Get all headers
*
* The returned headers are as saved internally. All names are lowercased. The value is a string or an array
* if a header with the same name occurs more than once.
*
* @return array headers as array(name => value)
*/
public function getHeaders();
/**
* Get a header in specificed format
*
* Internally headers that occur more than once are saved as array, all other as string. If $format
* is set to string implode is used to concat the values (with Zend_Mime::LINEEND as delim).
*
* @param string $name name of header, matches case-insensitive, but camel-case is replaced with dashes
* @param string $format change type of return value to 'string' or 'array'
* @return string|array value of header in wanted or internal format
* @throws Zend_Mail_Exception
*/
public function getHeader($name, $format = null);
/**
* Get a specific field from a header like content type or all fields as array
*
* If the header occurs more than once, only the value from the first header
* is returned.
*
* Throws a Zend_Mail_Exception if the requested header does not exist. If
* the specific header field does not exist, returns null.
*
* @param string $name name of header, like in getHeader()
* @param string $wantedPart the wanted part, default is first, if null an array with all parts is returned
* @param string $firstName key name for the first part
* @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
* @throws Zend_Exception, Zend_Mail_Exception
*/
public function getHeaderField($name, $wantedPart = 0, $firstName = 0);
/**
* Getter for mail headers - name is matched in lowercase
*
* This getter is short for Zend_Mail_Part::getHeader($name, 'string')
*
* @see Zend_Mail_Part::getHeader()
*
* @param string $name header name
* @return string value of header
* @throws Zend_Mail_Exception
*/
public function __get($name);
/**
* magic method to get content of part
*
* @return string content
*/
public function __toString();
}

View File

@ -0,0 +1,447 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Validate
*/
require_once 'Zend/Validate.php';
/**
* @see Zend_Validate_Hostname
*/
require_once 'Zend/Validate/Hostname.php';
/**
* Zend_Mail_Protocol_Abstract
*
* Provides low-level methods for concrete adapters to communicate with a remote mail server and track requests and responses.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 24593 2012-01-05 20:35:02Z matthew $
* @todo Implement proxy settings
*/
abstract class Zend_Mail_Protocol_Abstract
{
/**
* Mail default EOL string
*/
const EOL = "\r\n";
/**
* Default timeout in seconds for initiating session
*/
const TIMEOUT_CONNECTION = 30;
/**
* Maximum of the transaction log
* @var integer
*/
protected $_maximumLog = 64;
/**
* Hostname or IP address of remote server
* @var string
*/
protected $_host;
/**
* Port number of connection
* @var integer
*/
protected $_port;
/**
* Instance of Zend_Validate to check hostnames
* @var Zend_Validate
*/
protected $_validHost;
/**
* Socket connection resource
* @var resource
*/
protected $_socket;
/**
* Last request sent to server
* @var string
*/
protected $_request;
/**
* Array of server responses to last request
* @var array
*/
protected $_response;
/**
* String template for parsing server responses using sscanf (default: 3 digit code and response string)
* @var resource
* @deprecated Since 1.10.3
*/
protected $_template = '%d%s';
/**
* Log of mail requests and server responses for a session
* @var array
*/
private $_log = array();
/**
* Constructor.
*
* @param string $host OPTIONAL Hostname of remote connection (default: 127.0.0.1)
* @param integer $port OPTIONAL Port number (default: null)
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function __construct($host = '127.0.0.1', $port = null)
{
$this->_validHost = new Zend_Validate();
$this->_validHost->addValidator(new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL));
if (!$this->_validHost->isValid($host)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages()));
}
$this->_host = $host;
$this->_port = $port;
}
/**
* Class destructor to cleanup open resources
*
* @return void
*/
public function __destruct()
{
$this->_disconnect();
}
/**
* Set the maximum log size
*
* @param integer $maximumLog Maximum log size
* @return void
*/
public function setMaximumLog($maximumLog)
{
$this->_maximumLog = (int) $maximumLog;
}
/**
* Get the maximum log size
*
* @return int the maximum log size
*/
public function getMaximumLog()
{
return $this->_maximumLog;
}
/**
* Create a connection to the remote host
*
* Concrete adapters for this class will implement their own unique connect scripts, using the _connect() method to create the socket resource.
*/
abstract public function connect();
/**
* Retrieve the last client request
*
* @return string
*/
public function getRequest()
{
return $this->_request;
}
/**
* Retrieve the last server response
*
* @return array
*/
public function getResponse()
{
return $this->_response;
}
/**
* Retrieve the transaction log
*
* @return string
*/
public function getLog()
{
return implode('', $this->_log);
}
/**
* Reset the transaction log
*
* @return void
*/
public function resetLog()
{
$this->_log = array();
}
/**
* Add the transaction log
*
* @param string new transaction
* @return void
*/
protected function _addLog($value)
{
if ($this->_maximumLog >= 0 && count($this->_log) >= $this->_maximumLog) {
array_shift($this->_log);
}
$this->_log[] = $value;
}
/**
* Connect to the server using the supplied transport and target
*
* An example $remote string may be 'tcp://mail.example.com:25' or 'ssh://hostname.com:2222'
*
* @param string $remote Remote
* @throws Zend_Mail_Protocol_Exception
* @return boolean
*/
protected function _connect($remote)
{
$errorNum = 0;
$errorStr = '';
// open connection
$this->_socket = @stream_socket_client($remote, $errorNum, $errorStr, self::TIMEOUT_CONNECTION);
if ($this->_socket === false) {
if ($errorNum == 0) {
$errorStr = 'Could not open socket';
}
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception($errorStr);
}
if (($result = $this->_setStreamTimeout(self::TIMEOUT_CONNECTION)) === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Could not set stream timeout');
}
return $result;
}
/**
* Disconnect from remote host and free resource
*
* @return void
*/
protected function _disconnect()
{
if (is_resource($this->_socket)) {
fclose($this->_socket);
}
}
/**
* Send the given request followed by a LINEEND to the server.
*
* @param string $request
* @throws Zend_Mail_Protocol_Exception
* @return integer|boolean Number of bytes written to remote host
*/
protected function _send($request)
{
if (!is_resource($this->_socket)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host);
}
$this->_request = $request;
$result = fwrite($this->_socket, $request . self::EOL);
// Save request to internal log
$this->_addLog($request . self::EOL);
if ($result === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Could not send request to ' . $this->_host);
}
return $result;
}
/**
* Get a line from the stream.
*
* @var integer $timeout Per-request timeout value if applicable
* @throws Zend_Mail_Protocol_Exception
* @return string
*/
protected function _receive($timeout = null)
{
if (!is_resource($this->_socket)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host);
}
// Adapters may wish to supply per-commend timeouts according to appropriate RFC
if ($timeout !== null) {
$this->_setStreamTimeout($timeout);
}
// Retrieve response
$reponse = fgets($this->_socket, 1024);
// Save request to internal log
$this->_addLog($reponse);
// Check meta data to ensure connection is still valid
$info = stream_get_meta_data($this->_socket);
if (!empty($info['timed_out'])) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception($this->_host . ' has timed out');
}
if ($reponse === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Could not read from ' . $this->_host);
}
return $reponse;
}
/**
* Parse server response for successful codes
*
* Read the response from the stream and check for expected return code.
* Throws a Zend_Mail_Protocol_Exception if an unexpected code is returned.
*
* @param string|array $code One or more codes that indicate a successful response
* @throws Zend_Mail_Protocol_Exception
* @return string Last line of response string
*/
protected function _expect($code, $timeout = null)
{
$this->_response = array();
$cmd = '';
$more = '';
$msg = '';
$errMsg = '';
if (!is_array($code)) {
$code = array($code);
}
do {
$this->_response[] = $result = $this->_receive($timeout);
list($cmd, $more, $msg) = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE);
if ($errMsg !== '') {
$errMsg .= ' ' . $msg;
} elseif ($cmd === null || !in_array($cmd, $code)) {
$errMsg = $msg;
}
} while (strpos($more, '-') === 0); // The '-' message prefix indicates an information string instead of a response string.
if ($errMsg !== '') {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception($errMsg, $cmd);
}
return $msg;
}
/**
* Set stream timeout
*
* @param integer $timeout
* @return boolean
*/
protected function _setStreamTimeout($timeout)
{
return stream_set_timeout($this->_socket, $timeout);
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Exception
*/
require_once 'Zend/Mail/Exception.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Exception extends Zend_Mail_Exception
{}

View File

@ -0,0 +1,854 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Imap.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Imap
{
/**
* Default timeout in seconds for initiating session
*/
const TIMEOUT_CONNECTION = 30;
/**
* socket to imap server
* @var resource|null
*/
protected $_socket;
/**
* counter for request tag
* @var int
*/
protected $_tagCount = 0;
/**
* Public constructor
*
* @param string $host hostname or IP address of IMAP server, if given connect() is called
* @param int|null $port port of IMAP server, null for default (143 or 993 for ssl)
* @param bool $ssl use ssl? 'SSL', 'TLS' or false
* @throws Zend_Mail_Protocol_Exception
*/
function __construct($host = '', $port = null, $ssl = false)
{
if ($host) {
$this->connect($host, $port, $ssl);
}
}
/**
* Public destructor
*/
public function __destruct()
{
$this->logout();
}
/**
* Open connection to IMAP server
*
* @param string $host hostname or IP address of IMAP server
* @param int|null $port of IMAP server, default is 143 (993 for ssl)
* @param string|bool $ssl use 'SSL', 'TLS' or false
* @return string welcome message
* @throws Zend_Mail_Protocol_Exception
*/
public function connect($host, $port = null, $ssl = false)
{
if ($ssl == 'SSL') {
$host = 'ssl://' . $host;
}
if ($port === null) {
$port = $ssl === 'SSL' ? 993 : 143;
}
$errno = 0;
$errstr = '';
$this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION);
if (!$this->_socket) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot connect to host; error = ' . $errstr .
' (errno = ' . $errno . ' )');
}
if (!$this->_assumedNextLine('* OK')) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('host doesn\'t allow connection');
}
if ($ssl === 'TLS') {
$result = $this->requestAndResponse('STARTTLS');
$result = $result && stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
if (!$result) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
}
}
}
/**
* get the next line from socket with error checking, but nothing else
*
* @return string next line
* @throws Zend_Mail_Protocol_Exception
*/
protected function _nextLine()
{
$line = @fgets($this->_socket);
if ($line === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot read - connection closed?');
}
return $line;
}
/**
* get next line and assume it starts with $start. some requests give a simple
* feedback so we can quickly check if we can go on.
*
* @param string $start the first bytes we assume to be in the next line
* @return bool line starts with $start
* @throws Zend_Mail_Protocol_Exception
*/
protected function _assumedNextLine($start)
{
$line = $this->_nextLine();
return strpos($line, $start) === 0;
}
/**
* get next line and split the tag. that's the normal case for a response line
*
* @param string $tag tag of line is returned by reference
* @return string next line
* @throws Zend_Mail_Protocol_Exception
*/
protected function _nextTaggedLine(&$tag)
{
$line = $this->_nextLine();
// seperate tag from line
list($tag, $line) = explode(' ', $line, 2);
return $line;
}
/**
* split a given line in tokens. a token is literal of any form or a list
*
* @param string $line line to decode
* @return array tokens, literals are returned as string, lists as array
* @throws Zend_Mail_Protocol_Exception
*/
protected function _decodeLine($line)
{
$tokens = array();
$stack = array();
/*
We start to decode the response here. The unterstood tokens are:
literal
"literal" or also "lit\\er\"al"
{bytes}<NL>literal
(literals*)
All tokens are returned in an array. Literals in braces (the last unterstood
token in the list) are returned as an array of tokens. I.e. the following response:
"foo" baz {3}<NL>bar ("f\\\"oo" bar)
would be returned as:
array('foo', 'baz', 'bar', array('f\\\"oo', 'bar'));
// TODO: add handling of '[' and ']' to parser for easier handling of response text
*/
// replace any trailling <NL> including spaces with a single space
$line = rtrim($line) . ' ';
while (($pos = strpos($line, ' ')) !== false) {
$token = substr($line, 0, $pos);
while ($token[0] == '(') {
array_push($stack, $tokens);
$tokens = array();
$token = substr($token, 1);
}
if ($token[0] == '"') {
if (preg_match('%^\(*"((.|\\\\|\\")*?)" *%', $line, $matches)) {
$tokens[] = $matches[1];
$line = substr($line, strlen($matches[0]));
continue;
}
}
if ($token[0] == '{') {
$endPos = strpos($token, '}');
$chars = substr($token, 1, $endPos - 1);
if (is_numeric($chars)) {
$token = '';
while (strlen($token) < $chars) {
$token .= $this->_nextLine();
}
$line = '';
if (strlen($token) > $chars) {
$line = substr($token, $chars);
$token = substr($token, 0, $chars);
} else {
$line .= $this->_nextLine();
}
$tokens[] = $token;
$line = trim($line) . ' ';
continue;
}
}
if ($stack && $token[strlen($token) - 1] == ')') {
// closing braces are not seperated by spaces, so we need to count them
$braces = strlen($token);
$token = rtrim($token, ')');
// only count braces if more than one
$braces -= strlen($token) + 1;
// only add if token had more than just closing braces
if (rtrim($token) != '') {
$tokens[] = rtrim($token);
}
$token = $tokens;
$tokens = array_pop($stack);
// special handline if more than one closing brace
while ($braces-- > 0) {
$tokens[] = $token;
$token = $tokens;
$tokens = array_pop($stack);
}
}
$tokens[] = $token;
$line = substr($line, $pos + 1);
}
// maybe the server forgot to send some closing braces
while ($stack) {
$child = $tokens;
$tokens = array_pop($stack);
$tokens[] = $child;
}
return $tokens;
}
/**
* read a response "line" (could also be more than one real line if response has {..}<NL>)
* and do a simple decode
*
* @param array|string $tokens decoded tokens are returned by reference, if $dontParse
* is true the unparsed line is returned here
* @param string $wantedTag check for this tag for response code. Default '*' is
* continuation tag.
* @param bool $dontParse if true only the unparsed line is returned $tokens
* @return bool if returned tag matches wanted tag
* @throws Zend_Mail_Protocol_Exception
*/
public function readLine(&$tokens = array(), $wantedTag = '*', $dontParse = false)
{
$line = $this->_nextTaggedLine($tag);
if (!$dontParse) {
$tokens = $this->_decodeLine($line);
} else {
$tokens = $line;
}
// if tag is wanted tag we might be at the end of a multiline response
return $tag == $wantedTag;
}
/**
* read all lines of response until given tag is found (last line of response)
*
* @param string $tag the tag of your request
* @param string|array $filter you can filter the response so you get only the
* given response lines
* @param bool $dontParse if true every line is returned unparsed instead of
* the decoded tokens
* @return null|bool|array tokens if success, false if error, null if bad request
* @throws Zend_Mail_Protocol_Exception
*/
public function readResponse($tag, $dontParse = false)
{
$lines = array();
while (!$this->readLine($tokens, $tag, $dontParse)) {
$lines[] = $tokens;
}
if ($dontParse) {
// last to chars are still needed for response code
$tokens = array(substr($tokens, 0, 2));
}
// last line has response code
if ($tokens[0] == 'OK') {
return $lines ? $lines : true;
} else if ($tokens[0] == 'NO'){
return false;
}
return null;
}
/**
* send a request
*
* @param string $command your request command
* @param array $tokens additional parameters to command, use escapeString() to prepare
* @param string $tag provide a tag otherwise an autogenerated is returned
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function sendRequest($command, $tokens = array(), &$tag = null)
{
if (!$tag) {
++$this->_tagCount;
$tag = 'TAG' . $this->_tagCount;
}
$line = $tag . ' ' . $command;
foreach ($tokens as $token) {
if (is_array($token)) {
if (@fputs($this->_socket, $line . ' ' . $token[0] . "\r\n") === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
}
if (!$this->_assumedNextLine('+ ')) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot send literal string');
}
$line = $token[1];
} else {
$line .= ' ' . $token;
}
}
if (@fputs($this->_socket, $line . "\r\n") === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
}
}
/**
* send a request and get response at once
*
* @param string $command command as in sendRequest()
* @param array $tokens parameters as in sendRequest()
* @param bool $dontParse if true unparsed lines are returned instead of tokens
* @return mixed response as in readResponse()
* @throws Zend_Mail_Protocol_Exception
*/
public function requestAndResponse($command, $tokens = array(), $dontParse = false)
{
$this->sendRequest($command, $tokens, $tag);
$response = $this->readResponse($tag, $dontParse);
return $response;
}
public function pilerListFolders() {
$folders = array();
$a = $this->requestAndResponse("LIST", array('""', '"*"'));
while(list($k, $v) = each($a)) {
if($v[1][0] == '\HasNoChildren') {
array_push($folders, $v[3]);
}
}
return $folders;
}
/**
* escape one or more literals i.e. for sendRequest
*
* @param string|array $string the literal/-s
* @return string|array escape literals, literals with newline ar returned
* as array('{size}', 'string');
*/
public function escapeString($string)
{
if (func_num_args() < 2) {
if (strpos($string, "\n") !== false) {
return array('{' . strlen($string) . '}', $string);
} else {
return '"' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $string) . '"';
}
}
$result = array();
foreach (func_get_args() as $string) {
$result[] = $this->escapeString($string);
}
return $result;
}
/**
* escape a list with literals or lists
*
* @param array $list list with literals or lists as PHP array
* @return string escaped list for imap
*/
public function escapeList($list)
{
$result = array();
foreach ($list as $k => $v) {
if (!is_array($v)) {
// $result[] = $this->escapeString($v);
$result[] = $v;
continue;
}
$result[] = $this->escapeList($v);
}
return '(' . implode(' ', $result) . ')';
}
/**
* Login to IMAP server.
*
* @param string $user username
* @param string $password password
* @return bool success
* @throws Zend_Mail_Protocol_Exception
*/
public function login($user, $password)
{
return $this->requestAndResponse('LOGIN', $this->escapeString($user, $password), true);
}
/**
* logout of imap server
*
* @return bool success
*/
public function logout()
{
$result = false;
if ($this->_socket) {
try {
$result = $this->requestAndResponse('LOGOUT', array(), true);
} catch (Zend_Mail_Protocol_Exception $e) {
// ignoring exception
}
fclose($this->_socket);
$this->_socket = null;
}
return $result;
}
/**
* Get capabilities from IMAP server
*
* @return array list of capabilities
* @throws Zend_Mail_Protocol_Exception
*/
public function capability()
{
$response = $this->requestAndResponse('CAPABILITY');
if (!$response) {
return $response;
}
$capabilities = array();
foreach ($response as $line) {
$capabilities = array_merge($capabilities, $line);
}
return $capabilities;
}
/**
* Examine and select have the same response. The common code for both
* is in this method
*
* @param string $command can be 'EXAMINE' or 'SELECT' and this is used as command
* @param string $box which folder to change to or examine
* @return bool|array false if error, array with returned information
* otherwise (flags, exists, recent, uidvalidity)
* @throws Zend_Mail_Protocol_Exception
*/
public function examineOrSelect($command = 'EXAMINE', $box = 'INBOX')
{
$this->sendRequest($command, array($this->escapeString($box)), $tag);
$result = array();
while (!$this->readLine($tokens, $tag)) {
if ($tokens[0] == 'FLAGS') {
array_shift($tokens);
$result['flags'] = $tokens;
continue;
}
switch ($tokens[1]) {
case 'EXISTS':
case 'RECENT':
$result[strtolower($tokens[1])] = $tokens[0];
break;
case '[UIDVALIDITY':
$result['uidvalidity'] = (int)$tokens[2];
break;
default:
// ignore
}
}
if ($tokens[0] != 'OK') {
return false;
}
return $result;
}
/**
* change folder
*
* @param string $box change to this folder
* @return bool|array see examineOrselect()
* @throws Zend_Mail_Protocol_Exception
*/
public function select($box = 'INBOX')
{
return $this->examineOrSelect('SELECT', $box);
}
/**
* examine folder
*
* @param string $box examine this folder
* @return bool|array see examineOrselect()
* @throws Zend_Mail_Protocol_Exception
*/
public function examine($box = 'INBOX')
{
return $this->examineOrSelect('EXAMINE', $box);
}
/**
* fetch one or more items of one or more messages
*
* @param string|array $items items to fetch from message(s) as string (if only one item)
* or array of strings
* @param int $from message for items or start message if $to !== null
* @param int|null $to if null only one message ($from) is fetched, else it's the
* last message, INF means last message avaible
* @return string|array if only one item of one message is fetched it's returned as string
* if items of one message are fetched it's returned as (name => value)
* if one items of messages are fetched it's returned as (msgno => value)
* if items of messages are fetchted it's returned as (msgno => (name => value))
* @throws Zend_Mail_Protocol_Exception
*/
public function fetch($items, $from, $to = null)
{
if (is_array($from)) {
$set = implode(',', $from);
} else if ($to === null) {
$set = (int)$from;
} else if ($to === INF) {
$set = (int)$from . ':*';
} else {
$set = (int)$from . ':' . (int)$to;
}
$items = (array)$items;
$itemList = $this->escapeList($items);
$this->sendRequest('FETCH', array($set, $itemList), $tag);
$result = array();
while (!$this->readLine($tokens, $tag)) {
// ignore other responses
if ($tokens[1] != 'FETCH') {
continue;
}
// ignore other messages
if ($to === null && !is_array($from) && $tokens[0] != $from) {
continue;
}
// if we only want one item we return that one directly
if (count($items) == 1) {
if ($tokens[2][0] == $items[0]) {
$data = $tokens[2][1];
} else {
// maybe the server send an other field we didn't wanted
$count = count($tokens[2]);
// we start with 2, because 0 was already checked
for ($i = 2; $i < $count; $i += 2) {
if ($tokens[2][$i] != $items[0]) {
continue;
}
$data = $tokens[2][$i + 1];
break;
}
}
} else {
$data = array();
while (key($tokens[2]) !== null) {
$data[current($tokens[2])] = next($tokens[2]);
next($tokens[2]);
}
}
// if we want only one message we can ignore everything else and just return
if ($to === null && !is_array($from) && $tokens[0] == $from) {
// we still need to read all lines
while (!$this->readLine($tokens, $tag));
return $data;
}
$result[$tokens[0]] = $data;
}
if ($to === null && !is_array($from)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('the single id was not found in response');
}
return $result;
}
/**
* get mailbox list
*
* this method can't be named after the IMAP command 'LIST', as list is a reserved keyword
*
* @param string $reference mailbox reference for list
* @param string $mailbox mailbox name match with wildcards
* @return array mailboxes that matched $mailbox as array(globalName => array('delim' => .., 'flags' => ..))
* @throws Zend_Mail_Protocol_Exception
*/
public function listMailbox($reference = '', $mailbox = '*')
{
$result = array();
$list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
if (!$list || $list === true) {
return $result;
}
foreach ($list as $item) {
if (count($item) != 4 || $item[0] != 'LIST') {
continue;
}
$result[$item[3]] = array('delim' => $item[2], 'flags' => $item[1]);
}
return $result;
}
/**
* set flags
*
* @param array $flags flags to set, add or remove - see $mode
* @param int $from message for items or start message if $to !== null
* @param int|null $to if null only one message ($from) is fetched, else it's the
* last message, INF means last message avaible
* @param string|null $mode '+' to add flags, '-' to remove flags, everything else sets the flags as given
* @param bool $silent if false the return values are the new flags for the wanted messages
* @return bool|array new flags if $silent is false, else true or false depending on success
* @throws Zend_Mail_Protocol_Exception
*/
public function store(array $flags, $from, $to = null, $mode = null, $silent = true)
{
$item = 'FLAGS';
if ($mode == '+' || $mode == '-') {
$item = $mode . $item;
}
if ($silent) {
$item .= '.SILENT';
}
$flags = $this->escapeList($flags);
$set = (int)$from;
if ($to != null) {
$set .= ':' . ($to == INF ? '*' : (int)$to);
}
$result = $this->requestAndResponse('STORE', array($set, $item, $flags), $silent);
if ($silent) {
return $result ? true : false;
}
$tokens = $result;
$result = array();
foreach ($tokens as $token) {
if ($token[1] != 'FETCH' || $token[2][0] != 'FLAGS') {
continue;
}
$result[$token[0]] = $token[2][1];
}
return $result;
}
/**
* append a new message to given folder
*
* @param string $folder name of target folder
* @param string $message full message content
* @param array $flags flags for new message
* @param string $date date for new message
* @return bool success
* @throws Zend_Mail_Protocol_Exception
*/
public function append($folder, $message, $flags = null, $date = null)
{
$tokens = array();
$tokens[] = $this->escapeString($folder);
if ($flags !== null) {
$tokens[] = $this->escapeList($flags);
}
if ($date !== null) {
$tokens[] = $this->escapeString($date);
}
$tokens[] = $this->escapeString($message);
return $this->requestAndResponse('APPEND', $tokens, true);
}
/**
* copy message set from current folder to other folder
*
* @param string $folder destination folder
* @param int|null $to if null only one message ($from) is fetched, else it's the
* last message, INF means last message avaible
* @return bool success
* @throws Zend_Mail_Protocol_Exception
*/
public function copy($folder, $from, $to = null)
{
$set = (int)$from;
if ($to != null) {
$set .= ':' . ($to == INF ? '*' : (int)$to);
}
return $this->requestAndResponse('COPY', array($set, $this->escapeString($folder)), true);
}
/**
* create a new folder (and parent folders if needed)
*
* @param string $folder folder name
* @return bool success
*/
public function create($folder)
{
return $this->requestAndResponse('CREATE', array($this->escapeString($folder)), true);
}
/**
* rename an existing folder
*
* @param string $old old name
* @param string $new new name
* @return bool success
*/
public function rename($old, $new)
{
return $this->requestAndResponse('RENAME', $this->escapeString($old, $new), true);
}
/**
* remove a folder
*
* @param string $folder folder name
* @return bool success
*/
public function delete($folder)
{
return $this->requestAndResponse('DELETE', array($this->escapeString($folder)), true);
}
/**
* permanently remove messages
*
* @return bool success
*/
public function expunge()
{
// TODO: parse response?
return $this->requestAndResponse('EXPUNGE');
}
/**
* send noop
*
* @return bool success
*/
public function noop()
{
// TODO: parse response
return $this->requestAndResponse('NOOP');
}
/**
* do a search request
*
* This method is currently marked as internal as the API might change and is not
* safe if you don't take precautions.
*
* @internal
* @return array message ids
*/
public function search(array $params)
{
$response = $this->requestAndResponse('SEARCH', $params);
if (!$response) {
return $response;
}
foreach ($response as $ids) {
if ($ids[0] == 'SEARCH') {
array_shift($ids);
return $ids;
}
}
return array();
}
}

View File

@ -0,0 +1,472 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Pop3.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Pop3
{
/**
* Default timeout in seconds for initiating session
*/
const TIMEOUT_CONNECTION = 30;
/**
* saves if server supports top
* @var null|bool
*/
public $hasTop = null;
/**
* socket to pop3
* @var null|resource
*/
protected $_socket;
/**
* greeting timestamp for apop
* @var null|string
*/
protected $_timestamp;
/**
* Public constructor
*
* @param string $host hostname or IP address of POP3 server, if given connect() is called
* @param int|null $port port of POP3 server, null for default (110 or 995 for ssl)
* @param bool|string $ssl use ssl? 'SSL', 'TLS' or false
* @throws Zend_Mail_Protocol_Exception
*/
public function __construct($host = '', $port = null, $ssl = false)
{
if ($host) {
$this->connect($host, $port, $ssl);
}
}
/**
* Public destructor
*/
public function __destruct()
{
$this->logout();
}
/**
* Open connection to POP3 server
*
* @param string $host hostname or IP address of POP3 server
* @param int|null $port of POP3 server, default is 110 (995 for ssl)
* @param string|bool $ssl use 'SSL', 'TLS' or false
* @return string welcome message
* @throws Zend_Mail_Protocol_Exception
*/
public function connect($host, $port = null, $ssl = false)
{
if ($ssl == 'SSL') {
$host = 'ssl://' . $host;
}
if ($port === null) {
$port = $ssl == 'SSL' ? 995 : 110;
}
$errno = 0;
$errstr = '';
$this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION);
if (!$this->_socket) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot connect to host; error = ' . $errstr .
' (errno = ' . $errno . ' )');
}
$welcome = $this->readResponse();
strtok($welcome, '<');
$this->_timestamp = strtok('>');
if (!strpos($this->_timestamp, '@')) {
$this->_timestamp = null;
} else {
$this->_timestamp = '<' . $this->_timestamp . '>';
}
if ($ssl === 'TLS') {
$this->request('STLS');
$result = stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
if (!$result) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
}
}
return $welcome;
}
/**
* Send a request
*
* @param string $request your request without newline
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function sendRequest($request)
{
$result = @fputs($this->_socket, $request . "\r\n");
if (!$result) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('send failed - connection closed?');
}
}
/**
* read a response
*
* @param boolean $multiline response has multiple lines and should be read until "<nl>.<nl>"
* @return string response
* @throws Zend_Mail_Protocol_Exception
*/
public function readResponse($multiline = false)
{
$result = @fgets($this->_socket);
if (!is_string($result)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('read failed - connection closed?');
}
$result = trim($result);
if (strpos($result, ' ')) {
list($status, $message) = explode(' ', $result, 2);
} else {
$status = $result;
$message = '';
}
if ($status != '+OK') {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('last request failed');
}
if ($multiline) {
$message = '';
$line = fgets($this->_socket);
while ($line && rtrim($line, "\r\n") != '.') {
if ($line[0] == '.') {
$line = substr($line, 1);
}
$message .= $line;
$line = fgets($this->_socket);
};
}
return $message;
}
/**
* Send request and get resposne
*
* @see sendRequest(), readResponse()
*
* @param string $request request
* @param bool $multiline multiline response?
* @return string result from readResponse()
* @throws Zend_Mail_Protocol_Exception
*/
public function request($request, $multiline = false)
{
$this->sendRequest($request);
return $this->readResponse($multiline);
}
/**
* End communication with POP3 server (also closes socket)
*
* @return null
*/
public function logout()
{
if (!$this->_socket) {
return;
}
try {
$this->request('QUIT');
} catch (Zend_Mail_Protocol_Exception $e) {
// ignore error - we're closing the socket anyway
}
fclose($this->_socket);
$this->_socket = null;
}
/**
* Get capabilities from POP3 server
*
* @return array list of capabilities
* @throws Zend_Mail_Protocol_Exception
*/
public function capa()
{
$result = $this->request('CAPA', true);
return explode("\n", $result);
}
/**
* Login to POP3 server. Can use APOP
*
* @param string $user username
* @param string $password password
* @param bool $try_apop should APOP be tried?
* @return void
* @throws Zend_Mail_Protocol_Exception
*/
public function login($user, $password, $tryApop = true)
{
if ($tryApop && $this->_timestamp) {
try {
$this->request("APOP $user " . md5($this->_timestamp . $password));
return;
} catch (Zend_Mail_Protocol_Exception $e) {
// ignore
}
}
$result = $this->request("USER $user");
$result = $this->request("PASS $password");
}
/**
* Make STAT call for message count and size sum
*
* @param int $messages out parameter with count of messages
* @param int $octets out parameter with size in octects of messages
* @return void
* @throws Zend_Mail_Protocol_Exception
*/
public function status(&$messages, &$octets)
{
$messages = 0;
$octets = 0;
$result = $this->request('STAT');
list($messages, $octets) = explode(' ', $result);
}
/**
* Make LIST call for size of message(s)
*
* @param int|null $msgno number of message, null for all
* @return int|array size of given message or list with array(num => size)
* @throws Zend_Mail_Protocol_Exception
*/
public function getList($msgno = null)
{
if ($msgno !== null) {
$result = $this->request("LIST $msgno");
list(, $result) = explode(' ', $result);
return (int)$result;
}
$result = $this->request('LIST', true);
$messages = array();
$line = strtok($result, "\n");
while ($line) {
list($no, $size) = explode(' ', trim($line));
$messages[(int)$no] = (int)$size;
$line = strtok("\n");
}
return $messages;
}
/**
* Make UIDL call for getting a uniqueid
*
* @param int|null $msgno number of message, null for all
* @return string|array uniqueid of message or list with array(num => uniqueid)
* @throws Zend_Mail_Protocol_Exception
*/
public function uniqueid($msgno = null)
{
if ($msgno !== null) {
$result = $this->request("UIDL $msgno");
list(, $result) = explode(' ', $result);
return $result;
}
$result = $this->request('UIDL', true);
$result = explode("\n", $result);
$messages = array();
foreach ($result as $line) {
if (!$line) {
continue;
}
list($no, $id) = explode(' ', trim($line), 2);
$messages[(int)$no] = $id;
}
return $messages;
}
/**
* Make TOP call for getting headers and maybe some body lines
* This method also sets hasTop - before it it's not known if top is supported
*
* The fallback makes normale RETR call, which retrieves the whole message. Additional
* lines are not removed.
*
* @param int $msgno number of message
* @param int $lines number of wanted body lines (empty line is inserted after header lines)
* @param bool $fallback fallback with full retrieve if top is not supported
* @return string message headers with wanted body lines
* @throws Zend_Mail_Protocol_Exception
*/
public function top($msgno, $lines = 0, $fallback = false)
{
if ($this->hasTop === false) {
if ($fallback) {
return $this->retrieve($msgno);
} else {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('top not supported and no fallback wanted');
}
}
$this->hasTop = true;
$lines = (!$lines || $lines < 1) ? 0 : (int)$lines;
try {
$result = $this->request("TOP $msgno $lines", true);
} catch (Zend_Mail_Protocol_Exception $e) {
$this->hasTop = false;
if ($fallback) {
$result = $this->retrieve($msgno);
} else {
throw $e;
}
}
return $result;
}
/**
* Make a RETR call for retrieving a full message with headers and body
*
* @deprecated since 1.1.0; this method has a typo - please use retrieve()
* @param int $msgno message number
* @return string message
* @throws Zend_Mail_Protocol_Exception
*/
public function retrive($msgno)
{
return $this->retrieve($msgno);
}
/**
* Make a RETR call for retrieving a full message with headers and body
*
* @param int $msgno message number
* @return string message
* @throws Zend_Mail_Protocol_Exception
*/
public function retrieve($msgno)
{
$result = $this->request("RETR $msgno", true);
return $result;
}
/**
* Make a NOOP call, maybe needed for keeping the server happy
*
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function noop()
{
$this->request('NOOP');
}
/**
* Make a DELE count to remove a message
*
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function delete($msgno)
{
$this->request("DELE $msgno");
}
/**
* Make RSET call, which rollbacks delete requests
*
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function undelete()
{
$this->request('RSET');
}
}

View File

@ -0,0 +1,443 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Smtp.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* @see Zend_Mail_Protocol_Abstract
*/
require_once 'Zend/Mail/Protocol/Abstract.php';
/**
* Smtp implementation of Zend_Mail_Protocol_Abstract
*
* Minimum implementation according to RFC2821: EHLO, MAIL FROM, RCPT TO, DATA, RSET, NOOP, QUIT
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Smtp extends Zend_Mail_Protocol_Abstract
{
/**
* The transport method for the socket
*
* @var string
*/
protected $_transport = 'tcp';
/**
* Indicates that a session is requested to be secure
*
* @var string
*/
protected $_secure;
/**
* Indicates an smtp session has been started by the HELO command
*
* @var boolean
*/
protected $_sess = false;
/**
* Indicates the HELO command has been issues
*
* @var unknown_type
*/
protected $_helo = false;
/**
* Indicates an smtp AUTH has been issued and authenticated
*
* @var unknown_type
*/
protected $_auth = false;
/**
* Indicates a MAIL command has been issued
*
* @var unknown_type
*/
protected $_mail = false;
/**
* Indicates one or more RCTP commands have been issued
*
* @var unknown_type
*/
protected $_rcpt = false;
/**
* Indicates that DATA has been issued and sent
*
* @var unknown_type
*/
protected $_data = null;
/**
* Constructor.
*
* @param string $host
* @param integer $port
* @param array $config
* @return void
* @throws Zend_Mail_Protocol_Exception
*/
public function __construct($host = '127.0.0.1', $port = null, array $config = array())
{
if (isset($config['ssl'])) {
switch (strtolower($config['ssl'])) {
case 'tls':
$this->_secure = 'tls';
break;
case 'ssl':
$this->_transport = 'ssl';
$this->_secure = 'ssl';
if ($port == null) {
$port = 465;
}
break;
default:
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception($config['ssl'] . ' is unsupported SSL type');
break;
}
}
// If no port has been specified then check the master PHP ini file. Defaults to 25 if the ini setting is null.
if ($port == null) {
if (($port = ini_get('smtp_port')) == '') {
$port = 25;
}
}
parent::__construct($host, $port);
}
/**
* Connect to the server with the parameters given in the constructor.
*
* @return boolean
*/
public function connect()
{
return $this->_connect($this->_transport . '://' . $this->_host . ':'. $this->_port);
}
/**
* Initiate HELO/EHLO sequence and set flag to indicate valid smtp session
*
* @param string $host The client hostname or IP address (default: 127.0.0.1)
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function helo($host = '127.0.0.1')
{
// Respect RFC 2821 and disallow HELO attempts if session is already initiated.
if ($this->_sess === true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Cannot issue HELO to existing session');
}
// Validate client hostname
if (!$this->_validHost->isValid($host)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages()));
}
// Initiate helo sequence
$this->_expect(220, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
$this->_ehlo($host);
// If a TLS session is required, commence negotiation
if ($this->_secure == 'tls') {
$this->_send('STARTTLS');
$this->_expect(220, 180);
if (!stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Unable to connect via TLS');
}
$this->_ehlo($host);
}
$this->_startSession();
$this->auth();
}
/**
* Send EHLO or HELO depending on capabilities of smtp host
*
* @param string $host The client hostname or IP address (default: 127.0.0.1)
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
protected function _ehlo($host)
{
// Support for older, less-compliant remote servers. Tries multiple attempts of EHLO or HELO.
try {
$this->_send('EHLO ' . $host);
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
} catch (Zend_Mail_Protocol_Exception $e) {
$this->_send('HELO ' . $host);
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
} catch (Zend_Mail_Protocol_Exception $e) {
throw $e;
}
}
/**
* Issues MAIL command
*
* @param string $from Sender mailbox
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function mail($from)
{
if ($this->_sess !== true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('A valid session has not been started');
}
$this->_send('MAIL FROM:<' . $from . '>');
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
// Set mail to true, clear recipients and any existing data flags as per 4.1.1.2 of RFC 2821
$this->_mail = true;
$this->_rcpt = false;
$this->_data = false;
}
/**
* Issues RCPT command
*
* @param string $to Receiver(s) mailbox
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function rcpt($to)
{
if ($this->_mail !== true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('No sender reverse path has been supplied');
}
// Set rcpt to true, as per 4.1.1.3 of RFC 2821
$this->_send('RCPT TO:<' . $to . '>');
$this->_expect(array(250, 251), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
$this->_rcpt = true;
}
/**
* Issues DATA command
*
* @param string $data
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function data($data)
{
// Ensure recipients have been set
if ($this->_rcpt !== true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('No recipient forward path has been supplied');
}
$this->_send('DATA');
$this->_expect(354, 120); // Timeout set for 2 minutes as per RFC 2821 4.5.3.2
foreach (explode(Zend_Mime::LINEEND, $data) as $line) {
if (strpos($line, '.') === 0) {
// Escape lines prefixed with a '.'
$line = '.' . $line;
}
$this->_send($line);
}
$this->_send('.');
$this->_expect(250, 600); // Timeout set for 10 minutes as per RFC 2821 4.5.3.2
$this->_data = true;
}
/**
* Issues the RSET command and validates answer
*
* Can be used to restore a clean smtp communication state when a transaction has been cancelled or commencing a new transaction.
*
* @return void
*/
public function rset()
{
$this->_send('RSET');
// MS ESMTP doesn't follow RFC, see [ZF-1377]
$this->_expect(array(250, 220));
$this->_mail = false;
$this->_rcpt = false;
$this->_data = false;
}
/**
* Issues the NOOP command and validates answer
*
* Not used by Zend_Mail, could be used to keep a connection alive or check if it is still open.
*
* @return void
*/
public function noop()
{
$this->_send('NOOP');
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
}
/**
* Issues the VRFY command and validates answer
*
* Not used by Zend_Mail.
*
* @param string $user User Name or eMail to verify
* @return void
*/
public function vrfy($user)
{
$this->_send('VRFY ' . $user);
$this->_expect(array(250, 251, 252), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
}
/**
* Issues the QUIT command and clears the current session
*
* @return void
*/
public function quit()
{
if ($this->_sess) {
$this->_send('QUIT');
$this->_expect(221, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
$this->_stopSession();
}
}
/**
* Default authentication method
*
* This default method is implemented by AUTH adapters to properly authenticate to a remote host.
*
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function auth()
{
if ($this->_auth === true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Already authenticated for this session');
}
}
/**
* Closes connection
*
* @return void
*/
public function disconnect()
{
$this->_disconnect();
}
/**
* Start mail session
*
* @return void
*/
protected function _startSession()
{
$this->_sess = true;
}
/**
* Stop mail session
*
* @return void
*/
protected function _stopSession()
{
$this->_sess = false;
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Crammd5.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Protocol_Smtp
*/
require_once 'Zend/Mail/Protocol/Smtp.php';
/**
* Performs CRAM-MD5 authentication
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Smtp_Auth_Crammd5 extends Zend_Mail_Protocol_Smtp
{
/**
* Constructor.
*
* @param string $host (Default: 127.0.0.1)
* @param int $port (Default: null)
* @param array $config Auth-specific parameters
* @return void
*/
public function __construct($host = '127.0.0.1', $port = null, $config = null)
{
if (is_array($config)) {
if (isset($config['username'])) {
$this->_username = $config['username'];
}
if (isset($config['password'])) {
$this->_password = $config['password'];
}
}
parent::__construct($host, $port, $config);
}
/**
* @todo Perform CRAM-MD5 authentication with supplied credentials
*
* @return void
*/
public function auth()
{
// Ensure AUTH has not already been initiated.
parent::auth();
$this->_send('AUTH CRAM-MD5');
$challenge = $this->_expect(334);
$challenge = base64_decode($challenge);
$digest = $this->_hmacMd5($this->_password, $challenge);
$this->_send(base64_encode($this->_username . ' ' . $digest));
$this->_expect(235);
$this->_auth = true;
}
/**
* Prepare CRAM-MD5 response to server's ticket
*
* @param string $key Challenge key (usually password)
* @param string $data Challenge data
* @param string $block Length of blocks
* @return string
*/
protected function _hmacMd5($key, $data, $block = 64)
{
if (strlen($key) > 64) {
$key = pack('H32', md5($key));
} elseif (strlen($key) < 64) {
$key = str_pad($key, $block, "\0");
}
$k_ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64);
$k_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64);
$inner = pack('H32', md5($k_ipad . $data));
$digest = md5($k_opad . $inner);
return $digest;
}
}

View File

@ -0,0 +1,98 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Login.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Protocol_Smtp
*/
require_once 'Zend/Mail/Protocol/Smtp.php';
/**
* Performs LOGIN authentication
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Smtp_Auth_Login extends Zend_Mail_Protocol_Smtp
{
/**
* LOGIN username
*
* @var string
*/
protected $_username;
/**
* LOGIN password
*
* @var string
*/
protected $_password;
/**
* Constructor.
*
* @param string $host (Default: 127.0.0.1)
* @param int $port (Default: null)
* @param array $config Auth-specific parameters
* @return void
*/
public function __construct($host = '127.0.0.1', $port = null, $config = null)
{
if (is_array($config)) {
if (isset($config['username'])) {
$this->_username = $config['username'];
}
if (isset($config['password'])) {
$this->_password = $config['password'];
}
}
parent::__construct($host, $port, $config);
}
/**
* Perform LOGIN authentication with supplied credentials
*
* @return void
*/
public function auth()
{
// Ensure AUTH has not already been initiated.
parent::auth();
$this->_send('AUTH LOGIN');
$this->_expect(334);
$this->_send(base64_encode($this->_username));
$this->_expect(334);
$this->_send(base64_encode($this->_password));
$this->_expect(235);
$this->_auth = true;
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Plain.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Protocol_Smtp
*/
require_once 'Zend/Mail/Protocol/Smtp.php';
/**
* Performs PLAIN authentication
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Smtp_Auth_Plain extends Zend_Mail_Protocol_Smtp
{
/**
* PLAIN username
*
* @var string
*/
protected $_username;
/**
* PLAIN password
*
* @var string
*/
protected $_password;
/**
* Constructor.
*
* @param string $host (Default: 127.0.0.1)
* @param int $port (Default: null)
* @param array $config Auth-specific parameters
* @return void
*/
public function __construct($host = '127.0.0.1', $port = null, $config = null)
{
if (is_array($config)) {
if (isset($config['username'])) {
$this->_username = $config['username'];
}
if (isset($config['password'])) {
$this->_password = $config['password'];
}
}
parent::__construct($host, $port, $config);
}
/**
* Perform PLAIN authentication with supplied credentials
*
* @return void
*/
public function auth()
{
// Ensure AUTH has not already been initiated.
parent::auth();
$this->_send('AUTH PLAIN');
$this->_expect(334);
$this->_send(base64_encode("\0" . $this->_username . "\0" . $this->_password));
$this->_expect(235);
$this->_auth = true;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Storage.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage
{
// maildir and IMAP flags, using IMAP names, where possible to be able to distinguish between IMAP
// system flags and other flags
const FLAG_PASSED = 'Passed';
const FLAG_SEEN = '\Seen';
const FLAG_ANSWERED = '\Answered';
const FLAG_FLAGGED = '\Flagged';
const FLAG_DELETED = '\Deleted';
const FLAG_DRAFT = '\Draft';
const FLAG_RECENT = '\Recent';
}

View File

@ -0,0 +1,368 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Mail_Storage_Abstract implements Countable, ArrayAccess, SeekableIterator
{
/**
* class capabilities with default values
* @var array
*/
protected $_has = array('uniqueid' => true,
'delete' => false,
'create' => false,
'top' => false,
'fetchPart' => true,
'flags' => false);
/**
* current iteration position
* @var int
*/
protected $_iterationPos = 0;
/**
* maximum iteration position (= message count)
* @var null|int
*/
protected $_iterationMax = null;
/**
* used message class, change it in an extened class to extend the returned message class
* @var string
*/
protected $_messageClass = 'Zend_Mail_Message';
/**
* Getter for has-properties. The standard has properties
* are: hasFolder, hasUniqueid, hasDelete, hasCreate, hasTop
*
* The valid values for the has-properties are:
* - true if a feature is supported
* - false if a feature is not supported
* - null is it's not yet known or it can't be know if a feature is supported
*
* @param string $var property name
* @return bool supported or not
* @throws Zend_Mail_Storage_Exception
*/
public function __get($var)
{
if (strpos($var, 'has') === 0) {
$var = strtolower(substr($var, 3));
return isset($this->_has[$var]) ? $this->_has[$var] : null;
}
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception($var . ' not found');
}
/**
* Get a full list of features supported by the specific mail lib and the server
*
* @return array list of features as array(featurename => true|false[|null])
*/
public function getCapabilities()
{
return $this->_has;
}
/**
* Count messages messages in current box/folder
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
*/
abstract public function countMessages();
/**
* Get a list of messages with number and size
*
* @param int $id number of message
* @return int|array size of given message of list with all messages as array(num => size)
*/
abstract public function getSize($id = 0);
/**
* Get a message with headers and body
*
* @param int $id number of message
* @return Zend_Mail_Message
*/
abstract public function getMessage($id);
abstract public function getFullMessage($id);
/**
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
*/
abstract public function getRawHeader($id, $part = null, $topLines = 0);
/**
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
*/
abstract public function getRawContent($id, $part = null);
/**
* Create instance with parameters
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
abstract public function __construct($params);
/**
* Destructor calls close() and therefore closes the resource.
*/
public function __destruct()
{
$this->close();
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return null
*/
abstract public function close();
/**
* Keep the resource alive.
*
* @return null
*/
abstract public function noop();
/**
* delete a message from current box/folder
*
* @return null
*/
abstract public function removeMessage($id);
/**
* get unique id for one or all messages
*
* if storage does not support unique ids it's the same as the message number
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
abstract public function getUniqueId($id = null);
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
abstract public function getNumberByUniqueId($id);
// interface implementations follows
/**
* Countable::count()
*
* @return int
*/
public function count()
{
return $this->countMessages();
}
/**
* ArrayAccess::offsetExists()
*
* @param int $id
* @return boolean
*/
public function offsetExists($id)
{
try {
if ($this->getMessage($id)) {
return true;
}
} catch(Zend_Mail_Storage_Exception $e) {}
return false;
}
/**
* ArrayAccess::offsetGet()
*
* @param int $id
* @return Zend_Mail_Message message object
*/
public function offsetGet($id)
{
return $this->getMessage($id);
}
/**
* ArrayAccess::offsetSet()
*
* @param id $id
* @param mixed $value
* @throws Zend_Mail_Storage_Exception
* @return void
*/
public function offsetSet($id, $value)
{
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot write mail messages via array access');
}
/**
* ArrayAccess::offsetUnset()
*
* @param int $id
* @return boolean success
*/
public function offsetUnset($id)
{
return $this->removeMessage($id);
}
/**
* Iterator::rewind()
*
* Rewind always gets the new count from the storage. Thus if you use
* the interfaces and your scripts take long you should use reset()
* from time to time.
*
* @return void
*/
public function rewind()
{
$this->_iterationMax = $this->countMessages();
$this->_iterationPos = 1;
}
/**
* Iterator::current()
*
* @return Zend_Mail_Message current message
*/
public function current()
{
return $this->getMessage($this->_iterationPos);
}
/**
* Iterator::key()
*
* @return int id of current position
*/
public function key()
{
return $this->_iterationPos;
}
/**
* Iterator::next()
*
* @return void
*/
public function next()
{
++$this->_iterationPos;
}
/**
* Iterator::valid()
*
* @return boolean
*/
public function valid()
{
if ($this->_iterationMax === null) {
$this->_iterationMax = $this->countMessages();
}
return $this->_iterationPos && $this->_iterationPos <= $this->_iterationMax;
}
/**
* SeekableIterator::seek()
*
* @param int $pos
* @return void
* @throws OutOfBoundsException
*/
public function seek($pos)
{
if ($this->_iterationMax === null) {
$this->_iterationMax = $this->countMessages();
}
if ($pos > $this->_iterationMax) {
throw new OutOfBoundsException('this position does not exist');
}
$this->_iterationPos = $pos;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Exception extends Zend_Mail_Exception
{}

View File

@ -0,0 +1,236 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Folder.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Folder implements RecursiveIterator
{
/**
* subfolders of folder array(localName => Zend_Mail_Storage_Folder folder)
* @var array
*/
protected $_folders;
/**
* local name (name of folder in parent folder)
* @var string
*/
protected $_localName;
/**
* global name (absolute name of folder)
* @var string
*/
protected $_globalName;
/**
* folder is selectable if folder is able to hold messages, else it's just a parent folder
* @var bool
*/
protected $_selectable = true;
/**
* create a new mail folder instance
*
* @param string $localName name of folder in current subdirectory
* @param string $globalName absolute name of folder
* @param bool $selectable if true folder holds messages, if false it's just a parent for subfolders
* @param array $folders init with given instances of Zend_Mail_Storage_Folder as subfolders
*/
public function __construct($localName, $globalName = '', $selectable = true, array $folders = array())
{
$this->_localName = $localName;
$this->_globalName = $globalName ? $globalName : $localName;
$this->_selectable = $selectable;
$this->_folders = $folders;
}
/**
* implements RecursiveIterator::hasChildren()
*
* @return bool current element has children
*/
public function hasChildren()
{
$current = $this->current();
return $current && $current instanceof Zend_Mail_Storage_Folder && !$current->isLeaf();
}
/**
* implements RecursiveIterator::getChildren()
*
* @return Zend_Mail_Storage_Folder same as self::current()
*/
public function getChildren()
{
return $this->current();
}
/**
* implements Iterator::valid()
*
* @return bool check if there's a current element
*/
public function valid()
{
return key($this->_folders) !== null;
}
/**
* implements Iterator::next()
*
* @return null
*/
public function next()
{
next($this->_folders);
}
/**
* implements Iterator::key()
*
* @return string key/local name of current element
*/
public function key()
{
return key($this->_folders);
}
/**
* implements Iterator::current()
*
* @return Zend_Mail_Storage_Folder current folder
*/
public function current()
{
return current($this->_folders);
}
/**
* implements Iterator::rewind()
*
* @return null
*/
public function rewind()
{
reset($this->_folders);
}
/**
* get subfolder named $name
*
* @param string $name wanted subfolder
* @return Zend_Mail_Storage_Folder folder named $folder
* @throws Zend_Mail_Storage_Exception
*/
public function __get($name)
{
if (!isset($this->_folders[$name])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("no subfolder named $name");
}
return $this->_folders[$name];
}
/**
* add or replace subfolder named $name
*
* @param string $name local name of subfolder
* @param Zend_Mail_Storage_Folder $folder instance for new subfolder
* @return null
*/
public function __set($name, Zend_Mail_Storage_Folder $folder)
{
$this->_folders[$name] = $folder;
}
/**
* remove subfolder named $name
*
* @param string $name local name of subfolder
* @return null
*/
public function __unset($name)
{
unset($this->_folders[$name]);
}
/**
* magic method for easy output of global name
*
* @return string global name of folder
*/
public function __toString()
{
return (string)$this->getGlobalName();
}
/**
* get local name
*
* @return string local name
*/
public function getLocalName()
{
return $this->_localName;
}
/**
* get global name
*
* @return string global name
*/
public function getGlobalName()
{
return $this->_globalName;
}
/**
* is this folder selectable?
*
* @return bool selectable
*/
public function isSelectable()
{
return $this->_selectable;
}
/**
* check if folder has no subfolder
*
* @return bool true if no subfolders
*/
public function isLeaf()
{
return empty($this->_folders);
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Mail_Storage_Folder_Interface
{
/**
* get root folder or given folder
*
* @param string $rootFolder get folder structure for given folder, else root
* @return Zend_Mail_Storage_Folder root or wanted folder
*/
public function getFolders($rootFolder = null);
/**
* select given folder
*
* folder must be selectable!
*
* @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function selectFolder($globalName);
/**
* get Zend_Mail_Storage_Folder instance for current folder
*
* @return Zend_Mail_Storage_Folder instance of current folder
* @throws Zend_Mail_Storage_Exception
*/
public function getCurrentFolder();
}

View File

@ -0,0 +1,265 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Maildir.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Folder
*/
require_once 'Zend/Mail/Storage/Folder.php';
/**
* @see Zend_Mail_Storage_Folder_Interface
*/
require_once 'Zend/Mail/Storage/Folder/Interface.php';
/**
* @see Zend_Mail_Storage_Maildir
*/
require_once 'Zend/Mail/Storage/Maildir.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Folder_Maildir extends Zend_Mail_Storage_Maildir implements Zend_Mail_Storage_Folder_Interface
{
/**
* Zend_Mail_Storage_Folder root folder for folder structure
* @var Zend_Mail_Storage_Folder
*/
protected $_rootFolder;
/**
* rootdir of folder structure
* @var string
*/
protected $_rootdir;
/**
* name of current folder
* @var string
*/
protected $_currentFolder;
/**
* delim char for subfolders
* @var string
*/
protected $_delim;
/**
* Create instance with parameters
* Supported parameters are:
* - dirname rootdir of maildir structure
* - delim delim char for folder structur, default is '.'
* - folder intial selected folder, default is 'INBOX'
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
if (!isset($params->dirname) || !is_dir($params->dirname)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
}
$this->_rootdir = rtrim($params->dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$this->_delim = isset($params->delim) ? $params->delim : '.';
$this->_buildFolderTree();
$this->selectFolder(!empty($params->folder) ? $params->folder : 'INBOX');
$this->_has['top'] = true;
$this->_has['flags'] = true;
}
/**
* find all subfolders and mbox files for folder structure
*
* Result is save in Zend_Mail_Storage_Folder instances with the root in $this->_rootFolder.
* $parentFolder and $parentGlobalName are only used internally for recursion.
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
protected function _buildFolderTree()
{
$this->_rootFolder = new Zend_Mail_Storage_Folder('/', '/', false);
$this->_rootFolder->INBOX = new Zend_Mail_Storage_Folder('INBOX', 'INBOX', true);
$dh = @opendir($this->_rootdir);
if (!$dh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("can't read folders in maildir");
}
$dirs = array();
while (($entry = readdir($dh)) !== false) {
// maildir++ defines folders must start with .
if ($entry[0] != '.' || $entry == '.' || $entry == '..') {
continue;
}
if ($this->_isMaildir($this->_rootdir . $entry)) {
$dirs[] = $entry;
}
}
closedir($dh);
sort($dirs);
$stack = array(null);
$folderStack = array(null);
$parentFolder = $this->_rootFolder;
$parent = '.';
foreach ($dirs as $dir) {
do {
if (strpos($dir, $parent) === 0) {
$local = substr($dir, strlen($parent));
if (strpos($local, $this->_delim) !== false) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('error while reading maildir');
}
array_push($stack, $parent);
$parent = $dir . $this->_delim;
$folder = new Zend_Mail_Storage_Folder($local, substr($dir, 1), true);
$parentFolder->$local = $folder;
array_push($folderStack, $parentFolder);
$parentFolder = $folder;
break;
} else if ($stack) {
$parent = array_pop($stack);
$parentFolder = array_pop($folderStack);
}
} while ($stack);
if (!$stack) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('error while reading maildir');
}
}
}
/**
* get root folder or given folder
*
* @param string $rootFolder get folder structure for given folder, else root
* @return Zend_Mail_Storage_Folder root or wanted folder
* @throws Zend_Mail_Storage_Exception
*/
public function getFolders($rootFolder = null)
{
if (!$rootFolder || $rootFolder == 'INBOX') {
return $this->_rootFolder;
}
// rootdir is same as INBOX in maildir
if (strpos($rootFolder, 'INBOX' . $this->_delim) === 0) {
$rootFolder = substr($rootFolder, 6);
}
$currentFolder = $this->_rootFolder;
$subname = trim($rootFolder, $this->_delim);
while ($currentFolder) {
@list($entry, $subname) = @explode($this->_delim, $subname, 2);
$currentFolder = $currentFolder->$entry;
if (!$subname) {
break;
}
}
if ($currentFolder->getGlobalName() != rtrim($rootFolder, $this->_delim)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("folder $rootFolder not found");
}
return $currentFolder;
}
/**
* select given folder
*
* folder must be selectable!
*
* @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function selectFolder($globalName)
{
$this->_currentFolder = (string)$globalName;
// getting folder from folder tree for validation
$folder = $this->getFolders($this->_currentFolder);
try {
$this->_openMaildir($this->_rootdir . '.' . $folder->getGlobalName());
} catch(Zend_Mail_Storage_Exception $e) {
// check what went wrong
if (!$folder->isSelectable()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("{$this->_currentFolder} is not selectable", 0, $e);
}
// seems like file has vanished; rebuilding folder tree - but it's still an exception
$this->_buildFolderTree($this->_rootdir);
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('seems like the maildir has vanished, I\'ve rebuild the ' .
'folder tree, search for an other folder and try again', 0, $e);
}
}
/**
* get Zend_Mail_Storage_Folder instance for current folder
*
* @return Zend_Mail_Storage_Folder instance of current folder
* @throws Zend_Mail_Storage_Exception
*/
public function getCurrentFolder()
{
return $this->_currentFolder;
}
}

View File

@ -0,0 +1,264 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mbox.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Folder
*/
require_once 'Zend/Mail/Storage/Folder.php';
/**
* @see Zend_Mail_Storage_Folder_Interface
*/
require_once 'Zend/Mail/Storage/Folder/Interface.php';
/**
* @see Zend_Mail_Storage_Mbox
*/
require_once 'Zend/Mail/Storage/Mbox.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Folder_Mbox extends Zend_Mail_Storage_Mbox implements Zend_Mail_Storage_Folder_Interface
{
/**
* Zend_Mail_Storage_Folder root folder for folder structure
* @var Zend_Mail_Storage_Folder
*/
protected $_rootFolder;
/**
* rootdir of folder structure
* @var string
*/
protected $_rootdir;
/**
* name of current folder
* @var string
*/
protected $_currentFolder;
/**
* Create instance with parameters
*
* Disallowed parameters are:
* - filename use Zend_Mail_Storage_Mbox for a single file
* Supported parameters are:
* - dirname rootdir of mbox structure
* - folder intial selected folder, default is 'INBOX'
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
if (isset($params->filename)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('use Zend_Mail_Storage_Mbox for a single file');
}
if (!isset($params->dirname) || !is_dir($params->dirname)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
}
$this->_rootdir = rtrim($params->dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$this->_buildFolderTree($this->_rootdir);
$this->selectFolder(!empty($params->folder) ? $params->folder : 'INBOX');
$this->_has['top'] = true;
$this->_has['uniqueid'] = false;
}
/**
* find all subfolders and mbox files for folder structure
*
* Result is save in Zend_Mail_Storage_Folder instances with the root in $this->_rootFolder.
* $parentFolder and $parentGlobalName are only used internally for recursion.
*
* @param string $currentDir call with root dir, also used for recursion.
* @param Zend_Mail_Storage_Folder|null $parentFolder used for recursion
* @param string $parentGlobalName used for rescursion
* @return null
* @throws Zend_Mail_Storage_Exception
*/
protected function _buildFolderTree($currentDir, $parentFolder = null, $parentGlobalName = '')
{
if (!$parentFolder) {
$this->_rootFolder = new Zend_Mail_Storage_Folder('/', '/', false);
$parentFolder = $this->_rootFolder;
}
$dh = @opendir($currentDir);
if (!$dh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("can't read dir $currentDir");
}
while (($entry = readdir($dh)) !== false) {
// ignore hidden files for mbox
if ($entry[0] == '.') {
continue;
}
$absoluteEntry = $currentDir . $entry;
$globalName = $parentGlobalName . DIRECTORY_SEPARATOR . $entry;
if (is_file($absoluteEntry) && $this->_isMboxFile($absoluteEntry)) {
$parentFolder->$entry = new Zend_Mail_Storage_Folder($entry, $globalName);
continue;
}
if (!is_dir($absoluteEntry) /* || $entry == '.' || $entry == '..' */) {
continue;
}
$folder = new Zend_Mail_Storage_Folder($entry, $globalName, false);
$parentFolder->$entry = $folder;
$this->_buildFolderTree($absoluteEntry . DIRECTORY_SEPARATOR, $folder, $globalName);
}
closedir($dh);
}
/**
* get root folder or given folder
*
* @param string $rootFolder get folder structure for given folder, else root
* @return Zend_Mail_Storage_Folder root or wanted folder
* @throws Zend_Mail_Storage_Exception
*/
public function getFolders($rootFolder = null)
{
if (!$rootFolder) {
return $this->_rootFolder;
}
$currentFolder = $this->_rootFolder;
$subname = trim($rootFolder, DIRECTORY_SEPARATOR);
while ($currentFolder) {
@list($entry, $subname) = @explode(DIRECTORY_SEPARATOR, $subname, 2);
$currentFolder = $currentFolder->$entry;
if (!$subname) {
break;
}
}
if ($currentFolder->getGlobalName() != DIRECTORY_SEPARATOR . trim($rootFolder, DIRECTORY_SEPARATOR)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("folder $rootFolder not found");
}
return $currentFolder;
}
/**
* select given folder
*
* folder must be selectable!
*
* @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function selectFolder($globalName)
{
$this->_currentFolder = (string)$globalName;
// getting folder from folder tree for validation
$folder = $this->getFolders($this->_currentFolder);
try {
$this->_openMboxFile($this->_rootdir . $folder->getGlobalName());
} catch(Zend_Mail_Storage_Exception $e) {
// check what went wrong
if (!$folder->isSelectable()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("{$this->_currentFolder} is not selectable", 0, $e);
}
// seems like file has vanished; rebuilding folder tree - but it's still an exception
$this->_buildFolderTree($this->_rootdir);
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('seems like the mbox file has vanished, I\'ve rebuild the ' .
'folder tree, search for an other folder and try again', 0, $e);
}
}
/**
* get Zend_Mail_Storage_Folder instance for current folder
*
* @return Zend_Mail_Storage_Folder instance of current folder
* @throws Zend_Mail_Storage_Exception
*/
public function getCurrentFolder()
{
return $this->_currentFolder;
}
/**
* magic method for serialize()
*
* with this method you can cache the mbox class
*
* @return array name of variables
*/
public function __sleep()
{
return array_merge(parent::__sleep(), array('_currentFolder', '_rootFolder', '_rootdir'));
}
/**
* magic method for unserialize()
*
* with this method you can cache the mbox class
*
* @return null
*/
public function __wakeup()
{
// if cache is stall selectFolder() rebuilds the tree on error
parent::__wakeup();
}
}

View File

@ -0,0 +1,657 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Imap.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Abstract
*/
require_once 'Zend/Mail/Storage/Abstract.php';
/**
* @see Zend_Mail_Protocol_Imap
*/
require_once 'Zend/Mail/Protocol/Imap.php';
/**
* @see Zend_Mail_Storage_Writable_Interface
*/
require_once 'Zend/Mail/Storage/Writable/Interface.php';
/**
* @see Zend_Mail_Storage_Folder_Interface
*/
require_once 'Zend/Mail/Storage/Folder/Interface.php';
/**
* @see Zend_Mail_Storage_Folder
*/
require_once 'Zend/Mail/Storage/Folder.php';
/**
* @see Zend_Mail_Message
*/
require_once 'Zend/Mail/Message.php';
/**
* @see Zend_Mail_Storage
*/
require_once 'Zend/Mail/Storage.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Imap extends Zend_Mail_Storage_Abstract
implements Zend_Mail_Storage_Folder_Interface, Zend_Mail_Storage_Writable_Interface
{
// TODO: with an internal cache we could optimize this class, or create an extra class with
// such optimizations. Especially the various fetch calls could be combined to one cache call
/**
* protocol handler
* @var null|Zend_Mail_Protocol_Imap
*/
protected $_protocol;
/**
* name of current folder
* @var string
*/
protected $_currentFolder = '';
/**
* imap flags to constants translation
* @var array
*/
protected static $_knownFlags = array('\Passed' => Zend_Mail_Storage::FLAG_PASSED,
'\Answered' => Zend_Mail_Storage::FLAG_ANSWERED,
'\Seen' => Zend_Mail_Storage::FLAG_SEEN,
'\Deleted' => Zend_Mail_Storage::FLAG_DELETED,
'\Draft' => Zend_Mail_Storage::FLAG_DRAFT,
'\Flagged' => Zend_Mail_Storage::FLAG_FLAGGED);
/**
* map flags to search criterias
* @var array
*/
protected static $_searchFlags = array('\Recent' => 'RECENT',
'\Answered' => 'ANSWERED',
'\Seen' => 'SEEN',
'\Deleted' => 'DELETED',
'\Draft' => 'DRAFT',
'\Flagged' => 'FLAGGED');
/**
* Count messages all messages in current box
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function countMessages($flags = null)
{
if (!$this->_currentFolder) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('No selected folder to count');
}
if ($flags === null) {
return count($this->_protocol->search(array('ALL')));
}
$params = array();
foreach ((array)$flags as $flag) {
if (isset(self::$_searchFlags[$flag])) {
$params[] = self::$_searchFlags[$flag];
} else {
$params[] = 'KEYWORD';
$params[] = $this->_protocol->escapeString($flag);
}
}
return count($this->_protocol->search($params));
}
/**
* get a list of messages with number and size
*
* @param int $id number of message
* @return int|array size of given message of list with all messages as array(num => size)
* @throws Zend_Mail_Protocol_Exception
*/
public function getSize($id = 0)
{
if ($id) {
return $this->_protocol->fetch('RFC822.SIZE', $id);
}
return $this->_protocol->fetch('RFC822.SIZE', 1, INF);
}
/**
* Fetch a message
*
* @param int $id number of message
* @return Zend_Mail_Message
* @throws Zend_Mail_Protocol_Exception
*/
public function getMessage($id)
{
$data = $this->_protocol->fetch(array('FLAGS', 'RFC822.HEADER'), $id);
$header = $data['RFC822.HEADER'];
$flags = array();
foreach ($data['FLAGS'] as $flag) {
$flags[] = isset(self::$_knownFlags[$flag]) ? self::$_knownFlags[$flag] : $flag;
}
return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $header, 'flags' => $flags));
}
/*
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawHeader($id, $part = null, $topLines = 0)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
// TODO: toplines
return $this->_protocol->fetch('RFC822.HEADER', $id);
}
public function getFullMessage($id)
{
$data = $this->_protocol->fetch(array('RFC822.HEADER', 'RFC822.TEXT'), $id);
return $data['RFC822.HEADER'] . "\n\n" . $data['RFC822.TEXT'];
}
/*
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawContent($id, $part = null)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
return $this->_protocol->fetch('RFC822.TEXT', $id);
}
public function piler_batch_fetch($from, $to) {
return $this->_protocol->fetch(array('RFC822.HEADER', 'RFC822.TEXT'), $from, $to);
}
/**
* create instance with parameters
* Supported paramters are
* - user username
* - host hostname or ip address of IMAP server [optional, default = 'localhost']
* - password password for user 'username' [optional, default = '']
* - port port for IMAP server [optional, default = 110]
* - ssl 'SSL' or 'TLS' for secure sockets
* - folder select this folder [optional, default = 'INBOX']
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
$this->_has['flags'] = true;
if ($params instanceof Zend_Mail_Protocol_Imap) {
$this->_protocol = $params;
try {
$this->selectFolder('INBOX');
} catch(Zend_Mail_Storage_Exception $e) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot select INBOX, is this a valid transport?', 0, $e);
}
return;
}
if (!isset($params->user)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('need at least user in params');
}
$host = isset($params->host) ? $params->host : 'localhost';
$password = isset($params->password) ? $params->password : '';
$port = isset($params->port) ? $params->port : null;
$ssl = isset($params->ssl) ? $params->ssl : false;
$this->_protocol = new Zend_Mail_Protocol_Imap();
$this->_protocol->connect($host, $port, $ssl);
if (!$this->_protocol->login($params->user, $password)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot login, user or password wrong');
}
$this->selectFolder(isset($params->folder) ? $params->folder : 'INBOX');
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return null
*/
public function close()
{
$this->_currentFolder = '';
$this->_protocol->logout();
}
/**
* Keep the server busy.
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function noop()
{
if (!$this->_protocol->noop()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('could not do nothing');
}
}
/**
* Remove a message from server. If you're doing that from a web enviroment
* you should be careful and use a uniqueid as parameter if possible to
* identify the message.
*
* @param int $id number of message
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeMessage($id)
{
if (!$this->_protocol->store(array(Zend_Mail_Storage::FLAG_DELETED), $id, null, '+')) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot set deleted flag');
}
// TODO: expunge here or at close? we can handle an error here better and are more fail safe
if (!$this->_protocol->expunge()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('message marked as deleted, but could not expunge');
}
}
/**
* get unique id for one or all messages
*
* if storage does not support unique ids it's the same as the message number
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
public function getUniqueId($id = null)
{
if ($id) {
return $this->_protocol->fetch('UID', $id);
}
return $this->_protocol->fetch('UID', 1, INF);
}
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
public function getNumberByUniqueId($id)
{
// TODO: use search to find number directly
$ids = $this->getUniqueId();
foreach ($ids as $k => $v) {
if ($v == $id) {
return $k;
}
}
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('unique id not found');
}
/**
* get root folder or given folder
*
* @param string $rootFolder get folder structure for given folder, else root
* @return Zend_Mail_Storage_Folder root or wanted folder
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function getFolders($rootFolder = null)
{
$folders = $this->_protocol->listMailbox((string)$rootFolder);
if (!$folders) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('folder not found');
}
ksort($folders, SORT_STRING);
$root = new Zend_Mail_Storage_Folder('/', '/', false);
$stack = array(null);
$folderStack = array(null);
$parentFolder = $root;
$parent = '';
foreach ($folders as $globalName => $data) {
do {
if (!$parent || strpos($globalName, $parent) === 0) {
$pos = strrpos($globalName, $data['delim']);
if ($pos === false) {
$localName = $globalName;
} else {
$localName = substr($globalName, $pos + 1);
}
$selectable = !$data['flags'] || !in_array('\\Noselect', $data['flags']);
array_push($stack, $parent);
$parent = $globalName . $data['delim'];
$folder = new Zend_Mail_Storage_Folder($localName, $globalName, $selectable);
$parentFolder->$localName = $folder;
array_push($folderStack, $parentFolder);
$parentFolder = $folder;
break;
} else if ($stack) {
$parent = array_pop($stack);
$parentFolder = array_pop($folderStack);
}
} while ($stack);
if (!$stack) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('error while constructing folder tree');
}
}
return $root;
}
/**
* select given folder
*
* folder must be selectable!
*
* @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
* @return null
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function selectFolder($globalName)
{
$this->_currentFolder = $globalName;
if (!$this->_protocol->select($this->_currentFolder)) {
$this->_currentFolder = '';
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot change folder, maybe it does not exist');
}
}
/**
* get Zend_Mail_Storage_Folder instance for current folder
*
* @return Zend_Mail_Storage_Folder instance of current folder
* @throws Zend_Mail_Storage_Exception
*/
public function getCurrentFolder()
{
return $this->_currentFolder;
}
/**
* create a new folder
*
* This method also creates parent folders if necessary. Some mail storages may restrict, which folder
* may be used as parent or which chars may be used in the folder name
*
* @param string $name global name of folder, local name if $parentFolder is set
* @param string|Zend_Mail_Storage_Folder $parentFolder parent folder for new folder, else root folder is parent
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function createFolder($name, $parentFolder = null)
{
// TODO: we assume / as the hierarchy delim - need to get that from the folder class!
if ($parentFolder instanceof Zend_Mail_Storage_Folder) {
$folder = $parentFolder->getGlobalName() . '/' . $name;
} else if ($parentFolder != null) {
$folder = $parentFolder . '/' . $name;
} else {
$folder = $name;
}
if (!$this->_protocol->create($folder)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot create folder');
}
}
/**
* remove a folder
*
* @param string|Zend_Mail_Storage_Folder $name name or instance of folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeFolder($name)
{
if ($name instanceof Zend_Mail_Storage_Folder) {
$name = $name->getGlobalName();
}
if (!$this->_protocol->delete($name)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot delete folder');
}
}
/**
* rename and/or move folder
*
* The new name has the same restrictions as in createFolder()
*
* @param string|Zend_Mail_Storage_Folder $oldName name or instance of folder
* @param string $newName new global name of folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function renameFolder($oldName, $newName)
{
if ($oldName instanceof Zend_Mail_Storage_Folder) {
$oldName = $oldName->getGlobalName();
}
if (!$this->_protocol->rename($oldName, $newName)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot rename folder');
}
}
/**
* append a new message to mail storage
*
* @param string $message message as string or instance of message class
* @param null|string|Zend_Mail_Storage_Folder $folder folder for new message, else current folder is taken
* @param null|array $flags set flags for new message, else a default set is used
* @throws Zend_Mail_Storage_Exception
*/
// not yet * @param string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class
public function appendMessage($message, $folder = null, $flags = null)
{
if ($folder === null) {
$folder = $this->_currentFolder;
}
if ($flags === null) {
$flags = array(Zend_Mail_Storage::FLAG_SEEN);
}
// TODO: handle class instances for $message
if (!$this->_protocol->append($folder, $message, $flags)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot create message, please check if the folder exists and your flags');
}
}
/**
* copy an existing message
*
* @param int $id number of message
* @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function copyMessage($id, $folder)
{
if (!$this->_protocol->copy($folder, $id)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot copy message, does the folder exist?');
}
}
/**
* move an existing message
*
* NOTE: imap has no native move command, thus it's emulated with copy and delete
*
* @param int $id number of message
* @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function moveMessage($id, $folder) {
$this->copyMessage($id, $folder);
$this->removeMessage($id);
}
/**
* set flags for message
*
* NOTE: this method can't set the recent flag.
*
* @param int $id number of message
* @param array $flags new flags for message
* @throws Zend_Mail_Storage_Exception
*/
public function setFlags($id, $flags)
{
if (!$this->_protocol->store($flags, $id)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot set flags, have you tried to set the recent flag or special chars?');
}
}
}

View File

@ -0,0 +1,475 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Maildir.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Abstract
*/
require_once 'Zend/Mail/Storage/Abstract.php';
/**
* @see Zend_Mail_Message_File
*/
require_once 'Zend/Mail/Message/File.php';
/**
* @see Zend_Mail_Storage
*/
require_once 'Zend/Mail/Storage.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Maildir extends Zend_Mail_Storage_Abstract
{
/**
* used message class, change it in an extened class to extend the returned message class
* @var string
*/
protected $_messageClass = 'Zend_Mail_Message_File';
/**
* data of found message files in maildir dir
* @var array
*/
protected $_files = array();
/**
* known flag chars in filenames
*
* This list has to be in alphabetical order for setFlags()
*
* @var array
*/
protected static $_knownFlags = array('D' => Zend_Mail_Storage::FLAG_DRAFT,
'F' => Zend_Mail_Storage::FLAG_FLAGGED,
'P' => Zend_Mail_Storage::FLAG_PASSED,
'R' => Zend_Mail_Storage::FLAG_ANSWERED,
'S' => Zend_Mail_Storage::FLAG_SEEN,
'T' => Zend_Mail_Storage::FLAG_DELETED);
// TODO: getFlags($id) for fast access if headers are not needed (i.e. just setting flags)?
/**
* Count messages all messages in current box
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
*/
public function countMessages($flags = null)
{
if ($flags === null) {
return count($this->_files);
}
$count = 0;
if (!is_array($flags)) {
foreach ($this->_files as $file) {
if (isset($file['flaglookup'][$flags])) {
++$count;
}
}
return $count;
}
$flags = array_flip($flags);
foreach ($this->_files as $file) {
foreach ($flags as $flag => $v) {
if (!isset($file['flaglookup'][$flag])) {
continue 2;
}
}
++$count;
}
return $count;
}
/**
* Get one or all fields from file structure. Also checks if message is valid
*
* @param int $id message number
* @param string|null $field wanted field
* @return string|array wanted field or all fields as array
* @throws Zend_Mail_Storage_Exception
*/
protected function _getFileData($id, $field = null)
{
if (!isset($this->_files[$id - 1])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('id does not exist');
}
if (!$field) {
return $this->_files[$id - 1];
}
if (!isset($this->_files[$id - 1][$field])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('field does not exist');
}
return $this->_files[$id - 1][$field];
}
/**
* Get a list of messages with number and size
*
* @param int|null $id number of message or null for all messages
* @return int|array size of given message of list with all messages as array(num => size)
* @throws Zend_Mail_Storage_Exception
*/
public function getSize($id = null)
{
if ($id !== null) {
$filedata = $this->_getFileData($id);
return isset($filedata['size']) ? $filedata['size'] : filesize($filedata['filename']);
}
$result = array();
foreach ($this->_files as $num => $data) {
$result[$num + 1] = isset($data['size']) ? $data['size'] : filesize($data['filename']);
}
return $result;
}
/**
* Fetch a message
*
* @param int $id number of message
* @return Zend_Mail_Message_File
* @throws Zend_Mail_Storage_Exception
*/
public function getMessage($id)
{
// TODO that's ugly, would be better to let the message class decide
if (strtolower($this->_messageClass) == 'zend_mail_message_file' || is_subclass_of($this->_messageClass, 'zend_mail_message_file')) {
return new $this->_messageClass(array('file' => $this->_getFileData($id, 'filename'),
'flags' => $this->_getFileData($id, 'flags')));
}
return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $this->getRawHeader($id),
'flags' => $this->_getFileData($id, 'flags')));
}
/*
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
* @throws Zend_Mail_Storage_Exception
*/
public function getRawHeader($id, $part = null, $topLines = 0)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$fh = fopen($this->_getFileData($id, 'filename'), 'r');
$content = '';
while (!feof($fh)) {
$line = fgets($fh);
if (!trim($line)) {
break;
}
$content .= $line;
}
fclose($fh);
return $content;
}
/*
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
* @throws Zend_Mail_Storage_Exception
*/
public function getRawContent($id, $part = null)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$fh = fopen($this->_getFileData($id, 'filename'), 'r');
while (!feof($fh)) {
$line = fgets($fh);
if (!trim($line)) {
break;
}
}
$content = stream_get_contents($fh);
fclose($fh);
return $content;
}
/**
* Create instance with parameters
* Supported parameters are:
* - dirname dirname of mbox file
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
if (!isset($params->dirname) || !is_dir($params->dirname)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
}
if (!$this->_isMaildir($params->dirname)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('invalid maildir given');
}
$this->_has['top'] = true;
$this->_has['flags'] = true;
$this->_openMaildir($params->dirname);
}
/**
* check if a given dir is a valid maildir
*
* @param string $dirname name of dir
* @return bool dir is valid maildir
*/
protected function _isMaildir($dirname)
{
if (file_exists($dirname . '/new') && !is_dir($dirname . '/new')) {
return false;
}
if (file_exists($dirname . '/tmp') && !is_dir($dirname . '/tmp')) {
return false;
}
return is_dir($dirname . '/cur');
}
/**
* open given dir as current maildir
*
* @param string $dirname name of maildir
* @return null
* @throws Zend_Mail_Storage_Exception
*/
protected function _openMaildir($dirname)
{
if ($this->_files) {
$this->close();
}
$dh = @opendir($dirname . '/cur/');
if (!$dh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot open maildir');
}
$this->_getMaildirFiles($dh, $dirname . '/cur/');
closedir($dh);
$dh = @opendir($dirname . '/new/');
if ($dh) {
$this->_getMaildirFiles($dh, $dirname . '/new/', array(Zend_Mail_Storage::FLAG_RECENT));
closedir($dh);
} else if (file_exists($dirname . '/new/')) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot read recent mails in maildir');
}
}
/**
* find all files in opened dir handle and add to maildir files
*
* @param resource $dh dir handle used for search
* @param string $dirname dirname of dir in $dh
* @param array $default_flags default flags for given dir
* @return null
*/
protected function _getMaildirFiles($dh, $dirname, $default_flags = array())
{
while (($entry = readdir($dh)) !== false) {
if ($entry[0] == '.' || !is_file($dirname . $entry)) {
continue;
}
@list($uniq, $info) = explode(':', $entry, 2);
@list(,$size) = explode(',', $uniq, 2);
if ($size && $size[0] == 'S' && $size[1] == '=') {
$size = substr($size, 2);
}
if (!ctype_digit($size)) {
$size = null;
}
@list($version, $flags) = explode(',', $info, 2);
if ($version != 2) {
$flags = '';
}
$named_flags = $default_flags;
$length = strlen($flags);
for ($i = 0; $i < $length; ++$i) {
$flag = $flags[$i];
$named_flags[$flag] = isset(self::$_knownFlags[$flag]) ? self::$_knownFlags[$flag] : $flag;
}
$data = array('uniq' => $uniq,
'flags' => $named_flags,
'flaglookup' => array_flip($named_flags),
'filename' => $dirname . $entry);
if ($size !== null) {
$data['size'] = (int)$size;
}
$this->_files[] = $data;
}
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return void
*/
public function close()
{
$this->_files = array();
}
/**
* Waste some CPU cycles doing nothing.
*
* @return void
*/
public function noop()
{
return true;
}
/**
* stub for not supported message deletion
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeMessage($id)
{
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('maildir is (currently) read-only');
}
/**
* get unique id for one or all messages
*
* if storage does not support unique ids it's the same as the message number
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
public function getUniqueId($id = null)
{
if ($id) {
return $this->_getFileData($id, 'uniq');
}
$ids = array();
foreach ($this->_files as $num => $file) {
$ids[$num + 1] = $file['uniq'];
}
return $ids;
}
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
public function getNumberByUniqueId($id)
{
foreach ($this->_files as $num => $file) {
if ($file['uniq'] == $id) {
return $num + 1;
}
}
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('unique id not found');
}
}

View File

@ -0,0 +1,447 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mbox.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Loader
* May be used in constructor, but commented out for now
*/
// require_once 'Zend/Loader.php';
/**
* @see Zend_Mail_Storage_Abstract
*/
require_once 'Zend/Mail/Storage/Abstract.php';
/**
* @see Zend_Mail_Message_File
*/
require_once 'Zend/Mail/Message/File.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Mbox extends Zend_Mail_Storage_Abstract
{
/**
* file handle to mbox file
* @var null|resource
*/
protected $_fh;
/**
* filename of mbox file for __wakeup
* @var string
*/
protected $_filename;
/**
* modification date of mbox file for __wakeup
* @var int
*/
protected $_filemtime;
/**
* start and end position of messages as array('start' => start, 'seperator' => headersep, 'end' => end)
* @var array
*/
protected $_positions;
/**
* used message class, change it in an extened class to extend the returned message class
* @var string
*/
protected $_messageClass = 'Zend_Mail_Message_File';
/**
* Count messages all messages in current box
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
*/
public function countMessages()
{
return count($this->_positions);
}
/**
* Get a list of messages with number and size
*
* @param int|null $id number of message or null for all messages
* @return int|array size of given message of list with all messages as array(num => size)
*/
public function getSize($id = 0)
{
if ($id) {
$pos = $this->_positions[$id - 1];
return $pos['end'] - $pos['start'];
}
$result = array();
foreach ($this->_positions as $num => $pos) {
$result[$num + 1] = $pos['end'] - $pos['start'];
}
return $result;
}
/**
* Get positions for mail message or throw exeption if id is invalid
*
* @param int $id number of message
* @return array positions as in _positions
* @throws Zend_Mail_Storage_Exception
*/
protected function _getPos($id)
{
if (!isset($this->_positions[$id - 1])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('id does not exist');
}
return $this->_positions[$id - 1];
}
/**
* Fetch a message
*
* @param int $id number of message
* @return Zend_Mail_Message_File
* @throws Zend_Mail_Storage_Exception
*/
public function getMessage($id)
{
// TODO that's ugly, would be better to let the message class decide
if (strtolower($this->_messageClass) == 'zend_mail_message_file' || is_subclass_of($this->_messageClass, 'zend_mail_message_file')) {
// TODO top/body lines
$messagePos = $this->_getPos($id);
return new $this->_messageClass(array('file' => $this->_fh, 'startPos' => $messagePos['start'],
'endPos' => $messagePos['end']));
}
$bodyLines = 0; // TODO: need a way to change that
$message = $this->getRawHeader($id);
// file pointer is after headers now
if ($bodyLines) {
$message .= "\n";
while ($bodyLines-- && ftell($this->_fh) < $this->_positions[$id - 1]['end']) {
$message .= fgets($this->_fh);
}
}
return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $message));
}
/*
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawHeader($id, $part = null, $topLines = 0)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$messagePos = $this->_getPos($id);
// TODO: toplines
return stream_get_contents($this->_fh, $messagePos['separator'] - $messagePos['start'], $messagePos['start']);
}
/*
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawContent($id, $part = null)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$messagePos = $this->_getPos($id);
return stream_get_contents($this->_fh, $messagePos['end'] - $messagePos['separator'], $messagePos['separator']);
}
/**
* Create instance with parameters
* Supported parameters are:
* - filename filename of mbox file
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
if (!isset($params->filename) /* || Zend_Loader::isReadable($params['filename']) */) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('no valid filename given in params');
}
$this->_openMboxFile($params->filename);
$this->_has['top'] = true;
$this->_has['uniqueid'] = false;
}
/**
* check if given file is a mbox file
*
* if $file is a resource its file pointer is moved after the first line
*
* @param resource|string $file stream resource of name of file
* @param bool $fileIsString file is string or resource
* @return bool file is mbox file
*/
protected function _isMboxFile($file, $fileIsString = true)
{
if ($fileIsString) {
$file = @fopen($file, 'r');
if (!$file) {
return false;
}
} else {
fseek($file, 0);
}
$result = false;
$line = fgets($file);
if (strpos($line, 'From ') === 0) {
$result = true;
}
if ($fileIsString) {
@fclose($file);
}
return $result;
}
/**
* open given file as current mbox file
*
* @param string $filename filename of mbox file
* @return null
* @throws Zend_Mail_Storage_Exception
*/
protected function _openMboxFile($filename)
{
if ($this->_fh) {
$this->close();
}
$this->_fh = @fopen($filename, 'r');
if (!$this->_fh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot open mbox file');
}
$this->_filename = $filename;
$this->_filemtime = filemtime($this->_filename);
if (!$this->_isMboxFile($this->_fh, false)) {
@fclose($this->_fh);
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('file is not a valid mbox format');
}
$messagePos = array('start' => ftell($this->_fh), 'separator' => 0, 'end' => 0);
while (($line = fgets($this->_fh)) !== false) {
if (strpos($line, 'From ') === 0) {
$messagePos['end'] = ftell($this->_fh) - strlen($line) - 2; // + newline
if (!$messagePos['separator']) {
$messagePos['separator'] = $messagePos['end'];
}
$this->_positions[] = $messagePos;
$messagePos = array('start' => ftell($this->_fh), 'separator' => 0, 'end' => 0);
}
if (!$messagePos['separator'] && !trim($line)) {
$messagePos['separator'] = ftell($this->_fh);
}
}
$messagePos['end'] = ftell($this->_fh);
if (!$messagePos['separator']) {
$messagePos['separator'] = $messagePos['end'];
}
$this->_positions[] = $messagePos;
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return void
*/
public function close()
{
@fclose($this->_fh);
$this->_positions = array();
}
/**
* Waste some CPU cycles doing nothing.
*
* @return void
*/
public function noop()
{
return true;
}
/**
* stub for not supported message deletion
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeMessage($id)
{
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('mbox is read-only');
}
/**
* get unique id for one or all messages
*
* Mbox does not support unique ids (yet) - it's always the same as the message number.
* That shouldn't be a problem, because we can't change mbox files. Therefor the message
* number is save enough.
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
public function getUniqueId($id = null)
{
if ($id) {
// check if id exists
$this->_getPos($id);
return $id;
}
$range = range(1, $this->countMessages());
return array_combine($range, $range);
}
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
public function getNumberByUniqueId($id)
{
// check if id exists
$this->_getPos($id);
return $id;
}
/**
* magic method for serialize()
*
* with this method you can cache the mbox class
*
* @return array name of variables
*/
public function __sleep()
{
return array('_filename', '_positions', '_filemtime');
}
/**
* magic method for unserialize()
*
* with this method you can cache the mbox class
* for cache validation the mtime of the mbox file is used
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function __wakeup()
{
if ($this->_filemtime != @filemtime($this->_filename)) {
$this->close();
$this->_openMboxFile($this->_filename);
} else {
$this->_fh = @fopen($this->_filename, 'r');
if (!$this->_fh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot open mbox file');
}
}
}
}

View File

@ -0,0 +1,328 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Pop3.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Abstract
*/
require_once 'Zend/Mail/Storage/Abstract.php';
/**
* @see Zend_Mail_Protocol_Pop3
*/
require_once 'Zend/Mail/Protocol/Pop3.php';
/**
* @see Zend_Mail_Message
*/
require_once 'Zend/Mail/Message.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Pop3 extends Zend_Mail_Storage_Abstract
{
/**
* protocol handler
* @var null|Zend_Mail_Protocol_Pop3
*/
protected $_protocol;
/**
* Count messages all messages in current box
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function countMessages()
{
$this->_protocol->status($count, $null);
return (int)$count;
}
/**
* get a list of messages with number and size
*
* @param int $id number of message
* @return int|array size of given message of list with all messages as array(num => size)
* @throws Zend_Mail_Protocol_Exception
*/
public function getSize($id = 0)
{
$id = $id ? $id : null;
return $this->_protocol->getList($id);
}
/**
* Fetch a message
*
* @param int $id number of message
* @return Zend_Mail_Message
* @throws Zend_Mail_Protocol_Exception
*/
public function getMessage($id)
{
$bodyLines = 0;
$message = $this->_protocol->top($id, $bodyLines, true);
return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $message,
'noToplines' => $bodyLines < 1));
}
/*
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawHeader($id, $part = null, $topLines = 0)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
return $this->_protocol->top($id, 0, true);
}
/*
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawContent($id, $part = null)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$content = $this->_protocol->retrieve($id);
// TODO: find a way to avoid decoding the headers
Zend_Mime_Decode::splitMessage($content, $null, $body);
return $body;
}
/**
* create instance with parameters
* Supported paramters are
* - host hostname or ip address of POP3 server
* - user username
* - password password for user 'username' [optional, default = '']
* - port port for POP3 server [optional, default = 110]
* - ssl 'SSL' or 'TLS' for secure sockets
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
$this->_has['fetchPart'] = false;
$this->_has['top'] = null;
$this->_has['uniqueid'] = null;
if ($params instanceof Zend_Mail_Protocol_Pop3) {
$this->_protocol = $params;
return;
}
if (!isset($params->user)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('need at least user in params');
}
$host = isset($params->host) ? $params->host : 'localhost';
$password = isset($params->password) ? $params->password : '';
$port = isset($params->port) ? $params->port : null;
$ssl = isset($params->ssl) ? $params->ssl : false;
$this->_protocol = new Zend_Mail_Protocol_Pop3();
$this->_protocol->connect($host, $port, $ssl);
$this->_protocol->login($params->user, $password);
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return null
*/
public function close()
{
$this->_protocol->logout();
}
/**
* Keep the server busy.
*
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function noop()
{
return $this->_protocol->noop();
}
/**
* Remove a message from server. If you're doing that from a web enviroment
* you should be careful and use a uniqueid as parameter if possible to
* identify the message.
*
* @param int $id number of message
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function removeMessage($id)
{
$this->_protocol->delete($id);
}
/**
* get unique id for one or all messages
*
* if storage does not support unique ids it's the same as the message number
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
public function getUniqueId($id = null)
{
if (!$this->hasUniqueid) {
if ($id) {
return $id;
}
$count = $this->countMessages();
if ($count < 1) {
return array();
}
$range = range(1, $count);
return array_combine($range, $range);
}
return $this->_protocol->uniqueid($id);
}
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
public function getNumberByUniqueId($id)
{
if (!$this->hasUniqueid) {
return $id;
}
$ids = $this->getUniqueId();
foreach ($ids as $k => $v) {
if ($v == $id) {
return $k;
}
}
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('unique id not found');
}
/**
* Special handling for hasTop and hasUniqueid. The headers of the first message is
* retrieved if Top wasn't needed/tried yet.
*
* @see Zend_Mail_Storage_Abstract:__get()
* @param string $var
* @return string
* @throws Zend_Mail_Storage_Exception
*/
public function __get($var)
{
$result = parent::__get($var);
if ($result !== null) {
return $result;
}
if (strtolower($var) == 'hastop') {
if ($this->_protocol->hasTop === null) {
// need to make a real call, because not all server are honest in their capas
try {
$this->_protocol->top(1, 0, false);
} catch(Zend_Mail_Exception $e) {
// ignoring error
}
}
$this->_has['top'] = $this->_protocol->hasTop;
return $this->_protocol->hasTop;
}
if (strtolower($var) == 'hasuniqueid') {
$id = null;
try {
$id = $this->_protocol->uniqueid(1);
} catch(Zend_Mail_Exception $e) {
// ignoring error
}
$this->_has['uniqueid'] = $id ? true : false;
return $this->_has['uniqueid'];
}
return $result;
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Mail_Storage_Writable_Interface
{
/**
* create a new folder
*
* This method also creates parent folders if necessary. Some mail storages may restrict, which folder
* may be used as parent or which chars may be used in the folder name
*
* @param string $name global name of folder, local name if $parentFolder is set
* @param string|Zend_Mail_Storage_Folder $parentFolder parent folder for new folder, else root folder is parent
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function createFolder($name, $parentFolder = null);
/**
* remove a folder
*
* @param string|Zend_Mail_Storage_Folder $name name or instance of folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeFolder($name);
/**
* rename and/or move folder
*
* The new name has the same restrictions as in createFolder()
*
* @param string|Zend_Mail_Storage_Folder $oldName name or instance of folder
* @param string $newName new global name of folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function renameFolder($oldName, $newName);
/**
* append a new message to mail storage
*
* @param string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class
* @param null|string|Zend_Mail_Storage_Folder $folder folder for new message, else current folder is taken
* @param null|array $flags set flags for new message, else a default set is used
* @throws Zend_Mail_Storage_Exception
*/
public function appendMessage($message, $folder = null, $flags = null);
/**
* copy an existing message
*
* @param int $id number of message
* @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function copyMessage($id, $folder);
/**
* move an existing message
*
* @param int $id number of message
* @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function moveMessage($id, $folder);
/**
* set flags for message
*
* NOTE: this method can't set the recent flag.
*
* @param int $id number of message
* @param array $flags new flags for message
* @throws Zend_Mail_Storage_Exception
*/
public function setFlags($id, $flags);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,350 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* Abstract for sending eMails through different
* ways of transport
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Mail_Transport_Abstract
{
/**
* Mail body
* @var string
* @access public
*/
public $body = '';
/**
* MIME boundary
* @var string
* @access public
*/
public $boundary = '';
/**
* Mail header string
* @var string
* @access public
*/
public $header = '';
/**
* Array of message headers
* @var array
* @access protected
*/
protected $_headers = array();
/**
* Message is a multipart message
* @var boolean
* @access protected
*/
protected $_isMultipart = false;
/**
* Zend_Mail object
* @var false|Zend_Mail
* @access protected
*/
protected $_mail = false;
/**
* Array of message parts
* @var array
* @access protected
*/
protected $_parts = array();
/**
* Recipients string
* @var string
* @access public
*/
public $recipients = '';
/**
* EOL character string used by transport
* @var string
* @access public
*/
public $EOL = "\r\n";
/**
* Send an email independent from the used transport
*
* The requisite information for the email will be found in the following
* properties:
*
* - {@link $recipients} - list of recipients (string)
* - {@link $header} - message header
* - {@link $body} - message body
*/
abstract protected function _sendMail();
/**
* Return all mail headers as an array
*
* If a boundary is given, a multipart header is generated with a
* Content-Type of either multipart/alternative or multipart/mixed depending
* on the mail parts present in the {@link $_mail Zend_Mail object} present.
*
* @param string $boundary
* @return array
*/
protected function _getHeaders($boundary)
{
if (null !== $boundary) {
// Build multipart mail
$type = $this->_mail->getType();
if (!$type) {
if ($this->_mail->hasAttachments) {
$type = Zend_Mime::MULTIPART_MIXED;
} elseif ($this->_mail->getBodyText() && $this->_mail->getBodyHtml()) {
$type = Zend_Mime::MULTIPART_ALTERNATIVE;
} else {
$type = Zend_Mime::MULTIPART_MIXED;
}
}
$this->_headers['Content-Type'] = array(
$type . ';'
. $this->EOL
. " " . 'boundary="' . $boundary . '"'
);
$this->boundary = $boundary;
}
$this->_headers['MIME-Version'] = array('1.0');
return $this->_headers;
}
/**
* Prepend header name to header value
*
* @param string $item
* @param string $key
* @param string $prefix
* @static
* @access protected
* @return void
*/
protected static function _formatHeader(&$item, $key, $prefix)
{
$item = $prefix . ': ' . $item;
}
/**
* Prepare header string for use in transport
*
* Prepares and generates {@link $header} based on the headers provided.
*
* @param mixed $headers
* @access protected
* @return void
* @throws Zend_Mail_Transport_Exception if any header lines exceed 998
* characters
*/
protected function _prepareHeaders($headers)
{
if (!$this->_mail) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Missing Zend_Mail object in _mail property');
}
$this->header = '';
foreach ($headers as $header => $content) {
if (isset($content['append'])) {
unset($content['append']);
$value = implode(',' . $this->EOL . ' ', $content);
$this->header .= $header . ': ' . $value . $this->EOL;
} else {
array_walk($content, array(get_class($this), '_formatHeader'), $header);
$this->header .= implode($this->EOL, $content) . $this->EOL;
}
}
// Sanity check on headers -- should not be > 998 characters
$sane = true;
foreach (explode($this->EOL, $this->header) as $line) {
if (strlen(trim($line)) > 998) {
$sane = false;
break;
}
}
if (!$sane) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Exception('At least one mail header line is too long');
}
}
/**
* Generate MIME compliant message from the current configuration
*
* If both a text and HTML body are present, generates a
* multipart/alternative Zend_Mime_Part containing the headers and contents
* of each. Otherwise, uses whichever of the text or HTML parts present.
*
* The content part is then prepended to the list of Zend_Mime_Parts for
* this message.
*
* @return void
*/
protected function _buildBody()
{
if (($text = $this->_mail->getBodyText())
&& ($html = $this->_mail->getBodyHtml()))
{
// Generate unique boundary for multipart/alternative
$mime = new Zend_Mime(null);
$boundaryLine = $mime->boundaryLine($this->EOL);
$boundaryEnd = $mime->mimeEnd($this->EOL);
$text->disposition = false;
$html->disposition = false;
$body = $boundaryLine
. $text->getHeaders($this->EOL)
. $this->EOL
. $text->getContent($this->EOL)
. $this->EOL
. $boundaryLine
. $html->getHeaders($this->EOL)
. $this->EOL
. $html->getContent($this->EOL)
. $this->EOL
. $boundaryEnd;
$mp = new Zend_Mime_Part($body);
$mp->type = Zend_Mime::MULTIPART_ALTERNATIVE;
$mp->boundary = $mime->boundary();
$this->_isMultipart = true;
// Ensure first part contains text alternatives
array_unshift($this->_parts, $mp);
// Get headers
$this->_headers = $this->_mail->getHeaders();
return;
}
// If not multipart, then get the body
if (false !== ($body = $this->_mail->getBodyHtml())) {
array_unshift($this->_parts, $body);
} elseif (false !== ($body = $this->_mail->getBodyText())) {
array_unshift($this->_parts, $body);
}
if (!$body) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('No body specified');
}
// Get headers
$this->_headers = $this->_mail->getHeaders();
$headers = $body->getHeadersArray($this->EOL);
foreach ($headers as $header) {
// Headers in Zend_Mime_Part are kept as arrays with two elements, a
// key and a value
$this->_headers[$header[0]] = array($header[1]);
}
}
/**
* Send a mail using this transport
*
* @param Zend_Mail $mail
* @access public
* @return void
* @throws Zend_Mail_Transport_Exception if mail is empty
*/
public function send(Zend_Mail $mail)
{
$this->_isMultipart = false;
$this->_mail = $mail;
$this->_parts = $mail->getParts();
$mime = $mail->getMime();
// Build body content
$this->_buildBody();
// Determine number of parts and boundary
$count = count($this->_parts);
$boundary = null;
if ($count < 1) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Empty mail cannot be sent');
}
if ($count > 1) {
// Multipart message; create new MIME object and boundary
$mime = new Zend_Mime($this->_mail->getMimeBoundary());
$boundary = $mime->boundary();
} elseif ($this->_isMultipart) {
// multipart/alternative -- grab boundary
$boundary = $this->_parts[0]->boundary;
}
// Determine recipients, and prepare headers
$this->recipients = implode(',', $mail->getRecipients());
$this->_prepareHeaders($this->_getHeaders($boundary));
// Create message body
// This is done so that the same Zend_Mail object can be used in
// multiple transports
$message = new Zend_Mime_Message();
$message->setParts($this->_parts);
$message->setMime($mime);
$this->body = $message->generateMessage($this->EOL);
// Send to transport!
$this->_sendMail();
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Transport_Exception extends Zend_Mail_Exception
{}

View File

@ -0,0 +1,134 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Mail_Transport_Abstract
*/
require_once 'Zend/Mail/Transport/Abstract.php';
/**
* File transport
*
* Class for saving outgoing emails in filesystem
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Transport_File extends Zend_Mail_Transport_Abstract
{
/**
* Target directory for saving sent email messages
*
* @var string
*/
protected $_path;
/**
* Callback function generating a file name
*
* @var string|array
*/
protected $_callback;
/**
* Constructor
*
* @param array|Zend_Config $options OPTIONAL (Default: null)
* @return void
*/
public function __construct($options = null)
{
if ($options instanceof Zend_Config) {
$options = $options->toArray();
} elseif (!is_array($options)) {
$options = array();
}
// Making sure we have some defaults to work with
if (!isset($options['path'])) {
$options['path'] = sys_get_temp_dir();
}
if (!isset($options['callback'])) {
$options['callback'] = array($this, 'defaultCallback');
}
$this->setOptions($options);
}
/**
* Sets options
*
* @param array $options
* @return void
*/
public function setOptions(array $options)
{
if (isset($options['path']) && is_dir($options['path'])) {
$this->_path = $options['path'];
}
if (isset($options['callback']) && is_callable($options['callback'])) {
$this->_callback = $options['callback'];
}
}
/**
* Saves e-mail message to a file
*
* @return void
* @throws Zend_Mail_Transport_Exception on not writable target directory
* @throws Zend_Mail_Transport_Exception on file_put_contents() failure
*/
protected function _sendMail()
{
$file = $this->_path . DIRECTORY_SEPARATOR . call_user_func($this->_callback, $this);
if (!is_writable(dirname($file))) {
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception(sprintf(
'Target directory "%s" does not exist or is not writable',
dirname($file)
));
}
$email = $this->header . $this->EOL . $this->body;
if (!file_put_contents($file, $email)) {
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Unable to send mail');
}
}
/**
* Default callback for generating filenames
*
* @param Zend_Mail_Transport_File File transport instance
* @return string
*/
public function defaultCallback($transport)
{
return 'ZendMail_' . $_SERVER['REQUEST_TIME'] . '_' . mt_rand() . '.tmp';
}
}

View File

@ -0,0 +1,220 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Sendmail.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Transport_Abstract
*/
require_once 'Zend/Mail/Transport/Abstract.php';
/**
* Class for sending eMails via the PHP internal mail() function
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Transport_Sendmail extends Zend_Mail_Transport_Abstract
{
/**
* Subject
* @var string
* @access public
*/
public $subject = null;
/**
* Config options for sendmail parameters
*
* @var string
*/
public $parameters;
/**
* EOL character string
* @var string
* @access public
*/
public $EOL = PHP_EOL;
/**
* error information
* @var string
*/
protected $_errstr;
/**
* Constructor.
*
* @param string|array|Zend_Config $parameters OPTIONAL (Default: null)
* @return void
*/
public function __construct($parameters = null)
{
if ($parameters instanceof Zend_Config) {
$parameters = $parameters->toArray();
}
if (is_array($parameters)) {
$parameters = implode(' ', $parameters);
}
$this->parameters = $parameters;
}
/**
* Send mail using PHP native mail()
*
* @access public
* @return void
* @throws Zend_Mail_Transport_Exception if parameters is set
* but not a string
* @throws Zend_Mail_Transport_Exception on mail() failure
*/
public function _sendMail()
{
if ($this->parameters === null) {
set_error_handler(array($this, '_handleMailErrors'));
$result = mail(
$this->recipients,
$this->_mail->getSubject(),
$this->body,
$this->header);
restore_error_handler();
} else {
if(!is_string($this->parameters)) {
/**
* @see Zend_Mail_Transport_Exception
*
* Exception is thrown here because
* $parameters is a public property
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception(
'Parameters were set but are not a string'
);
}
set_error_handler(array($this, '_handleMailErrors'));
$result = mail(
$this->recipients,
$this->_mail->getSubject(),
$this->body,
$this->header,
$this->parameters);
restore_error_handler();
}
if ($this->_errstr !== null || !$result) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Unable to send mail. ' . $this->_errstr);
}
}
/**
* Format and fix headers
*
* mail() uses its $to and $subject arguments to set the To: and Subject:
* headers, respectively. This method strips those out as a sanity check to
* prevent duplicate header entries.
*
* @access protected
* @param array $headers
* @return void
* @throws Zend_Mail_Transport_Exception
*/
protected function _prepareHeaders($headers)
{
if (!$this->_mail) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('_prepareHeaders requires a registered Zend_Mail object');
}
// mail() uses its $to parameter to set the To: header, and the $subject
// parameter to set the Subject: header. We need to strip them out.
if (0 === strpos(PHP_OS, 'WIN')) {
// If the current recipients list is empty, throw an error
if (empty($this->recipients)) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Missing To addresses');
}
} else {
// All others, simply grab the recipients and unset the To: header
if (!isset($headers['To'])) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Missing To header');
}
unset($headers['To']['append']);
$this->recipients = implode(',', $headers['To']);
}
// Remove recipient header
unset($headers['To']);
// Remove subject header, if present
if (isset($headers['Subject'])) {
unset($headers['Subject']);
}
// Prepare headers
parent::_prepareHeaders($headers);
// Fix issue with empty blank line ontop when using Sendmail Trnasport
$this->header = rtrim($this->header);
}
/**
* Temporary error handler for PHP native mail().
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param string $errline
* @param array $errcontext
* @return true
*/
public function _handleMailErrors($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
{
$this->_errstr = $errstr;
return true;
}
}

View File

@ -0,0 +1,243 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Smtp.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* @see Zend_Mail_Protocol_Smtp
*/
require_once 'Zend/Mail/Protocol/Smtp.php';
/**
* @see Zend_Mail_Transport_Abstract
*/
require_once 'Zend/Mail/Transport/Abstract.php';
/**
* SMTP connection object
*
* Loads an instance of Zend_Mail_Protocol_Smtp and forwards smtp transactions
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Transport_Smtp extends Zend_Mail_Transport_Abstract
{
/**
* EOL character string used by transport
* @var string
* @access public
*/
public $EOL = "\n";
/**
* Remote smtp hostname or i.p.
*
* @var string
*/
protected $_host;
/**
* Port number
*
* @var integer|null
*/
protected $_port;
/**
* Local client hostname or i.p.
*
* @var string
*/
protected $_name = 'localhost';
/**
* Authentication type OPTIONAL
*
* @var string
*/
protected $_auth;
/**
* Config options for authentication
*
* @var array
*/
protected $_config;
/**
* Instance of Zend_Mail_Protocol_Smtp
*
* @var Zend_Mail_Protocol_Smtp
*/
protected $_connection;
/**
* Constructor.
*
* @param string $host OPTIONAL (Default: 127.0.0.1)
* @param array|null $config OPTIONAL (Default: null)
* @return void
*
* @todo Someone please make this compatible
* with the SendMail transport class.
*/
public function __construct($host = '127.0.0.1', Array $config = array())
{
if (isset($config['name'])) {
$this->_name = $config['name'];
}
if (isset($config['port'])) {
$this->_port = $config['port'];
}
if (isset($config['auth'])) {
$this->_auth = $config['auth'];
}
$this->_host = $host;
$this->_config = $config;
}
/**
* Class destructor to ensure all open connections are closed
*
* @return void
*/
public function __destruct()
{
if ($this->_connection instanceof Zend_Mail_Protocol_Smtp) {
try {
$this->_connection->quit();
} catch (Zend_Mail_Protocol_Exception $e) {
// ignore
}
$this->_connection->disconnect();
}
}
/**
* Sets the connection protocol instance
*
* @param Zend_Mail_Protocol_Abstract $client
*
* @return void
*/
public function setConnection(Zend_Mail_Protocol_Abstract $connection)
{
$this->_connection = $connection;
}
/**
* Gets the connection protocol instance
*
* @return Zend_Mail_Protocol|null
*/
public function getConnection()
{
return $this->_connection;
}
/**
* Send an email via the SMTP connection protocol
*
* The connection via the protocol adapter is made just-in-time to allow a
* developer to add a custom adapter if required before mail is sent.
*
* @return void
* @todo Rename this to sendMail, it's a public method...
*/
public function _sendMail()
{
// If sending multiple messages per session use existing adapter
if (!($this->_connection instanceof Zend_Mail_Protocol_Smtp)) {
// Check if authentication is required and determine required class
$connectionClass = 'Zend_Mail_Protocol_Smtp';
if ($this->_auth) {
$connectionClass .= '_Auth_' . ucwords($this->_auth);
}
if (!class_exists($connectionClass)) {
require_once 'Zend/Loader.php';
Zend_Loader::loadClass($connectionClass);
}
$this->setConnection(new $connectionClass($this->_host, $this->_port, $this->_config));
$this->_connection->connect();
$this->_connection->helo($this->_name);
} else {
// Reset connection to ensure reliable transaction
$this->_connection->rset();
}
// Set sender email address
$this->_connection->mail($this->_mail->getReturnPath());
// Set recipient forward paths
foreach ($this->_mail->getRecipients() as $recipient) {
$this->_connection->rcpt($recipient);
}
// Issue DATA command to client
$this->_connection->data($this->header . Zend_Mime::LINEEND . $this->body);
}
/**
* Format and fix headers
*
* Some SMTP servers do not strip BCC headers. Most clients do it themselves as do we.
*
* @access protected
* @param array $headers
* @return void
* @throws Zend_Transport_Exception
*/
protected function _prepareHeaders($headers)
{
if (!$this->_mail) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('_prepareHeaders requires a registered Zend_Mail object');
}
unset($headers['Bcc']);
// Prepare headers
parent::_prepareHeaders($headers);
}
}

365
webui/Zend/Mime.php Normal file
View File

@ -0,0 +1,365 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mime.php 24953 2012-06-13 19:09:58Z rob $
*/
/**
* Support class for MultiPart Mime Messages
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime
{
const TYPE_OCTETSTREAM = 'application/octet-stream';
const TYPE_TEXT = 'text/plain';
const TYPE_HTML = 'text/html';
const ENCODING_7BIT = '7bit';
const ENCODING_8BIT = '8bit';
const ENCODING_QUOTEDPRINTABLE = 'quoted-printable';
const ENCODING_BASE64 = 'base64';
const DISPOSITION_ATTACHMENT = 'attachment';
const DISPOSITION_INLINE = 'inline';
const LINELENGTH = 72;
const LINEEND = "\n";
const MULTIPART_ALTERNATIVE = 'multipart/alternative';
const MULTIPART_MIXED = 'multipart/mixed';
const MULTIPART_RELATED = 'multipart/related';
protected $_boundary;
protected static $makeUnique = 0;
// lookup-Tables for QuotedPrintable
public static $qpKeys = array(
"\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07",
"\x08","\x09","\x0A","\x0B","\x0C","\x0D","\x0E","\x0F",
"\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17",
"\x18","\x19","\x1A","\x1B","\x1C","\x1D","\x1E","\x1F",
"\x7F","\x80","\x81","\x82","\x83","\x84","\x85","\x86",
"\x87","\x88","\x89","\x8A","\x8B","\x8C","\x8D","\x8E",
"\x8F","\x90","\x91","\x92","\x93","\x94","\x95","\x96",
"\x97","\x98","\x99","\x9A","\x9B","\x9C","\x9D","\x9E",
"\x9F","\xA0","\xA1","\xA2","\xA3","\xA4","\xA5","\xA6",
"\xA7","\xA8","\xA9","\xAA","\xAB","\xAC","\xAD","\xAE",
"\xAF","\xB0","\xB1","\xB2","\xB3","\xB4","\xB5","\xB6",
"\xB7","\xB8","\xB9","\xBA","\xBB","\xBC","\xBD","\xBE",
"\xBF","\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6",
"\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE",
"\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6",
"\xD7","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE",
"\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6",
"\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE",
"\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6",
"\xF7","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE",
"\xFF"
);
public static $qpReplaceValues = array(
"=00","=01","=02","=03","=04","=05","=06","=07",
"=08","=09","=0A","=0B","=0C","=0D","=0E","=0F",
"=10","=11","=12","=13","=14","=15","=16","=17",
"=18","=19","=1A","=1B","=1C","=1D","=1E","=1F",
"=7F","=80","=81","=82","=83","=84","=85","=86",
"=87","=88","=89","=8A","=8B","=8C","=8D","=8E",
"=8F","=90","=91","=92","=93","=94","=95","=96",
"=97","=98","=99","=9A","=9B","=9C","=9D","=9E",
"=9F","=A0","=A1","=A2","=A3","=A4","=A5","=A6",
"=A7","=A8","=A9","=AA","=AB","=AC","=AD","=AE",
"=AF","=B0","=B1","=B2","=B3","=B4","=B5","=B6",
"=B7","=B8","=B9","=BA","=BB","=BC","=BD","=BE",
"=BF","=C0","=C1","=C2","=C3","=C4","=C5","=C6",
"=C7","=C8","=C9","=CA","=CB","=CC","=CD","=CE",
"=CF","=D0","=D1","=D2","=D3","=D4","=D5","=D6",
"=D7","=D8","=D9","=DA","=DB","=DC","=DD","=DE",
"=DF","=E0","=E1","=E2","=E3","=E4","=E5","=E6",
"=E7","=E8","=E9","=EA","=EB","=EC","=ED","=EE",
"=EF","=F0","=F1","=F2","=F3","=F4","=F5","=F6",
"=F7","=F8","=F9","=FA","=FB","=FC","=FD","=FE",
"=FF"
);
public static $qpKeysString =
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
/**
* Check if the given string is "printable"
*
* Checks that a string contains no unprintable characters. If this returns
* false, encode the string for secure delivery.
*
* @param string $str
* @return boolean
*/
public static function isPrintable($str)
{
return (strcspn($str, self::$qpKeysString) == strlen($str));
}
/**
* Encode a given string with the QUOTED_PRINTABLE mechanism and wrap the lines.
*
* @param string $str
* @param int $lineLength Defaults to {@link LINELENGTH}
* @param int $lineEnd Defaults to {@link LINEEND}
* @return string
*/
public static function encodeQuotedPrintable($str,
$lineLength = self::LINELENGTH,
$lineEnd = self::LINEEND)
{
$out = '';
$str = self::_encodeQuotedPrintable($str);
// Split encoded text into separate lines
while(strlen($str) > 0) {
$ptr = strlen($str);
if ($ptr > $lineLength) {
$ptr = $lineLength;
}
// Ensure we are not splitting across an encoded character
$pos = strrpos(substr($str, 0, $ptr), '=');
if ($pos !== false && $pos >= $ptr - 2) {
$ptr = $pos;
}
// Check if there is a space at the end of the line and rewind
if ($ptr > 0 && $str[$ptr - 1] == ' ') {
--$ptr;
}
// Add string and continue
$out .= substr($str, 0, $ptr) . '=' . $lineEnd;
$str = substr($str, $ptr);
}
$out = rtrim($out, $lineEnd);
$out = rtrim($out, '=');
return $out;
}
/**
* Converts a string into quoted printable format.
*
* @param string $str
* @return string
*/
private static function _encodeQuotedPrintable($str)
{
$str = str_replace('=', '=3D', $str);
$str = str_replace(self::$qpKeys, self::$qpReplaceValues, $str);
$str = rtrim($str);
return $str;
}
/**
* Encode a given string with the QUOTED_PRINTABLE mechanism for Mail Headers.
*
* Mail headers depend on an extended quoted printable algorithm otherwise
* a range of bugs can occur.
*
* @param string $str
* @param string $charset
* @param int $lineLength Defaults to {@link LINELENGTH}
* @param int $lineEnd Defaults to {@link LINEEND}
* @return string
*/
public static function encodeQuotedPrintableHeader($str, $charset,
$lineLength = self::LINELENGTH,
$lineEnd = self::LINEEND)
{
// Reduce line-length by the length of the required delimiter, charsets and encoding
$prefix = sprintf('=?%s?Q?', $charset);
$lineLength = $lineLength-strlen($prefix)-3;
$str = self::_encodeQuotedPrintable($str);
// Mail-Header required chars have to be encoded also:
$str = str_replace(array('?', ' ', '_', ','), array('=3F', '=20', '=5F', '=2C'), $str);
// initialize first line, we need it anyways
$lines = array(0 => "");
// Split encoded text into separate lines
$tmp = "";
while(strlen($str) > 0) {
$currentLine = max(count($lines)-1, 0);
$token = self::getNextQuotedPrintableToken($str);
$str = substr($str, strlen($token));
$tmp .= $token;
if($token == '=20') {
// only if we have a single char token or space, we can append the
// tempstring it to the current line or start a new line if necessary.
if(strlen($lines[$currentLine].$tmp) > $lineLength) {
$lines[$currentLine+1] = $tmp;
} else {
$lines[$currentLine] .= $tmp;
}
$tmp = "";
}
// don't forget to append the rest to the last line
if(strlen($str) == 0) {
$lines[$currentLine] .= $tmp;
}
}
// assemble the lines together by pre- and appending delimiters, charset, encoding.
for($i = 0; $i < count($lines); $i++) {
$lines[$i] = " ".$prefix.$lines[$i]."?=";
}
$str = trim(implode($lineEnd, $lines));
return $str;
}
/**
* Retrieves the first token from a quoted printable string.
*
* @param string $str
* @return string
*/
private static function getNextQuotedPrintableToken($str)
{
if(substr($str, 0, 1) == "=") {
$token = substr($str, 0, 3);
} else {
$token = substr($str, 0, 1);
}
return $token;
}
/**
* Encode a given string in mail header compatible base64 encoding.
*
* @param string $str
* @param string $charset
* @param int $lineLength Defaults to {@link LINELENGTH}
* @param int $lineEnd Defaults to {@link LINEEND}
* @return string
*/
public static function encodeBase64Header($str,
$charset,
$lineLength = self::LINELENGTH,
$lineEnd = self::LINEEND)
{
$prefix = '=?' . $charset . '?B?';
$suffix = '?=';
$remainingLength = $lineLength - strlen($prefix) - strlen($suffix);
$encodedValue = self::encodeBase64($str, $remainingLength, $lineEnd);
$encodedValue = str_replace($lineEnd, $suffix . $lineEnd . ' ' . $prefix, $encodedValue);
$encodedValue = $prefix . $encodedValue . $suffix;
return $encodedValue;
}
/**
* Encode a given string in base64 encoding and break lines
* according to the maximum linelength.
*
* @param string $str
* @param int $lineLength Defaults to {@link LINELENGTH}
* @param int $lineEnd Defaults to {@link LINEEND}
* @return string
*/
public static function encodeBase64($str,
$lineLength = self::LINELENGTH,
$lineEnd = self::LINEEND)
{
return rtrim(chunk_split(base64_encode($str), $lineLength, $lineEnd));
}
/**
* Constructor
*
* @param null|string $boundary
* @access public
* @return void
*/
public function __construct($boundary = null)
{
// This string needs to be somewhat unique
if ($boundary === null) {
$this->_boundary = '=_' . md5(microtime(1) . self::$makeUnique++);
} else {
$this->_boundary = $boundary;
}
}
/**
* Encode the given string with the given encoding.
*
* @param string $str
* @param string $encoding
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return string
*/
public static function encode($str, $encoding, $EOL = self::LINEEND)
{
switch ($encoding) {
case self::ENCODING_BASE64:
return self::encodeBase64($str, self::LINELENGTH, $EOL);
case self::ENCODING_QUOTEDPRINTABLE:
return self::encodeQuotedPrintable($str, self::LINELENGTH, $EOL);
default:
/**
* @todo 7Bit and 8Bit is currently handled the same way.
*/
return $str;
}
}
/**
* Return a MIME boundary
*
* @access public
* @return string
*/
public function boundary()
{
return $this->_boundary;
}
/**
* Return a MIME boundary line
*
* @param mixed $EOL Defaults to {@link LINEEND}
* @access public
* @return string
*/
public function boundaryLine($EOL = self::LINEEND)
{
return $EOL . '--' . $this->_boundary . $EOL;
}
/**
* Return MIME ending
*
* @access public
* @return string
*/
public function mimeEnd($EOL = self::LINEEND)
{
return $EOL . '--' . $this->_boundary . '--' . $EOL;
}
}

244
webui/Zend/Mime/Decode.php Normal file
View File

@ -0,0 +1,244 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Decode.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime_Decode
{
/**
* Explode MIME multipart string into seperate parts
*
* Parts consist of the header and the body of each MIME part.
*
* @param string $body raw body of message
* @param string $boundary boundary as found in content-type
* @return array parts with content of each part, empty if no parts found
* @throws Zend_Exception
*/
public static function splitMime($body, $boundary)
{
// TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r?
$body = str_replace("\r", '', $body);
$start = 0;
$res = array();
// find every mime part limiter and cut out the
// string before it.
// the part before the first boundary string is discarded:
$p = strpos($body, '--' . $boundary . "\n", $start);
if ($p === false) {
// no parts found!
return array();
}
// position after first boundary line
$start = $p + 3 + strlen($boundary);
while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) {
$res[] = substr($body, $start, $p-$start);
$start = $p + 3 + strlen($boundary);
}
// no more parts, find end boundary
$p = strpos($body, '--' . $boundary . '--', $start);
if ($p===false) {
throw new Zend_Exception('Not a valid Mime Message: End Missing');
}
// the remaining part also needs to be parsed:
$res[] = substr($body, $start, $p-$start);
return $res;
}
/**
* decodes a mime encoded String and returns a
* struct of parts with header and body
*
* @param string $message raw message content
* @param string $boundary boundary as found in content-type
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return array|null parts as array('header' => array(name => value), 'body' => content), null if no parts found
* @throws Zend_Exception
*/
public static function splitMessageStruct($message, $boundary, $EOL = Zend_Mime::LINEEND)
{
$parts = self::splitMime($message, $boundary);
if (count($parts) <= 0) {
return null;
}
$result = array();
foreach ($parts as $part) {
self::splitMessage($part, $headers, $body, $EOL);
$result[] = array('header' => $headers,
'body' => $body );
}
return $result;
}
/**
* split a message in header and body part, if no header or an
* invalid header is found $headers is empty
*
* The charset of the returned headers depend on your iconv settings.
*
* @param string $message raw message with header and optional content
* @param array $headers output param, array with headers as array(name => value)
* @param string $body output param, content of message
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return null
*/
public static function splitMessage($message, &$headers, &$body, $EOL = Zend_Mime::LINEEND)
{
// check for valid header at first line
$firstline = strtok($message, "\n");
if (!preg_match('%^[^\s]+[^:]*:%', $firstline)) {
$headers = array();
// TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r?
$body = str_replace(array("\r", "\n"), array('', $EOL), $message);
return;
}
// find an empty line between headers and body
// default is set new line
if (strpos($message, $EOL . $EOL)) {
list($headers, $body) = explode($EOL . $EOL, $message, 2);
// next is the standard new line
} else if ($EOL != "\r\n" && strpos($message, "\r\n\r\n")) {
list($headers, $body) = explode("\r\n\r\n", $message, 2);
// next is the other "standard" new line
} else if ($EOL != "\n" && strpos($message, "\n\n")) {
list($headers, $body) = explode("\n\n", $message, 2);
// at last resort find anything that looks like a new line
} else {
@list($headers, $body) = @preg_split("%([\r\n]+)\\1%U", $message, 2);
}
$headers = iconv_mime_decode_headers($headers, ICONV_MIME_DECODE_CONTINUE_ON_ERROR);
if ($headers === false ) {
// an error occurs during the decoding
return;
}
// normalize header names
foreach ($headers as $name => $header) {
$lower = strtolower($name);
if ($lower == $name) {
continue;
}
unset($headers[$name]);
if (!isset($headers[$lower])) {
$headers[$lower] = $header;
continue;
}
if (is_array($headers[$lower])) {
$headers[$lower][] = $header;
continue;
}
$headers[$lower] = array($headers[$lower], $header);
}
}
/**
* split a content type in its different parts
*
* @param string $type content-type
* @param string $wantedPart the wanted part, else an array with all parts is returned
* @return string|array wanted part or all parts as array('type' => content-type, partname => value)
*/
public static function splitContentType($type, $wantedPart = null)
{
return self::splitHeaderField($type, $wantedPart, 'type');
}
/**
* split a header field like content type in its different parts
*
* @param string $type header field
* @param string $wantedPart the wanted part, else an array with all parts is returned
* @param string $firstName key name for the first part
* @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
* @throws Zend_Exception
*/
public static function splitHeaderField($field, $wantedPart = null, $firstName = 0)
{
$wantedPart = strtolower($wantedPart);
$firstName = strtolower($firstName);
// special case - a bit optimized
if ($firstName === $wantedPart) {
$field = strtok($field, ';');
return $field[0] == '"' ? substr($field, 1, -1) : $field;
}
$field = $firstName . '=' . $field;
if (!preg_match_all('%([^=\s]+)\s*=\s*("[^"]+"|[^;]+)(;\s*|$)%', $field, $matches)) {
throw new Zend_Exception('not a valid header field');
}
if ($wantedPart) {
foreach ($matches[1] as $key => $name) {
if (strcasecmp($name, $wantedPart)) {
continue;
}
if ($matches[2][$key][0] != '"') {
return $matches[2][$key];
}
return substr($matches[2][$key], 1, -1);
}
return null;
}
$split = array();
foreach ($matches[1] as $key => $name) {
$name = strtolower($name);
if ($matches[2][$key][0] == '"') {
$split[$name] = substr($matches[2][$key], 1, -1);
} else {
$split[$name] = $matches[2][$key];
}
}
return $split;
}
/**
* decode a quoted printable encoded string
*
* The charset of the returned string depends on your iconv settings.
*
* @param string encoded string
* @return string decoded string
*/
public static function decodeQuotedPrintable($string)
{
return quoted_printable_decode($string);
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Exception
*/
require_once 'Zend/Exception.php';
/**
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime_Exception extends Zend_Exception
{}

286
webui/Zend/Mime/Message.php Normal file
View File

@ -0,0 +1,286 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Message.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* Zend_Mime_Part
*/
require_once 'Zend/Mime/Part.php';
/**
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime_Message
{
protected $_parts = array();
protected $_mime = null;
/**
* Returns the list of all Zend_Mime_Parts in the message
*
* @return array of Zend_Mime_Part
*/
public function getParts()
{
return $this->_parts;
}
/**
* Sets the given array of Zend_Mime_Parts as the array for the message
*
* @param array $parts
*/
public function setParts($parts)
{
$this->_parts = $parts;
}
/**
* Append a new Zend_Mime_Part to the current message
*
* @param Zend_Mime_Part $part
*/
public function addPart(Zend_Mime_Part $part)
{
/**
* @todo check for duplicate object handle
*/
$this->_parts[] = $part;
}
/**
* Check if message needs to be sent as multipart
* MIME message or if it has only one part.
*
* @return boolean
*/
public function isMultiPart()
{
return (count($this->_parts) > 1);
}
/**
* Set Zend_Mime object for the message
*
* This can be used to set the boundary specifically or to use a subclass of
* Zend_Mime for generating the boundary.
*
* @param Zend_Mime $mime
*/
public function setMime(Zend_Mime $mime)
{
$this->_mime = $mime;
}
/**
* Returns the Zend_Mime object in use by the message
*
* If the object was not present, it is created and returned. Can be used to
* determine the boundary used in this message.
*
* @return Zend_Mime
*/
public function getMime()
{
if ($this->_mime === null) {
$this->_mime = new Zend_Mime();
}
return $this->_mime;
}
/**
* Generate MIME-compliant message from the current configuration
*
* This can be a multipart message if more than one MIME part was added. If
* only one part is present, the content of this part is returned. If no
* part had been added, an empty string is returned.
*
* Parts are seperated by the mime boundary as defined in Zend_Mime. If
* {@link setMime()} has been called before this method, the Zend_Mime
* object set by this call will be used. Otherwise, a new Zend_Mime object
* is generated and used.
*
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return string
*/
public function generateMessage($EOL = Zend_Mime::LINEEND)
{
if (! $this->isMultiPart()) {
$body = array_shift($this->_parts);
$body = $body->getContent($EOL);
} else {
$mime = $this->getMime();
$boundaryLine = $mime->boundaryLine($EOL);
$body = 'This is a message in Mime Format. If you see this, '
. "your mail reader does not support this format." . $EOL;
foreach (array_keys($this->_parts) as $p) {
$body .= $boundaryLine
. $this->getPartHeaders($p, $EOL)
. $EOL
. $this->getPartContent($p, $EOL);
}
$body .= $mime->mimeEnd($EOL);
}
return trim($body);
}
/**
* Get the headers of a given part as an array
*
* @param int $partnum
* @return array
*/
public function getPartHeadersArray($partnum)
{
return $this->_parts[$partnum]->getHeadersArray();
}
/**
* Get the headers of a given part as a string
*
* @param int $partnum
* @return string
*/
public function getPartHeaders($partnum, $EOL = Zend_Mime::LINEEND)
{
return $this->_parts[$partnum]->getHeaders($EOL);
}
/**
* Get the (encoded) content of a given part as a string
*
* @param int $partnum
* @return string
*/
public function getPartContent($partnum, $EOL = Zend_Mime::LINEEND)
{
return $this->_parts[$partnum]->getContent($EOL);
}
/**
* Explode MIME multipart string into seperate parts
*
* Parts consist of the header and the body of each MIME part.
*
* @param string $body
* @param string $boundary
* @return array
*/
protected static function _disassembleMime($body, $boundary)
{
$start = 0;
$res = array();
// find every mime part limiter and cut out the
// string before it.
// the part before the first boundary string is discarded:
$p = strpos($body, '--'.$boundary."\n", $start);
if ($p === false) {
// no parts found!
return array();
}
// position after first boundary line
$start = $p + 3 + strlen($boundary);
while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) {
$res[] = substr($body, $start, $p-$start);
$start = $p + 3 + strlen($boundary);
}
// no more parts, find end boundary
$p = strpos($body, '--' . $boundary . '--', $start);
if ($p===false) {
throw new Zend_Exception('Not a valid Mime Message: End Missing');
}
// the remaining part also needs to be parsed:
$res[] = substr($body, $start, $p-$start);
return $res;
}
/**
* Decodes a MIME encoded string and returns a Zend_Mime_Message object with
* all the MIME parts set according to the given string
*
* @param string $message
* @param string $boundary
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return Zend_Mime_Message
*/
public static function createFromMessage($message, $boundary, $EOL = Zend_Mime::LINEEND)
{
require_once 'Zend/Mime/Decode.php';
$parts = Zend_Mime_Decode::splitMessageStruct($message, $boundary, $EOL);
$res = new self();
foreach ($parts as $part) {
// now we build a new MimePart for the current Message Part:
$newPart = new Zend_Mime_Part($part['body']);
foreach ($part['header'] as $key => $value) {
/**
* @todo check for characterset and filename
*/
switch(strtolower($key)) {
case 'content-type':
$newPart->type = $value;
break;
case 'content-transfer-encoding':
$newPart->encoding = $value;
break;
case 'content-id':
$newPart->id = trim($value,'<>');
break;
case 'content-disposition':
$newPart->disposition = $value;
break;
case 'content-description':
$newPart->description = $value;
break;
case 'content-location':
$newPart->location = $value;
break;
case 'content-language':
$newPart->language = $value;
break;
default:
throw new Zend_Exception('Unknown header ignored for MimePart:' . $key);
}
}
$res->addPart($newPart);
}
return $res;
}
}

230
webui/Zend/Mime/Part.php Normal file
View File

@ -0,0 +1,230 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Part.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* Class representing a MIME part.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime_Part {
public $type = Zend_Mime::TYPE_OCTETSTREAM;
public $encoding = Zend_Mime::ENCODING_8BIT;
public $id;
public $disposition;
public $filename;
public $description;
public $charset;
public $boundary;
public $location;
public $language;
protected $_content;
protected $_isStream = false;
/**
* create a new Mime Part.
* The (unencoded) content of the Part as passed
* as a string or stream
*
* @param mixed $content String or Stream containing the content
*/
public function __construct($content)
{
$this->_content = $content;
if (is_resource($content)) {
$this->_isStream = true;
}
}
/**
* @todo setters/getters
* @todo error checking for setting $type
* @todo error checking for setting $encoding
*/
/**
* check if this part can be read as a stream.
* if true, getEncodedStream can be called, otherwise
* only getContent can be used to fetch the encoded
* content of the part
*
* @return bool
*/
public function isStream()
{
return $this->_isStream;
}
/**
* if this was created with a stream, return a filtered stream for
* reading the content. very useful for large file attachments.
*
* @return stream
* @throws Zend_Mime_Exception if not a stream or unable to append filter
*/
public function getEncodedStream()
{
if (!$this->_isStream) {
require_once 'Zend/Mime/Exception.php';
throw new Zend_Mime_Exception('Attempt to get a stream from a string part');
}
//stream_filter_remove(); // ??? is that right?
switch ($this->encoding) {
case Zend_Mime::ENCODING_QUOTEDPRINTABLE:
$filter = stream_filter_append(
$this->_content,
'convert.quoted-printable-encode',
STREAM_FILTER_READ,
array(
'line-length' => 76,
'line-break-chars' => Zend_Mime::LINEEND
)
);
if (!is_resource($filter)) {
require_once 'Zend/Mime/Exception.php';
throw new Zend_Mime_Exception('Failed to append quoted-printable filter');
}
break;
case Zend_Mime::ENCODING_BASE64:
$filter = stream_filter_append(
$this->_content,
'convert.base64-encode',
STREAM_FILTER_READ,
array(
'line-length' => 76,
'line-break-chars' => Zend_Mime::LINEEND
)
);
if (!is_resource($filter)) {
require_once 'Zend/Mime/Exception.php';
throw new Zend_Mime_Exception('Failed to append base64 filter');
}
break;
default:
}
return $this->_content;
}
/**
* Get the Content of the current Mime Part in the given encoding.
*
* @return String
*/
public function getContent($EOL = Zend_Mime::LINEEND)
{
if ($this->_isStream) {
return stream_get_contents($this->getEncodedStream());
} else {
return Zend_Mime::encode($this->_content, $this->encoding, $EOL);
}
}
/**
* Get the RAW unencoded content from this part
* @return string
*/
public function getRawContent()
{
if ($this->_isStream) {
return stream_get_contents($this->_content);
} else {
return $this->_content;
}
}
/**
* Create and return the array of headers for this MIME part
*
* @access public
* @return array
*/
public function getHeadersArray($EOL = Zend_Mime::LINEEND)
{
$headers = array();
$contentType = $this->type;
if ($this->charset) {
$contentType .= '; charset=' . $this->charset;
}
if ($this->boundary) {
$contentType .= ';' . $EOL
. " boundary=\"" . $this->boundary . '"';
}
$headers[] = array('Content-Type', $contentType);
if ($this->encoding) {
$headers[] = array('Content-Transfer-Encoding', $this->encoding);
}
if ($this->id) {
$headers[] = array('Content-ID', '<' . $this->id . '>');
}
if ($this->disposition) {
$disposition = $this->disposition;
if ($this->filename) {
$disposition .= '; filename="' . $this->filename . '"';
}
$headers[] = array('Content-Disposition', $disposition);
}
if ($this->description) {
$headers[] = array('Content-Description', $this->description);
}
if ($this->location) {
$headers[] = array('Content-Location', $this->location);
}
if ($this->language){
$headers[] = array('Content-Language', $this->language);
}
return $headers;
}
/**
* Return the headers for this part as a string
*
* @return String
*/
public function getHeaders($EOL = Zend_Mime::LINEEND)
{
$res = '';
foreach ($this->getHeadersArray($EOL) as $header) {
$res .= $header[0] . ': ' . $header[1] . $EOL;
}
return $res;
}
}