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

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;
}
}