/lib/horde/framework/Horde/Imap/Client/Base.php
PHP | 4082 lines | 1821 code | 428 blank | 1833 comment | 255 complexity | 352de1c56e0596fa41d6654dba822b6c MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- <?php
- /**
- * Copyright 2008-2017 Horde LLC (http://www.horde.org/)
- *
- * See the enclosed file LICENSE for license information (LGPL). If you
- * did not receive this file, see http://www.horde.org/licenses/lgpl21.
- *
- * @category Horde
- * @copyright 2008-2017 Horde LLC
- * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
- * @package Imap_Client
- */
- /**
- * An abstracted API interface to IMAP backends supporting the IMAP4rev1
- * protocol (RFC 3501).
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @copyright 2008-2017 Horde LLC
- * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
- * @package Imap_Client
- *
- * @property-read Horde_Imap_Client_Base_Alert $alerts_ob
- The alert reporting object (@since 2.26.0)
- * @property-read Horde_Imap_Client_Data_Capability $capability
- * A capability object. (@since 2.24.0)
- * @property-read Horde_Imap_Client_Data_SearchCharset $search_charset
- * A search charset object. (@since 2.24.0)
- * @property-read Horde_Imap_Client_Url $url The URL object for the current
- * connection parameters (@since 2.24.0)
- */
- abstract class Horde_Imap_Client_Base
- implements Serializable, SplObserver
- {
- /** Serialized version. */
- const VERSION = 3;
- /** Cache names for miscellaneous data. */
- const CACHE_MODSEQ = '_m';
- const CACHE_SEARCH = '_s';
- /* @since 2.9.0 */
- const CACHE_SEARCHID = '_i';
- /** Cache names used exclusively within this class. @since 2.11.0 */
- const CACHE_DOWNGRADED = 'HICdg';
- /**
- * The list of fetch fields that can be cached, and their cache names.
- *
- * @var array
- */
- public $cacheFields = array(
- Horde_Imap_Client::FETCH_ENVELOPE => 'HICenv',
- Horde_Imap_Client::FETCH_FLAGS => 'HICflags',
- Horde_Imap_Client::FETCH_HEADERS => 'HIChdrs',
- Horde_Imap_Client::FETCH_IMAPDATE => 'HICdate',
- Horde_Imap_Client::FETCH_SIZE => 'HICsize',
- Horde_Imap_Client::FETCH_STRUCTURE => 'HICstruct'
- );
- /**
- * Has the internal configuration changed?
- *
- * @var boolean
- */
- public $changed = false;
- /**
- * Horde_Imap_Client is optimized for short (i.e. 1 seconds) scripts. It
- * makes heavy use of mailbox caching to save on server accesses. This
- * property should be set to false for long-running scripts, or else
- * status() data may not reflect the current state of the mailbox on the
- * server.
- *
- * @since 2.14.0
- *
- * @var boolean
- */
- public $statuscache = true;
- /**
- * Alerts reporting object.
- *
- * @var Horde_Imap_Client_Base_Alerts
- */
- protected $_alerts;
- /**
- * The Horde_Imap_Client_Cache object.
- *
- * @var Horde_Imap_Client_Cache
- */
- protected $_cache = null;
- /**
- * Connection to the IMAP server.
- *
- * @var Horde\Socket\Client
- */
- protected $_connection = null;
- /**
- * The debug object.
- *
- * @var Horde_Imap_Client_Base_Debug
- */
- protected $_debug = null;
- /**
- * The default ports to use for a connection.
- * First element is non-secure, second is SSL.
- *
- * @var array
- */
- protected $_defaultPorts = array();
- /**
- * The fetch data object type to return.
- *
- * @var string
- */
- protected $_fetchDataClass = 'Horde_Imap_Client_Data_Fetch';
- /**
- * Cached server data.
- *
- * @var array
- */
- protected $_init;
- /**
- * Is there an active authenticated connection to the IMAP Server?
- *
- * @var boolean
- */
- protected $_isAuthenticated = false;
- /**
- * The current mailbox selection mode.
- *
- * @var integer
- */
- protected $_mode = 0;
- /**
- * Hash containing connection parameters.
- * This hash never changes.
- *
- * @var array
- */
- protected $_params = array();
- /**
- * The currently selected mailbox.
- *
- * @var Horde_Imap_Client_Mailbox
- */
- protected $_selected = null;
- /**
- * Temp array (destroyed at end of process).
- *
- * @var array
- */
- protected $_temp = array();
- /**
- * Constructor.
- *
- * @param array $params Configuration parameters:
- * <pre>
- * - cache: (array) If set, caches data from fetch(), search(), and
- * thread() calls. Requires the horde/Cache package to be
- * installed. The array can contain the following keys (see
- * Horde_Imap_Client_Cache for default values):
- * - backend: [REQUIRED (or cacheob)] (Horde_Imap_Client_Cache_Backend)
- * Backend cache driver [@since 2.9.0].
- * - fetch_ignore: (array) A list of mailboxes to ignore when storing
- * fetch data.
- * - fields: (array) The fetch criteria to cache. If not defined, all
- * cacheable data is cached. The following is a list of
- * criteria that can be cached:
- * - Horde_Imap_Client::FETCH_ENVELOPE
- * - Horde_Imap_Client::FETCH_FLAGS
- * Only if server supports CONDSTORE extension
- * - Horde_Imap_Client::FETCH_HEADERS
- * Only for queries that specifically request caching
- * - Horde_Imap_Client::FETCH_IMAPDATE
- * - Horde_Imap_Client::FETCH_SIZE
- * - Horde_Imap_Client::FETCH_STRUCTURE
- * - capability_ignore: (array) A list of IMAP capabilites to ignore, even
- * if they are supported on the server.
- * DEFAULT: No supported capabilities are ignored.
- * - comparator: (string) The search comparator to use instead of the
- * default server comparator. See setComparator() for
- * format.
- * DEFAULT: Use the server default
- * - context: (array) Any context parameters passed to
- * stream_create_context(). @since 2.27.0
- * - debug: (string) If set, will output debug information to the stream
- * provided. The value can be any PHP supported wrapper that can
- * be opened via PHP's fopen() function.
- * DEFAULT: No debug output
- * - hostspec: (string) The hostname or IP address of the server.
- * DEFAULT: 'localhost'
- * - id: (array) Send ID information to the server (only if server
- * supports the ID extension). An array with the keys as the fields
- * to send and the values being the associated values. See RFC 2971
- * [3.3] for a list of standard field values.
- * DEFAULT: No info sent to server
- * - lang: (array) A list of languages (in priority order) to be used to
- * display human readable messages.
- * DEFAULT: Messages output in IMAP server default language
- * - password: (mixed) The user password. Either a string or a
- * Horde_Imap_Client_Base_Password object [@since 2.14.0].
- * - port: (integer) The server port to which we will connect.
- * DEFAULT: 143 (imap or imap w/TLS) or 993 (imaps)
- * - secure: (string) Use SSL or TLS to connect. Values:
- * - false (No encryption)
- * - 'ssl' (Auto-detect SSL version)
- * - 'sslv2' (Force SSL version 3)
- * - 'sslv3' (Force SSL version 2)
- * - 'tls' (TLS; started via protocol-level negotation over
- * unencrypted channel; RECOMMENDED way of initiating secure
- * connection)
- * - 'tlsv1' (TLS direct version 1.x connection to server) [@since
- * 2.16.0]
- * - true (TLS if available/necessary) [@since 2.15.0]
- * DEFAULT: false
- * - timeout: (integer) Connection timeout, in seconds.
- * DEFAULT: 30 seconds
- * - username: (string) [REQUIRED] The username.
- * - authusername (string) The username used for SASL authentication.
- * If specified this is the user name whose password is used
- * (e.g. administrator).
- * Only valid for RFC 2595/4616 - PLAIN SASL mechanism.
- * DEFAULT: the same value provided in the username parameter.
- * </pre>
- */
- public function __construct(array $params = array())
- {
- if (!isset($params['username'])) {
- throw new InvalidArgumentException('Horde_Imap_Client requires a username.');
- }
- $this->_setInit();
- // Default values.
- $params = array_merge(array(
- 'context' => array(),
- 'hostspec' => 'localhost',
- 'secure' => false,
- 'timeout' => 30
- ), array_filter($params));
- if (!isset($params['port']) && strpos($params['hostspec'], 'unix://') !== 0) {
- $params['port'] = (!empty($params['secure']) && in_array($params['secure'], array('ssl', 'sslv2', 'sslv3'), true))
- ? $this->_defaultPorts[1]
- : $this->_defaultPorts[0];
- }
- if (empty($params['cache'])) {
- $params['cache'] = array('fields' => array());
- } elseif (empty($params['cache']['fields'])) {
- $params['cache']['fields'] = $this->cacheFields;
- } else {
- $params['cache']['fields'] = array_flip($params['cache']['fields']);
- }
- if (empty($params['cache']['fetch_ignore'])) {
- $params['cache']['fetch_ignore'] = array();
- }
- $this->_params = $params;
- if (isset($params['password'])) {
- $this->setParam('password', $params['password']);
- }
- $this->changed = true;
- $this->_initOb();
- }
- /**
- * Get encryption key.
- *
- * @deprecated Pass callable into 'password' parameter instead.
- *
- * @return string The encryption key.
- */
- protected function _getEncryptKey()
- {
- if (is_callable($ekey = $this->getParam('encryptKey'))) {
- return call_user_func($ekey);
- }
- throw new InvalidArgumentException('encryptKey parameter is not a valid callback.');
- }
- /**
- * Do initialization tasks.
- */
- protected function _initOb()
- {
- register_shutdown_function(array($this, 'shutdown'));
- $this->_alerts = new Horde_Imap_Client_Base_Alerts();
- // @todo: Remove (BC)
- $this->_alerts->attach($this);
- $this->_debug = ($debug = $this->getParam('debug'))
- ? new Horde_Imap_Client_Base_Debug($debug)
- : new Horde_Support_Stub();
- // @todo: Remove (BC purposes)
- if (isset($this->_init['capability']) &&
- !is_object($this->_init['capability'])) {
- $this->_setInit('capability');
- }
- foreach (array('capability', 'search_charset') as $val) {
- if (isset($this->_init[$val])) {
- $this->_init[$val]->attach($this);
- }
- }
- }
- /**
- * Shutdown actions.
- */
- public function shutdown()
- {
- try {
- $this->logout();
- } catch (Horde_Imap_Client_Exception $e) {
- }
- }
- /**
- * This object can not be cloned.
- */
- public function __clone()
- {
- throw new LogicException('Object cannot be cloned.');
- }
- /**
- */
- public function update(SplSubject $subject)
- {
- if (($subject instanceof Horde_Imap_Client_Data_Capability) ||
- ($subject instanceof Horde_Imap_Client_Data_SearchCharset)) {
- $this->changed = true;
- }
- /* @todo: BC - remove */
- if ($subject instanceof Horde_Imap_Client_Base_Alerts) {
- $this->_temp['alerts'][] = $subject->getLast()->alert;
- }
- }
- /**
- */
- public function serialize()
- {
- return serialize(array(
- 'i' => $this->_init,
- 'p' => $this->_params,
- 'v' => self::VERSION
- ));
- }
- /**
- */
- public function unserialize($data)
- {
- $data = @unserialize($data);
- if (!is_array($data) ||
- !isset($data['v']) ||
- ($data['v'] != self::VERSION)) {
- throw new Exception('Cache version change');
- }
- $this->_init = $data['i'];
- $this->_params = $data['p'];
- $this->_initOb();
- }
- /**
- */
- public function __get($name)
- {
- switch ($name) {
- case 'alerts_ob':
- return $this->_alerts;
- case 'capability':
- return $this->_capability();
- case 'search_charset':
- if (!isset($this->_init['search_charset'])) {
- $this->_init['search_charset'] = new Horde_Imap_Client_Data_SearchCharset();
- $this->_init['search_charset']->attach($this);
- }
- $this->_init['search_charset']->setBaseOb($this);
- return $this->_init['search_charset'];
- case 'url':
- $url = new Horde_Imap_Client_Url();
- $url->hostspec = $this->getParam('hostspec');
- $url->port = $this->getParam('port');
- $url->protocol = 'imap';
- return $url;
- }
- }
- /**
- * Set an initialization value.
- *
- * @param string $key The initialization key. If null, resets all keys.
- * @param mixed $val The cached value. If null, removes the key.
- */
- public function _setInit($key = null, $val = null)
- {
- if (is_null($key)) {
- $this->_init = array();
- } elseif (is_null($val)) {
- unset($this->_init[$key]);
- } else {
- switch ($key) {
- case 'capability':
- if ($ci = $this->getParam('capability_ignore')) {
- $ignored = array();
- foreach ($ci as $val2) {
- $c = explode('=', $val2);
- if ($val->query($c[0], isset($c[1]) ? $c[1] : null)) {
- $ignored[] = $val2;
- $val->remove($c[0], isset($c[1]) ? $c[1] : null);
- }
- }
- if ($this->_debug->debug && !empty($ignored)) {
- $this->_debug->info(sprintf(
- 'CONFIG: IGNORING these IMAP capabilities: %s',
- implode(', ', $ignored)
- ));
- }
- }
- $val->attach($this);
- break;
- }
- /* Nothing has changed. */
- if (isset($this->_init[$key]) && ($this->_init[$key] === $val)) {
- return;
- }
- $this->_init[$key] = $val;
- }
- $this->changed = true;
- }
- /**
- * Initialize the Horde_Imap_Client_Cache object, if necessary.
- *
- * @param boolean $current If true, we are going to update the currently
- * selected mailbox. Add an additional check to
- * see if caching is available in current
- * mailbox.
- *
- * @return boolean Returns true if caching is enabled.
- */
- protected function _initCache($current = false)
- {
- $c = $this->getParam('cache');
- if (empty($c['fields'])) {
- return false;
- }
- if (is_null($this->_cache)) {
- if (isset($c['backend'])) {
- $backend = $c['backend'];
- } elseif (isset($c['cacheob'])) {
- /* Deprecated */
- $backend = new Horde_Imap_Client_Cache_Backend_Cache($c);
- } else {
- return false;
- }
- $this->_cache = new Horde_Imap_Client_Cache(array(
- 'backend' => $backend,
- 'baseob' => $this,
- 'debug' => $this->_debug
- ));
- }
- return $current
- /* If UIDs are labeled as not sticky, don't cache since UIDs will
- * change on every access. */
- ? !($this->_mailboxOb()->getStatus(Horde_Imap_Client::STATUS_UIDNOTSTICKY))
- : true;
- }
- /**
- * Returns a value from the internal params array.
- *
- * @param string $key The param key.
- *
- * @return mixed The param value, or null if not found.
- */
- public function getParam($key)
- {
- /* Passwords may be stored encrypted. */
- switch ($key) {
- case 'password':
- if (isset($this->_params[$key]) &&
- ($this->_params[$key] instanceof Horde_Imap_Client_Base_Password)) {
- return $this->_params[$key]->getPassword();
- }
- // DEPRECATED
- if (!empty($this->_params['_passencrypt'])) {
- try {
- $secret = new Horde_Secret();
- return $secret->read($this->_getEncryptKey(), $this->_params['password']);
- } catch (Exception $e) {
- return null;
- }
- }
- break;
- }
- return isset($this->_params[$key])
- ? $this->_params[$key]
- : null;
- }
- /**
- * Sets a configuration parameter value.
- *
- * @param string $key The param key.
- * @param mixed $val The param value.
- */
- public function setParam($key, $val)
- {
- switch ($key) {
- case 'password':
- if ($val instanceof Horde_Imap_Client_Base_Password) {
- break;
- }
- // DEPRECATED: Encrypt password.
- try {
- $encrypt_key = $this->_getEncryptKey();
- if (strlen($encrypt_key)) {
- $secret = new Horde_Secret();
- $val = $secret->write($encrypt_key, $val);
- $this->_params['_passencrypt'] = true;
- }
- } catch (Exception $e) {}
- break;
- }
- $this->_params[$key] = $val;
- $this->changed = true;
- }
- /**
- * Returns the Horde_Imap_Client_Cache object used, if available.
- *
- * @return mixed Either the cache object or null.
- */
- public function getCache()
- {
- $this->_initCache();
- return $this->_cache;
- }
- /**
- * Returns the correct IDs object for use with this driver.
- *
- * @param mixed $ids Either self::ALL, self::SEARCH_RES, self::LARGEST,
- * Horde_Imap_Client_Ids object, array, or sequence
- * string.
- * @param boolean $sequence Are $ids message sequence numbers?
- *
- * @return Horde_Imap_Client_Ids The IDs object.
- */
- public function getIdsOb($ids = null, $sequence = false)
- {
- return new Horde_Imap_Client_Ids($ids, $sequence);
- }
- /**
- * Returns whether the IMAP server supports the given capability
- * (See RFC 3501 [6.1.1]).
- *
- * @deprecated Use $capability property instead.
- *
- * @param string $capability The capability string to query.
- *
- * @return mixed True if the server supports the queried capability,
- * false if it doesn't, or an array if the capability can
- * contain multiple values.
- */
- public function queryCapability($capability)
- {
- try {
- $c = $this->_capability();
- return ($out = $c->getParams($capability))
- ? $out
- : $c->query($capability);
- } catch (Horde_Imap_Client_Exception $e) {
- return false;
- }
- }
- /**
- * Get CAPABILITY information from the IMAP server.
- *
- * @deprecated Use $capability property instead.
- *
- * @return array The capability array.
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function capability()
- {
- return $this->_capability()->toArray();
- }
- /**
- * Query server capability.
- *
- * Required because internal code can't call capability via magic method
- * directly - it may not exist yet, the creation code may call capability
- * recursively, and __get() doesn't allow recursive calls to the same
- * property (chicken/egg issue).
- *
- * @return mixed The capability object if no arguments provided. If
- * arguments are provided, they are passed to the query()
- * method and this value is returned.
- * @throws Horde_Imap_Client_Exception
- */
- protected function _capability()
- {
- if (!isset($this->_init['capability'])) {
- $this->_initCapability();
- }
- return ($args = func_num_args())
- ? $this->_init['capability']->query(func_get_arg(0), ($args > 1) ? func_get_arg(1) : null)
- : $this->_init['capability'];
- }
- /**
- * Retrieve capability information from the IMAP server.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _initCapability();
- /**
- * Send a NOOP command (RFC 3501 [6.1.2]).
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function noop()
- {
- if (!$this->_connection) {
- // NOOP can be called in the unauthenticated state.
- $this->_connect();
- }
- $this->_noop();
- }
- /**
- * Send a NOOP command.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _noop();
- /**
- * Get the NAMESPACE information from the IMAP server (RFC 2342).
- *
- * @param array $additional If the server supports namespaces, any
- * additional namespaces to add to the
- * namespace list that are not broadcast by
- * the server. The namespaces must be UTF-8
- * strings.
- * @param array $opts Additional options:
- * - ob_return: (boolean) If true, returns a
- * Horde_Imap_Client_Namespace_List object instead of an
- * array.
- *
- * @return mixed A Horde_Imap_Client_Namespace_List object if
- * 'ob_return', is true. Otherwise, an array of namespace
- * objects (@deprecated) with the name as the key (UTF-8)
- * and the following values:
- * <pre>
- * - delimiter: (string) The namespace delimiter.
- * - hidden: (boolean) Is this a hidden namespace?
- * - name: (string) The namespace name (UTF-8).
- * - translation: (string) Returns the translated name of the namespace
- * (UTF-8). Requires RFC 5255 and a previous call to
- * setLanguage().
- * - type: (integer) The namespace type. Either:
- * - Horde_Imap_Client::NS_PERSONAL
- * - Horde_Imap_Client::NS_OTHER
- * - Horde_Imap_Client::NS_SHARED
- * </pre>
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function getNamespaces(
- array $additional = array(), array $opts = array()
- )
- {
- $additional = array_map('strval', $additional);
- $sig = hash(
- 'md5',
- json_encode($additional) . intval(empty($opts['ob_return']))
- );
- if (isset($this->_init['namespace'][$sig])) {
- $ns = $this->_init['namespace'][$sig];
- } else {
- $this->login();
- $ns = $this->_getNamespaces();
- /* Skip namespaces if we have already auto-detected them. Also,
- * hidden namespaces cannot be empty. */
- $to_process = array_diff(array_filter($additional, 'strlen'), array_map('strlen', iterator_to_array($ns)));
- if (!empty($to_process)) {
- foreach ($this->listMailboxes($to_process, Horde_Imap_Client::MBOX_ALL, array('delimiter' => true)) as $key => $val) {
- $ob = new Horde_Imap_Client_Data_Namespace();
- $ob->delimiter = $val['delimiter'];
- $ob->hidden = true;
- $ob->name = $key;
- $ob->type = $ob::NS_SHARED;
- $ns[$val] = $ob;
- }
- }
- if (!count($ns)) {
- /* This accurately determines the namespace information of the
- * base namespace if the NAMESPACE command is not supported.
- * See: RFC 3501 [6.3.8] */
- $mbox = $this->listMailboxes('', Horde_Imap_Client::MBOX_ALL, array('delimiter' => true));
- $first = reset($mbox);
- $ob = new Horde_Imap_Client_Data_Namespace();
- $ob->delimiter = $first['delimiter'];
- $ns[''] = $ob;
- }
- $this->_init['namespace'][$sig] = $ns;
- $this->_setInit('namespace', $this->_init['namespace']);
- }
- if (!empty($opts['ob_return'])) {
- return $ns;
- }
- /* @todo Remove for 3.0 */
- $out = array();
- foreach ($ns as $key => $val) {
- $out[$key] = array(
- 'delimiter' => $val->delimiter,
- 'hidden' => $val->hidden,
- 'name' => $val->name,
- 'translation' => $val->translation,
- 'type' => $val->type
- );
- }
- return $out;
- }
- /**
- * Get the NAMESPACE information from the IMAP server.
- *
- * @return Horde_Imap_Client_Namespace_List Namespace list object.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _getNamespaces();
- /**
- * Display if connection to the server has been secured via TLS or SSL.
- *
- * @return boolean True if the IMAP connection is secured.
- */
- public function isSecureConnection()
- {
- return ($this->_connection && $this->_connection->secure);
- }
- /**
- * Connect to the remote server.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _connect();
- /**
- * Return a list of alerts that MUST be presented to the user (RFC 3501
- * [7.1]).
- *
- * @deprecated Add an observer to the $alerts_ob property instead.
- *
- * @return array An array of alert messages.
- */
- public function alerts()
- {
- $alerts = isset($this->_temp['alerts'])
- ? $this->_temp['alerts']
- : array();
- unset($this->_temp['alerts']);
- return $alerts;
- }
- /**
- * Login to the IMAP server.
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function login()
- {
- if (!$this->_isAuthenticated && $this->_login()) {
- if ($this->getParam('id')) {
- try {
- $this->sendID();
- /* ID is queued - force sending the queued command. */
- $this->_sendCmd($this->_pipeline());
- } catch (Horde_Imap_Client_Exception_NoSupportExtension $e) {
- // Ignore if server doesn't support ID extension.
- }
- }
- if ($this->getParam('comparator')) {
- try {
- $this->setComparator();
- } catch (Horde_Imap_Client_Exception_NoSupportExtension $e) {
- // Ignore if server doesn't support I18NLEVEL=2
- }
- }
- }
- $this->_isAuthenticated = true;
- }
- /**
- * Login to the IMAP server.
- *
- * @return boolean Return true if global login tasks should be run.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _login();
- /**
- * Logout from the IMAP server (see RFC 3501 [6.1.3]).
- */
- public function logout()
- {
- if ($this->_isAuthenticated && $this->_connection->connected) {
- $this->_logout();
- $this->_connection->close();
- }
- $this->_connection = $this->_selected = null;
- $this->_isAuthenticated = false;
- $this->_mode = 0;
- }
- /**
- * Logout from the IMAP server (see RFC 3501 [6.1.3]).
- */
- abstract protected function _logout();
- /**
- * Send ID information to the IMAP server (RFC 2971).
- *
- * @param array $info Overrides the value of the 'id' param and sends
- * this information instead.
- *
- * @throws Horde_Imap_Client_Exception
- * @throws Horde_Imap_Client_Exception_NoSupportExtension
- */
- public function sendID($info = null)
- {
- if (!$this->_capability('ID')) {
- throw new Horde_Imap_Client_Exception_NoSupportExtension('ID');
- }
- $this->_sendID(is_null($info) ? ($this->getParam('id') ?: array()) : $info);
- }
- /**
- * Send ID information to the IMAP server (RFC 2971).
- *
- * @param array $info The information to send to the server.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _sendID($info);
- /**
- * Return ID information from the IMAP server (RFC 2971).
- *
- * @return array An array of information returned, with the keys as the
- * 'field' and the values as the 'value'.
- *
- * @throws Horde_Imap_Client_Exception
- * @throws Horde_Imap_Client_Exception_NoSupportExtension
- */
- public function getID()
- {
- if (!$this->_capability('ID')) {
- throw new Horde_Imap_Client_Exception_NoSupportExtension('ID');
- }
- return $this->_getID();
- }
- /**
- * Return ID information from the IMAP server (RFC 2971).
- *
- * @return array An array of information returned, with the keys as the
- * 'field' and the values as the 'value'.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _getID();
- /**
- * Sets the preferred language for server response messages (RFC 5255).
- *
- * @param array $langs Overrides the value of the 'lang' param and sends
- * this list of preferred languages instead. The
- * special string 'i-default' can be used to restore
- * the language to the server default.
- *
- * @return string The language accepted by the server, or null if the
- * default language is used.
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function setLanguage($langs = null)
- {
- $lang = null;
- if ($this->_capability('LANGUAGE')) {
- $lang = is_null($langs)
- ? $this->getParam('lang')
- : $langs;
- }
- return is_null($lang)
- ? null
- : $this->_setLanguage($lang);
- }
- /**
- * Sets the preferred language for server response messages (RFC 5255).
- *
- * @param array $langs The preferred list of languages.
- *
- * @return string The language accepted by the server, or null if the
- * default language is used.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _setLanguage($langs);
- /**
- * Gets the preferred language for server response messages (RFC 5255).
- *
- * @param array $list If true, return the list of available languages.
- *
- * @return mixed If $list is true, the list of languages available on the
- * server (may be empty). If false, the language used by
- * the server, or null if the default language is used.
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function getLanguage($list = false)
- {
- if (!$this->_capability('LANGUAGE')) {
- return $list ? array() : null;
- }
- return $this->_getLanguage($list);
- }
- /**
- * Gets the preferred language for server response messages (RFC 5255).
- *
- * @param array $list If true, return the list of available languages.
- *
- * @return mixed If $list is true, the list of languages available on the
- * server (may be empty). If false, the language used by
- * the server, or null if the default language is used.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _getLanguage($list);
- /**
- * Open a mailbox.
- *
- * @param mixed $mailbox The mailbox to open. Either a
- * Horde_Imap_Client_Mailbox object or a string
- * (UTF-8).
- * @param integer $mode The access mode. Either
- * - Horde_Imap_Client::OPEN_READONLY
- * - Horde_Imap_Client::OPEN_READWRITE
- * - Horde_Imap_Client::OPEN_AUTO
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function openMailbox($mailbox, $mode = Horde_Imap_Client::OPEN_AUTO)
- {
- $this->login();
- $change = false;
- $mailbox = Horde_Imap_Client_Mailbox::get($mailbox);
- if ($mode == Horde_Imap_Client::OPEN_AUTO) {
- if (is_null($this->_selected) ||
- !$mailbox->equals($this->_selected)) {
- $mode = Horde_Imap_Client::OPEN_READONLY;
- $change = true;
- }
- } else {
- $change = (is_null($this->_selected) ||
- !$mailbox->equals($this->_selected) ||
- ($mode != $this->_mode));
- }
- if ($change) {
- $this->_openMailbox($mailbox, $mode);
- $this->_mailboxOb()->open = true;
- if ($this->_initCache(true)) {
- $this->_condstoreSync();
- }
- }
- }
- /**
- * Open a mailbox.
- *
- * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to open.
- * @param integer $mode The access mode.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _openMailbox(Horde_Imap_Client_Mailbox $mailbox,
- $mode);
- /**
- * Called when the selected mailbox is changed.
- *
- * @param mixed $mailbox The selected mailbox or null.
- * @param integer $mode The access mode.
- */
- protected function _changeSelected($mailbox = null, $mode = null)
- {
- $this->_mode = $mode;
- if (is_null($mailbox)) {
- $this->_selected = null;
- } else {
- $this->_selected = clone $mailbox;
- $this->_mailboxOb()->reset();
- }
- }
- /**
- * Return the Horde_Imap_Client_Base_Mailbox object.
- *
- * @param string $mailbox The mailbox name. Defaults to currently
- * selected mailbox.
- *
- * @return Horde_Imap_Client_Base_Mailbox Mailbox object.
- */
- protected function _mailboxOb($mailbox = null)
- {
- $name = is_null($mailbox)
- ? strval($this->_selected)
- : strval($mailbox);
- if (!isset($this->_temp['mailbox_ob'][$name])) {
- $this->_temp['mailbox_ob'][$name] = new Horde_Imap_Client_Base_Mailbox();
- }
- return $this->_temp['mailbox_ob'][$name];
- }
- /**
- * Return the currently opened mailbox and access mode.
- *
- * @return mixed Null if no mailbox selected, or an array with two
- * elements:
- * - mailbox: (Horde_Imap_Client_Mailbox) The mailbox object.
- * - mode: (integer) Current mode.
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function currentMailbox()
- {
- return is_null($this->_selected)
- ? null
- : array(
- 'mailbox' => clone $this->_selected,
- 'mode' => $this->_mode
- );
- }
- /**
- * Create a mailbox.
- *
- * @param mixed $mailbox The mailbox to create. Either a
- * Horde_Imap_Client_Mailbox object or a string
- * (UTF-8).
- * @param array $opts Additional options:
- * - special_use: (array) An array of special-use flags to mark the
- * mailbox with. The server MUST support RFC 6154.
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function createMailbox($mailbox, array $opts = array())
- {
- $this->login();
- if (!$this->_capability('CREATE-SPECIAL-USE')) {
- unset($opts['special_use']);
- }
- $this->_createMailbox(Horde_Imap_Client_Mailbox::get($mailbox), $opts);
- }
- /**
- * Create a mailbox.
- *
- * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to create.
- * @param array $opts Additional options. See
- * createMailbox().
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _createMailbox(Horde_Imap_Client_Mailbox $mailbox,
- $opts);
- /**
- * Delete a mailbox.
- *
- * @param mixed $mailbox The mailbox to delete. Either a
- * Horde_Imap_Client_Mailbox object or a string
- * (UTF-8).
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function deleteMailbox($mailbox)
- {
- $this->login();
- $mailbox = Horde_Imap_Client_Mailbox::get($mailbox);
- $this->_deleteMailbox($mailbox);
- $this->_deleteMailboxPost($mailbox);
- }
- /**
- * Delete a mailbox.
- *
- * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to delete.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _deleteMailbox(Horde_Imap_Client_Mailbox $mailbox);
- /**
- * Actions to perform after a mailbox delete.
- *
- * @param Horde_Imap_Client_Mailbox $mailbox The deleted mailbox.
- */
- protected function _deleteMailboxPost(Horde_Imap_Client_Mailbox $mailbox)
- {
- /* Delete mailbox caches. */
- if ($this->_initCache()) {
- $this->_cache->deleteMailbox($mailbox);
- }
- unset($this->_temp['mailbox_ob'][strval($mailbox)]);
- /* Unsubscribe from mailbox. */
- try {
- $this->subscribeMailbox($mailbox, false);
- } catch (Horde_Imap_Client_Exception $e) {
- // Ignore failed unsubscribe request
- }
- }
- /**
- * Rename a mailbox.
- *
- * @param mixed $old The old mailbox name. Either a
- * Horde_Imap_Client_Mailbox object or a string (UTF-8).
- * @param mixed $new The new mailbox name. Either a
- * Horde_Imap_Client_Mailbox object or a string (UTF-8).
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function renameMailbox($old, $new)
- {
- // Login will be handled by first listMailboxes() call.
- $old = Horde_Imap_Client_Mailbox::get($old);
- $new = Horde_Imap_Client_Mailbox::get($new);
- /* Check if old mailbox(es) were subscribed to. */
- $base = $this->listMailboxes($old, Horde_Imap_Client::MBOX_SUBSCRIBED, array('delimiter' => true));
- if (empty($base)) {
- $base = $this->listMailboxes($old, Horde_Imap_Client::MBOX_ALL, array('delimiter' => true));
- $base = reset($base);
- $subscribed = array();
- } else {
- $base = reset($base);
- $subscribed = array($base['mailbox']);
- }
- $all_mboxes = array($base['mailbox']);
- if (strlen($base['delimiter'])) {
- $search = $old->list_escape . $base['delimiter'] . '*';
- $all_mboxes = array_merge($all_mboxes, $this->listMailboxes($search, Horde_Imap_Client::MBOX_ALL, array('flat' => true)));
- $subscribed = array_merge($subscribed, $this->listMailboxes($search, Horde_Imap_Client::MBOX_SUBSCRIBED, array('flat' => true)));
- }
- $this->_renameMailbox($old, $new);
- /* Delete mailbox actions. */
- foreach ($all_mboxes as $val) {
- $this->_deleteMailboxPost($val);
- }
- foreach ($subscribed as $val) {
- try {
- $this->subscribeMailbox(new Horde_Imap_Client_Mailbox(substr_replace($val, $new, 0, strlen($old))));
- } catch (Horde_Imap_Client_Exception $e) {
- // Ignore failed subscription requests
- }
- }
- }
- /**
- * Rename a mailbox.
- *
- * @param Horde_Imap_Client_Mailbox $old The old mailbox name.
- * @param Horde_Imap_Client_Mailbox $new The new mailbox name.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _renameMailbox(Horde_Imap_Client_Mailbox $old,
- Horde_Imap_Client_Mailbox $new);
- /**
- * Manage subscription status for a mailbox.
- *
- * @param mixed $mailbox The mailbox to [un]subscribe to. Either a
- * Horde_Imap_Client_Mailbox object or a string
- * (UTF-8).
- * @param boolean $subscribe True to subscribe, false to unsubscribe.
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function subscribeMailbox($mailbox, $subscribe = true)
- {
- $this->login();
- $this->_subscribeMailbox(Horde_Imap_Client_Mailbox::get($mailbox), (bool)$subscribe);
- }
- /**
- * Manage subscription status for a mailbox.
- *
- * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to [un]subscribe
- * to.
- * @param boolean $subscribe True to subscribe, false to
- * unsubscribe.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _subscribeMailbox(Horde_Imap_Client_Mailbox $mailbox,
- $subscribe);
- /**
- * Obtain a list of mailboxes matching a pattern.
- *
- * @param mixed $pattern The mailbox search pattern(s) (see RFC 3501
- * [6.3.8] for the format). A UTF-8 string or an
- * array of strings. If a Horde_Imap_Client_Mailbox
- * object is given, it is escaped (i.e. wildcard
- * patterns are converted to return the miminal
- * number of matches possible).
- * @param integer $mode Which mailboxes to return. Either:
- * - Horde_Imap_Client::MBOX_SUBSCRIBED
- * Return subscribed mailboxes.
- * - Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS
- * Return subscribed mailboxes that exist on the server.
- * - Horde_Imap_Client::MBOX_UNSUBSCRIBED
- * Return unsubscribed mailboxes.
- * - Horde_Imap_Client::MBOX_ALL
- * Return all mailboxes regardless of subscription status.
- * - Horde_Imap_Client::MBOX_ALL_SUBSCRIBED (@since 2.23.0)
- * Return all mailboxes regardless of subscription status, and ensure
- * the '\subscribed' attribute is set if mailbox is subscribed
- * (implies 'attributes' option is true).
- * @param array $options Additional options:
- * <pre>
- * - attributes: (boolean) If true, return attribute information under
- * the 'attributes' key.
- * DEFAULT: Do not return this information.
- * - children: (boolean) Tell server to return children attribute
- * information (\HasChildren, \HasNoChildren). Requires the
- * LIST-EXTENDED extension to guarantee this information is
- * returned. Server MAY return this attribute without this
- * option, or if the CHILDREN extension is available, but it
- * is not guaranteed.
- * DEFAULT: false
- * - flat: (boolean) If true, return a flat list of mailbox names only.
- * Overrides the 'attributes' option.
- * DEFAULT: Do not return flat list.
- * - recursivematch: (boolean) Force the server to return information
- * about parent mailboxes that don't match other
- * selection options, but have some sub-mailboxes that
- * do. Information about children is returned in the
- * CHILDINFO extended data item ('extended'). Requires
- * the LIST-EXTENDED extension.
- * DEFAULT: false
- * - remote: (boolean) Tell server to return mailboxes that reside on
- * another server. Requires the LIST-EXTENDED extension.
- * DEFAULT: false
- * - special_use: (boolean) Tell server to return special-use attribute
- * information (see Horde_Imap_Client SPECIALUSE_*
- * constants). Server must support the SPECIAL-USE return
- * option for this setting to have any effect.
- * DEFAULT: false
- * - status: (integer) Tell server to return status information. The
- * value is a bitmask that may contain any of:
- * - Horde_Imap_Client::STATUS_MESSAGES
- * - Horde_Imap_Client::STATUS_RECENT
- * - Horde_Imap_Client::STATUS_UIDNEXT
- * - Horde_Imap_Client::STATUS_UIDVALIDITY
- * - Horde_Imap_Client::STATUS_UNSEEN
- * - Horde_Imap_Client::STATUS_HIGHESTMODSEQ
- * DEFAULT: 0
- * - sort: (boolean) If true, return a sorted list of mailboxes?
- * DEFAULT: Do not sort the list.
- * - sort_delimiter: (string) If 'sort' is true, this is the delimiter
- * used to sort the mailboxes.
- * DEFAULT: '.'
- * </pre>
- *
- * @return array If 'flat' option is true, the array values are a list
- * of Horde_Imap_Client_Mailbox objects. Otherwise, the
- * keys are UTF-8 mailbox names and the values are arrays
- * with these keys:
- * - attributes: (array) List of lower-cased attributes [only if
- * 'attributes' option is true].
- * - delimiter: (string) The delimiter for the mailbox.
- * - extended: (TODO) TODO [only if 'recursivematch' option is true and
- * LIST-EXTENDED extension is supported on the server].
- * - mailbox: (Horde_Imap_Client_Mailbox) The mailbox object.
- * - status: (array) See status() [only if 'status' option is true].
- *
- * @throws Horde_Imap_Client_Exception
- */
- public function listMailboxes($pattern,
- $mode = Horde_Imap_Client::MBOX_ALL,
- array $options = array())
- {
- $this->login();
- $pattern = is_array($pattern)
- ? array_unique($pattern)
- : array($pattern);
- /* Prepare patterns. */
- $plist = array();
- foreach ($pattern as $val) {
- if ($val instanceof Horde_Imap_Client_Mailbox) {
- $val = $val->list_escape;
- }
- $plist[] = Horde_Imap_Client_Mailbox::get(preg_replace(
- array("/\*{2,}/", "/\%{2,}/"),
- array('*', '%'),
- Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($val)
- ), true);
- }
- if (isset($options['special_use']) &&
- !$this->_capability('SPECIAL-USE')) {
- unset($options['special_use']);
- }
- $ret = $this->_listMailboxes($plist, $mode, $options);
- if (!empty($options['status']) &&
- !$this->_capability('LIST-STATUS')) {
- foreach ($this->status(array_keys($ret), $options['status']) as $key => $val) {
- $ret[$key]['status'] = $val;
- }
- }
- if (empty($options['sort'])) {
- return $ret;
- }
- $list_ob = new Horde_Imap_Client_Mailbox_List(empty($options['flat']) ? array_keys($ret) : $ret);
- $sorted = $list_ob->sort(array(
- 'delimiter' => empty($options['sort_delimiter']) ? '.' : $options['sort_delimiter']
- ));
- if (!empty($options['flat'])) {
- return $sorted;
- }
- $out = array();
- foreach ($sorted as $val) {
- $out[$val] = $ret[$val];
- }
- return $out;
- }
- /**
- * Obtain a list of mailboxes matching a pattern.
- *
- * @param array $pattern The mailbox search patterns
- * (Horde_Imap_Client_Mailbox objects).
- * @param integer $mode Which mailboxes to return.
- * @param array $options Additional options.
- *
- * @return array See listMailboxes().
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _listMailboxes($pattern, $mode, $options);
- /**
- * Obtain status information for a mailbox.
- *
- * @param mixed $mailbox The mailbox(es) to query. Either a
- * Horde_Imap_Client_Mailbox object, a string
- * (UTF-8), or an array of objects/strings (since
- * 2.10.0).
- * @param integer $flags A bitmask of information requested from the
- * server. Allowed flags:
- * <pre>
- * - Horde_Imap_Client::STATUS_MESSAGES
- * Return key: messages
- * Return format: (integer) The number of messages in the mailbox.
- *
- * - Horde_Imap_Client::STATUS_RECENT
- * Return key: recent
- * Return format: (integer) The number of messages with the \Recent
- * flag set as currently reported in the mailbox
- *
- * - Horde_Imap_Client::STATUS_RECENT_TOTAL
- * Return key: recent_total
- * Return format: (integer) The number of messages with the \Recent
- * flag set. This returns the total number of messages
- * that have been marked as recent in this …
Large files files are truncated, but you can click here to view the full file