diff options
Diffstat (limited to 'Postman/Postman-Mail/Zend-1.12.10/Mail/Protocol/Imap.php')
-rw-r--r-- | Postman/Postman-Mail/Zend-1.12.10/Mail/Protocol/Imap.php | 838 |
1 files changed, 0 insertions, 838 deletions
diff --git a/Postman/Postman-Mail/Zend-1.12.10/Mail/Protocol/Imap.php b/Postman/Postman-Mail/Zend-1.12.10/Mail/Protocol/Imap.php deleted file mode 100644 index 6b3679e..0000000 --- a/Postman/Postman-Mail/Zend-1.12.10/Mail/Protocol/Imap.php +++ /dev/null @@ -1,838 +0,0 @@ -<?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 Postman_Zend_Mail - * @subpackage Protocol - * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id$ - */ - - -/** - * @category Zend - * @package Postman_Zend_Mail - * @subpackage Protocol - * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - */ -class Postman_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 Postman_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 Postman_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 Postman_Zend_Mail_Protocol_Exception - */ - require_once 'Zend/Mail/Protocol/Exception.php'; - throw new Postman_Zend_Mail_Protocol_Exception('cannot connect to host; error = ' . $errstr . - ' (errno = ' . $errno . ' )'); - } - - if (!$this->_assumedNextLine('* OK')) { - /** - * @see Postman_Zend_Mail_Protocol_Exception - */ - require_once 'Zend/Mail/Protocol/Exception.php'; - throw new Postman_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 Postman_Zend_Mail_Protocol_Exception - */ - require_once 'Zend/Mail/Protocol/Exception.php'; - throw new Postman_Zend_Mail_Protocol_Exception('cannot enable TLS'); - } - } - } - - /** - * get the next line from socket with error checking, but nothing else - * - * @return string next line - * @throws Postman_Zend_Mail_Protocol_Exception - */ - protected function _nextLine() - { - $line = @fgets($this->_socket); - if ($line === false) { - /** - * @see Postman_Zend_Mail_Protocol_Exception - */ - require_once 'Zend/Mail/Protocol/Exception.php'; - throw new Postman_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 Postman_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 Postman_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 Postman_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 Postman_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 Postman_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 Postman_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 Postman_Zend_Mail_Protocol_Exception - */ - require_once 'Zend/Mail/Protocol/Exception.php'; - throw new Postman_Zend_Mail_Protocol_Exception('cannot write - connection closed?'); - } - if (!$this->_assumedNextLine('+ ')) { - /** - * @see Postman_Zend_Mail_Protocol_Exception - */ - require_once 'Zend/Mail/Protocol/Exception.php'; - throw new Postman_Zend_Mail_Protocol_Exception('cannot send literal string'); - } - $line = $token[1]; - } else { - $line .= ' ' . $token; - } - } - - if (@fputs($this->_socket, $line . "\r\n") === false) { - /** - * @see Postman_Zend_Mail_Protocol_Exception - */ - require_once 'Zend/Mail/Protocol/Exception.php'; - throw new Postman_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 Postman_Zend_Mail_Protocol_Exception - */ - public function requestAndResponse($command, $tokens = array(), $dontParse = false) - { - $this->sendRequest($command, $tokens, $tag); - $response = $this->readResponse($tag, $dontParse); - - return $response; - } - - /** - * 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 Postman_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 (Postman_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 Postman_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 Postman_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 Postman_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 Postman_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 Postman_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 Postman_Zend_Mail_Protocol_Exception - */ - require_once 'Zend/Mail/Protocol/Exception.php'; - throw new Postman_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 Postman_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 Postman_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 Postman_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 Postman_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(); - } - -} |