<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[2318] 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client: Reverted Socket.php, Socket/Pop3.php and Base.php to d5ac35d (before continuations were introduced)</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://gsoc.trac.wordpress.org/changeset/2318">2318</a></dd>
<dt>Author</dt> <dd>codebykat</dd>
<dt>Date</dt> <dd>2013-09-16 02:11:57 +0000 (Mon, 16 Sep 2013)</dd>
</dl>
<h3>Log Message</h3>
<pre>Reverted Socket.php, Socket/Pop3.php and Base.php to d5ac35d (before continuations were introduced)</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#2013codebykatpostbyemailtrunkincludeHordeImapClientBasephp">2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Base.php</a></li>
<li><a href="#2013codebykatpostbyemailtrunkincludeHordeImapClientSocketPop3php">2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Socket/Pop3.php</a></li>
<li><a href="#2013codebykatpostbyemailtrunkincludeHordeImapClientSocketphp">2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Socket.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="2013codebykatpostbyemailtrunkincludeHordeImapClientBasephp"></a>
<div class="modfile"><h4>Modified: 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Base.php (2317 => 2318)</h4>
<pre class="diff"><span>
<span class="info">--- 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Base.php 2013-09-16 02:11:45 UTC (rev 2317)
+++ 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Base.php 2013-09-16 02:11:57 UTC (rev 2318)
</span><span class="lines">@@ -32,9 +32,6 @@
</span><span class="cx"> /* @since 2.9.0 */
</span><span class="cx"> const CACHE_SEARCHID = '_i';
</span><span class="cx">
</span><del>- /* Cache names used exclusively within this class. @since 2.11.0 */
- const CACHE_DOWNGRADED = 'HICdg';
-
</del><span class="cx"> /**
</span><span class="cx"> * The list of fetch fields that can be cached, and their cache names.
</span><span class="cx"> *
</span><span class="lines">@@ -57,19 +54,6 @@
</span><span class="cx"> public $changed = false;
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * 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;
-
- /**
</del><span class="cx"> * The Horde_Imap_Client_Cache object.
</span><span class="cx"> *
</span><span class="cx"> * @var Horde_Imap_Client_Cache
</span><span class="lines">@@ -77,13 +61,6 @@
</span><span class="cx"> protected $_cache = null;
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Connection to the IMAP server.
- *
- * @var Horde_Imap_Client_Base_Connection
- */
- protected $_connection = null;
-
- /**
</del><span class="cx"> * The debug object.
</span><span class="cx"> *
</span><span class="cx"> * @var Horde_Imap_Client_Base_Debug
</span><span class="lines">@@ -91,14 +68,6 @@
</span><span class="cx"> protected $_debug = null;
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * The default ports to use for a connection.
- * First element is non-secure, second is SSL.
- *
- * @var array
- */
- protected $_defaultPorts = array();
-
- /**
</del><span class="cx"> * The fetch data object type to return.
</span><span class="cx"> *
</span><span class="cx"> * @var string
</span><span class="lines">@@ -120,6 +89,13 @@
</span><span class="cx"> protected $_isAuthenticated = false;
</span><span class="cx">
</span><span class="cx"> /**
</span><ins>+ * Is there a secure connection to the IMAP Server?
+ *
+ * @var boolean
+ */
+ protected $_isSecure = false;
+
+ /**
</ins><span class="cx"> * The current mailbox selection mode.
</span><span class="cx"> *
</span><span class="cx"> * @var integer
</span><span class="lines">@@ -146,9 +122,7 @@
</span><span class="cx"> *
</span><span class="cx"> * @var array
</span><span class="cx"> */
</span><del>- protected $_temp = array(
- 'enabled' => array()
- );
</del><ins>+ protected $_temp = array();
</ins><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Constructor.
</span><span class="lines">@@ -157,9 +131,7 @@
</span><span class="cx"> * <ul>
</span><span class="cx"> * <li>REQUIRED Parameters
</span><span class="cx"> * <ul>
</span><del>- * <li>password: (mixed) The IMAP user password. Either a string or
- * a Horde_Imap_Client_Base_Password object (since
- * 2.14.0).</li>
</del><ins>+ * <li>password: (string) The IMAP user password.</li>
</ins><span class="cx"> * <li>username: (string) The IMAP username.</li>
</span><span class="cx"> * </ul>
</span><span class="cx"> * </li>
</span><span class="lines">@@ -176,6 +148,10 @@
</span><span class="cx"> * Backend cache driver (as of 2.9.0).
</span><span class="cx"> * </li>
</span><span class="cx"> * <li>
</span><ins>+ * cacheob: [REQUIRED (or backend)] (Horde_Cache) The cache object to
+ * use (DEPRECATED).
+ * </li>
+ * <li>
</ins><span class="cx"> * fetch_ignore: (array) A list of mailboxes to ignore when storing
</span><span class="cx"> * fetch data.
</span><span class="cx"> * </li>
</span><span class="lines">@@ -224,6 +200,12 @@
</span><span class="cx"> * DEFAULT: No debug output
</span><span class="cx"> * </li>
</span><span class="cx"> * <li>
</span><ins>+ * encryptKey: (array) A callback to a function that returns the key
+ * used to encrypt the password. This function MUST be
+ * static.
+ * DEFAULT: No encryption
+ * </li>
+ * <li>
</ins><span class="cx"> * hostspec: (string) The hostname or IP address of the server.
</span><span class="cx"> * DEFAULT: 'localhost'
</span><span class="cx"> * </li>
</span><span class="lines">@@ -247,14 +229,13 @@
</span><span class="cx"> * secure: (string) Use SSL or TLS to connect.
</span><span class="cx"> * VALUES:
</span><span class="cx"> * <ul>
</span><del>- * <li>false (No encryption)</li>
</del><ins>+ * <li>false</li>
</ins><span class="cx"> * <li>'ssl' (Auto-detect SSL version)</li>
</span><span class="cx"> * <li>'sslv2' (Force SSL version 3)</li>
</span><span class="cx"> * <li>'sslv3' (Force SSL version 2)</li>
</span><del>- * <li>'tls' (TLS)</li>
- * <li>true (TLS if available/necessary) [since 2.15.0]</li>
</del><ins>+ * <li>'tls'</li>
</ins><span class="cx"> * </ul>
</span><del>- * DEFAULT: false</li>
</del><ins>+ * DEFAULT: No encryption</li>
</ins><span class="cx"> * </li>
</span><span class="cx"> * <li>
</span><span class="cx"> * timeout: (integer) Connection timeout, in seconds.
</span><span class="lines">@@ -280,10 +261,14 @@
</span><span class="cx"> 'timeout' => 30
</span><span class="cx"> ), array_filter($params));
</span><span class="cx">
</span><ins>+ if ($params['secure'] === true) {
+ $params['secure'] = 'tls';
+ }
+
</ins><span class="cx"> if (!isset($params['port'])) {
</span><del>- $params['port'] = (!empty($params['secure']) && in_array($params['secure'], array('ssl', 'sslv2', 'sslv3'), true))
- ? $this->_defaultPorts[1]
- : $this->_defaultPorts[0];
</del><ins>+ $params['port'] = (isset($params['secure']) && in_array($params['secure'], array('ssl', 'sslv2', 'sslv3')))
+ ? 993
+ : 143;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (empty($params['cache'])) {
</span><span class="lines">@@ -299,7 +284,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> $this->_params = $params;
</span><del>- $this->setParam('password', $params['password']);
</del><ins>+ $this->setParam('password', $this->_params['password']);
</ins><span class="cx">
</span><span class="cx"> $this->changed = true;
</span><span class="cx"> $this->_initOb();
</span><span class="lines">@@ -308,14 +293,12 @@
</span><span class="cx"> /**
</span><span class="cx"> * Get encryption key.
</span><span class="cx"> *
</span><del>- * @deprecated Pass callable into 'password' parameter instead.
- *
</del><span class="cx"> * @return string The encryption key.
</span><span class="cx"> */
</span><span class="cx"> protected function _getEncryptKey()
</span><span class="cx"> {
</span><del>- if (is_callable($ekey = $this->getParam('encryptKey'))) {
- return call_user_func($ekey);
</del><ins>+ if (is_callable($this->_params['encryptKey'])) {
+ return call_user_func($this->_params['encryptKey']);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> throw new InvalidArgumentException('encryptKey parameter is not a valid callback.');
</span><span class="lines">@@ -327,9 +310,9 @@
</span><span class="cx"> protected function _initOb()
</span><span class="cx"> {
</span><span class="cx"> register_shutdown_function(array($this, 'shutdown'));
</span><del>- $this->_debug = ($debug = $this->getParam('debug'))
- ? new Horde_Imap_Client_Base_Debug($debug)
- : new Horde_Support_Stub();
</del><ins>+ $this->_debug = empty($this->_params['debug'])
+ ? new Horde_Support_Stub()
+ : new Horde_Imap_Client_Base_Debug($this->_params['debug']);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -386,6 +369,7 @@
</span><span class="cx"> {
</span><span class="cx"> if (is_null($key)) {
</span><span class="cx"> $this->_init = array(
</span><ins>+ 'enabled' => array(),
</ins><span class="cx"> 'namespace' => array(),
</span><span class="cx"> 's_charset' => array()
</span><span class="cx"> );
</span><span class="lines">@@ -394,13 +378,13 @@
</span><span class="cx"> } else {
</span><span class="cx"> switch ($key) {
</span><span class="cx"> case 'capability':
</span><del>- if ($ci = $this->getParam('capability_ignore')) {
</del><ins>+ if (!empty($this->_params['capability_ignore'])) {
</ins><span class="cx"> if ($this->_debug->debug &&
</span><del>- ($ignored = array_intersect_key($val, array_flip($ci)))) {
</del><ins>+ ($ignored = array_intersect_key($val, array_flip($this->_params['capability_ignore'])))) {
</ins><span class="cx"> $this->_debug->info(sprintf("CONFIG: IGNORING these IMAP capabilities: %s", implode(', ', array_keys($ignored))));
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $val = array_diff_key($val, array_flip($ci));
</del><ins>+ $val = array_diff_key($val, array_flip($this->_params['capability_ignore']));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /* RFC 5162 [1] - QRESYNC implies CONDSTORE and ENABLE, even
</span><span class="lines">@@ -410,54 +394,22 @@
</span><span class="cx"> $val['ENABLE'] = true;
</span><span class="cx"> }
</span><span class="cx"> break;
</span><del>- }
</del><span class="cx">
</span><del>- /* Nothing has changed. */
- if (isset($this->_init[$key]) && ($this->_init[$key] == $val)) {
- return;
</del><ins>+ case 'enabled':
+ /* RFC 5162 [1] - Enabling QRESYNC also implies enabling of
+ * CONDSTORE. */
+ if (isset($val['QRESYNC'])) {
+ $val['CONDSTORE'] = true;
+ }
+ break;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> $this->_init[$key] = $val;
</span><span class="cx"> }
</span><del>-
</del><span class="cx"> $this->changed = true;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Set the list of enabled extensions.
- *
- * @param array $exts The list of extensions.
- * @param integer $status 1 means to report as ENABLED, although it has
- * not been formally enabled on server yet. 2 is
- * verified enabled on the server.
- */
- protected function _enabled($exts, $status)
- {
- /* RFC 5162 [1] - Enabling QRESYNC also implies enabling of
- * CONDSTORE. */
- if (in_array('QRESYNC', $exts)) {
- $exts[] = 'CONDSTORE';
- }
-
- switch ($status) {
- case 2:
- $enabled_list = array_intersect(array(2), $this->_temp['enabled']);
- break;
-
- case 1:
- default:
- $enabled_list = $this->_temp['enabled'];
- $status = 1;
- break;
- }
-
- $this->_temp['enabled'] = array_merge(
- $enabled_list,
- array_fill_keys($exts, $status)
- );
- }
-
- /**
</del><span class="cx"> * Initialize the Horde_Imap_Client_Cache object, if necessary.
</span><span class="cx"> *
</span><span class="cx"> * @param boolean $current If true, we are going to update the currently
</span><span class="lines">@@ -469,13 +421,13 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _initCache($current = false)
</span><span class="cx"> {
</span><del>- $c = $this->getParam('cache');
-
- if (empty($c['fields'])) {
</del><ins>+ if (empty($this->_params['cache']['fields'])) {
</ins><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (is_null($this->_cache)) {
</span><ins>+ $c = $this->getParam('cache');
+
</ins><span class="cx"> if (isset($c['backend']) &&
</span><span class="cx"> ($c['backend'] instanceof Horde_Imap_Client_Cache_Backend)) {
</span><span class="cx"> $backend = $c['backend'];
</span><span class="lines">@@ -510,22 +462,13 @@
</span><span class="cx"> public function getParam($key)
</span><span class="cx"> {
</span><span class="cx"> /* Passwords may be stored encrypted. */
</span><del>- switch ($key) {
- case 'password':
- if ($this->_params[$key] instanceof Horde_Imap_Client_Base_Password) {
- return $this->_params[$key]->getPassword();
</del><ins>+ if (($key == 'password') && !empty($this->_params['_passencrypt'])) {
+ try {
+ $secret = new Horde_Secret();
+ return $secret->read($this->_getEncryptKey(), $this->_params['password']);
+ } catch (Exception $e) {
+ return null;
</ins><span class="cx"> }
</span><del>-
- // 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;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return isset($this->_params[$key])
</span><span class="lines">@@ -543,11 +486,7 @@
</span><span class="cx"> {
</span><span class="cx"> switch ($key) {
</span><span class="cx"> case 'password':
</span><del>- if ($val instanceof Horde_Imap_Client_Base_Password) {
- break;
- }
-
- // DEPRECATED: Encrypt password.
</del><ins>+ // Encrypt password.
</ins><span class="cx"> try {
</span><span class="cx"> $encrypt_key = $this->_getEncryptKey();
</span><span class="cx"> if (strlen($encrypt_key)) {
</span><span class="lines">@@ -555,7 +494,9 @@
</span><span class="cx"> $val = $secret->write($encrypt_key, $val);
</span><span class="cx"> $this->_params['_passencrypt'] = true;
</span><span class="cx"> }
</span><del>- } catch (Exception $e) {}
</del><ins>+ } catch (Exception $e) {
+ $this->_params['_passencrypt'] = false;
+ }
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -599,10 +540,12 @@
</span><span class="cx"> */
</span><span class="cx"> public function queryCapability($capability)
</span><span class="cx"> {
</span><del>- try {
- $this->capability();
- } catch (Horde_Imap_Client_Exception $e) {
- return false;
</del><ins>+ if (!isset($this->_init['capability'])) {
+ try {
+ $this->capability();
+ } catch (Horde_Imap_Client_Exception $e) {
+ return false;
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> $capability = strtoupper($capability);
</span><span class="lines">@@ -633,15 +576,17 @@
</span><span class="cx"> public function capability()
</span><span class="cx"> {
</span><span class="cx"> if (!isset($this->_init['capability'])) {
</span><del>- $this->_capability();
</del><ins>+ $this->_setInit('capability', $this->_capability());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return $this->_init['capability'];
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Retrieve CAPABILITY information from the IMAP server.
</del><ins>+ * Get CAPABILITY information from the IMAP server.
</ins><span class="cx"> *
</span><ins>+ * @return array The capability array.
+ *
</ins><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><span class="cx"> abstract protected function _capability();
</span><span class="lines">@@ -710,13 +655,19 @@
</span><span class="cx">
</span><span class="cx"> $ns = $this->_getNamespaces();
</span><span class="cx">
</span><del>- /* Skip namespaces if we have already auto-detected them. Also, hidden
- * namespaces cannot be empty. */
- $to_process = array_diff(array_filter($additional, 'strlen'), array_keys($ns));;
- if (!empty($to_process)) {
- foreach ($this->listMailboxes($to_process, Horde_Imap_Client::MBOX_ALL, array('delimiter' => true)) as $val) {
</del><ins>+ foreach ($additional as $val) {
+ /* Skip namespaces if we have already auto-detected them. Also,
+ * hidden namespaces cannot be empty. */
+ if (!strlen($val) || isset($ns[$val])) {
+ continue;
+ }
+
+ $mbox = $this->listMailboxes($val, Horde_Imap_Client::MBOX_ALL, array('delimiter' => true));
+ $first = reset($mbox);
+
+ if ($first && ($first['mailbox'] == $val)) {
</ins><span class="cx"> $ns[$val] = array(
</span><del>- 'delimiter' => $val['delimiter'],
</del><ins>+ 'delimiter' => $first['delimiter'],
</ins><span class="cx"> 'hidden' => true,
</span><span class="cx"> 'name' => $val,
</span><span class="cx"> 'translation' => '',
</span><span class="lines">@@ -762,17 +713,10 @@
</span><span class="cx"> */
</span><span class="cx"> public function isSecureConnection()
</span><span class="cx"> {
</span><del>- return ($this->_connection && $this->_connection->secure);
</del><ins>+ return $this->_isSecure;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Connect to the remote server.
- *
- * @throws Horde_Imap_Client_Exception
- */
- abstract protected function _connect();
-
- /**
</del><span class="cx"> * Return a list of alerts that MUST be presented to the user (RFC 3501
</span><span class="cx"> * [7.1]).
</span><span class="cx"> *
</span><span class="lines">@@ -787,8 +731,12 @@
</span><span class="cx"> */
</span><span class="cx"> public function login()
</span><span class="cx"> {
</span><del>- if (!$this->_isAuthenticated && $this->_login()) {
- if ($this->getParam('id')) {
</del><ins>+ if ($this->_isAuthenticated) {
+ return;
+ }
+
+ if ($this->_login()) {
+ if (!empty($this->_params['id'])) {
</ins><span class="cx"> try {
</span><span class="cx"> $this->sendID();
</span><span class="cx"> } catch (Horde_Imap_Client_Exception_NoSupportExtension $e) {
</span><span class="lines">@@ -796,7 +744,7 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if ($this->getParam('comparator')) {
</del><ins>+ if (!empty($this->_params['comparator'])) {
</ins><span class="cx"> try {
</span><span class="cx"> $this->setComparator();
</span><span class="cx"> } catch (Horde_Imap_Client_Exception_NoSupportExtension $e) {
</span><span class="lines">@@ -822,13 +770,11 @@
</span><span class="cx"> */
</span><span class="cx"> public function logout()
</span><span class="cx"> {
</span><del>- if ($this->_isAuthenticated && $this->_connection->connected) {
</del><ins>+ if ($this->_isAuthenticated) {
</ins><span class="cx"> $this->_logout();
</span><del>- $this->_connection->close();
</del><ins>+ $this->_isAuthenticated = false;
</ins><span class="cx"> }
</span><del>-
- $this->_connection = $this->_selected = null;
- $this->_isAuthenticated = false;
</del><ins>+ $this->_selected = null;
</ins><span class="cx"> $this->_mode = 0;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -852,7 +798,7 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_NoSupportExtension('ID');
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $this->_sendID(is_null($info) ? ($this->getParam('id') ?: array()) : $info);
</del><ins>+ $this->_sendID(is_null($info) ? (empty($this->_params['id']) ? array() : $this->_params['id']) : $info);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -911,7 +857,7 @@
</span><span class="cx">
</span><span class="cx"> if ($this->queryCapability('LANGUAGE')) {
</span><span class="cx"> $lang = is_null($langs)
</span><del>- ? $this->getParam('lang')
</del><ins>+ ? (empty($this->_params['lang']) ? null : $this->_params['lang'])
</ins><span class="cx"> : $langs;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1380,7 +1326,8 @@
</span><span class="cx">
</span><span class="cx"> if (!empty($options['status']) &&
</span><span class="cx"> !$this->queryCapability('LIST-STATUS')) {
</span><del>- foreach ($this->status(array_keys($ret), $options['status']) as $key => $val) {
</del><ins>+ $status = $this->statusMultiple($this->_selected, $options['status']);
+ foreach ($status as $key => $val) {
</ins><span class="cx"> $ret[$key]['status'] = $val;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -1423,10 +1370,9 @@
</span><span class="cx"> /**
</span><span class="cx"> * Obtain status information for a mailbox.
</span><span class="cx"> *
</span><del>- * @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).
</del><ins>+ * @param mixed $mailbox The mailbox to query. Either a
+ * Horde_Imap_Client_Mailbox object or a string
+ * (UTF-8).
</ins><span class="cx"> * @param integer $flags A bitmask of information requested from the
</span><span class="cx"> * server. Allowed flags:
</span><span class="cx"> * <ul>
</span><span class="lines">@@ -1449,25 +1395,11 @@
</span><span class="cx"> * </li>
</span><span class="cx"> * <li>
</span><span class="cx"> * Return format: (integer) The number of messages with the \Recent
</span><del>- * flag set as currently reported in the mailbox
</del><ins>+ * flag set
</ins><span class="cx"> * </li>
</span><span class="cx"> * </ul>
</span><span class="cx"> * </li>
</span><span class="cx"> * <li>
</span><del>- * Horde_Imap_Client::STATUS_RECENT_TOTAL
- * <ul>
- * <li>
- * Return key: recent_total
- * </li>
- * <li>
- * 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 mailbox since the PHP process began.
- * (since 2.12.0)
- * </li>
- * </ul>
- * </li>
- * <li>
</del><span class="cx"> * Horde_Imap_Client::STATUS_UIDNEXT
</span><span class="cx"> * <ul>
</span><span class="cx"> * <li>
</span><span class="lines">@@ -1626,19 +1558,6 @@
</span><span class="cx"> * </ul>
</span><span class="cx"> * </li>
</span><span class="cx"> * <li>
</span><del>- * Horde_Imap_Client::STATUS_FORCE_REFRESH
- * <ul>
- * <li>
- * Normally, the status information will be cached for a given
- * mailbox. Since most PHP requests are generally less than a second,
- * this is fine. However, if your script is long running, the status
- * information may not be up-to-date. Specifying this flag will ensure
- * that the server is always polled for the current mailbox status
- * before results are returned. (since 2.14.0)
- * </li>
- * </ul>
- * </li>
- * <li>
</del><span class="cx"> * Horde_Imap_Client::STATUS_ALL (DEFAULT)
</span><span class="cx"> * <ul>
</span><span class="cx"> * <li>
</span><span class="lines">@@ -1648,201 +1567,95 @@
</span><span class="cx"> * </ul>
</span><span class="cx"> * </li>
</span><span class="cx"> * </ul>
</span><del>- * @param array $opts Additional options:
- * - sort: (boolean) If true, sort the list of mailboxes? (since 2.10.0)
- * DEFAULT: Do not sort the list.
- * - sort_delimiter: (string) If 'sort' is true, this is the delimiter
- * used to sort the mailboxes. (since 2.10.0)
- * DEFAULT: '.'
</del><span class="cx"> *
</span><del>- * @return array If $mailbox contains multiple mailboxes, an array with
- * keys being the UTF-8 mailbox name and values as arrays
- * containing the requested keys (see above).
- * Otherwise, an array with keys as the requested keys (see
- * above) and values as the key data.
</del><ins>+ * @return array An array with the requested keys (see above).
</ins><span class="cx"> *
</span><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><del>- public function status($mailbox, $flags = Horde_Imap_Client::STATUS_ALL,
- array $opts = array())
</del><ins>+ public function status($mailbox, $flags = Horde_Imap_Client::STATUS_ALL)
</ins><span class="cx"> {
</span><del>- $opts = array_merge(array(
- 'sort' => false,
- 'sort_delimiter' => '.'
- ), $opts);
-
</del><span class="cx"> $this->login();
</span><span class="cx">
</span><del>- if (is_array($mailbox)) {
- if (empty($mailbox)) {
- return array();
- }
- $ret_array = true;
- } else {
- $mailbox = array($mailbox);
- $ret_array = false;
- }
-
- $mlist = array_map(array('Horde_Imap_Client_Mailbox', 'get'), $mailbox);
-
</del><span class="cx"> $unselected_flags = array(
</span><span class="cx"> 'messages' => Horde_Imap_Client::STATUS_MESSAGES,
</span><span class="cx"> 'recent' => Horde_Imap_Client::STATUS_RECENT,
</span><ins>+ 'unseen' => Horde_Imap_Client::STATUS_UNSEEN,
</ins><span class="cx"> 'uidnext' => Horde_Imap_Client::STATUS_UIDNEXT,
</span><del>- 'uidvalidity' => Horde_Imap_Client::STATUS_UIDVALIDITY,
- 'unseen' => Horde_Imap_Client::STATUS_UNSEEN
</del><ins>+ 'uidvalidity' => Horde_Imap_Client::STATUS_UIDVALIDITY
</ins><span class="cx"> );
</span><span class="cx">
</span><del>- if (!$this->statuscache) {
- $flags |= Horde_Imap_Client::STATUS_FORCE_REFRESH;
- }
-
</del><span class="cx"> if ($flags & Horde_Imap_Client::STATUS_ALL) {
</span><span class="cx"> foreach ($unselected_flags as $val) {
</span><span class="cx"> $flags |= $val;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $master = $ret = array();
</del><ins>+ $mailbox = Horde_Imap_Client_Mailbox::get($mailbox);
+ $ret = array();
</ins><span class="cx">
</span><span class="cx"> /* Catch flags that are not supported. */
</span><span class="cx"> if (($flags & Horde_Imap_Client::STATUS_HIGHESTMODSEQ) &&
</span><del>- !isset($this->_temp['enabled']['CONDSTORE'])) {
- $master['highestmodseq'] = 0;
</del><ins>+ !isset($this->_init['enabled']['CONDSTORE'])) {
+ $ret['highestmodseq'] = 0;
</ins><span class="cx"> $flags &= ~Horde_Imap_Client::STATUS_HIGHESTMODSEQ;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY) &&
</span><span class="cx"> !$this->queryCapability('UIDPLUS')) {
</span><del>- $master['uidnotsticky'] = false;
</del><ins>+ $ret['uidnotsticky'] = false;
</ins><span class="cx"> $flags &= ~Horde_Imap_Client::STATUS_UIDNOTSTICKY;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- /* UIDNEXT return options. */
- if ($flags & Horde_Imap_Client::STATUS_UIDNEXT_FORCE) {
- $flags |= Horde_Imap_Client::STATUS_UIDNEXT;
</del><ins>+ /* Handle SYNC related return options. These require the mailbox
+ * to be opened at least once. */
+ if ($flags & Horde_Imap_Client::STATUS_SYNCMODSEQ) {
+ $this->openMailbox($mailbox);
+ $ret['syncmodseq'] = $this->_mailboxOb($mailbox)->getStatus(Horde_Imap_Client::STATUS_SYNCMODSEQ);
+ $flags &= ~Horde_Imap_Client::STATUS_SYNCMODSEQ;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- foreach ($mlist as $val) {
- $name = strval($val);
- $tmp_flags = $flags;
</del><ins>+ if ($flags & Horde_Imap_Client::STATUS_SYNCFLAGUIDS) {
+ $this->openMailbox($mailbox);
+ $ret['syncflaguids'] = $this->getIdsOb($this->_mailboxOb($mailbox)->getStatus(Horde_Imap_Client::STATUS_SYNCFLAGUIDS));
+ $flags &= ~Horde_Imap_Client::STATUS_SYNCFLAGUIDS;
+ }
</ins><span class="cx">
</span><del>- if ($val->equals($this->_selected)) {
- /* Check if already in mailbox. */
- $opened = true;
-
- if ($flags & Horde_Imap_Client::STATUS_FORCE_REFRESH) {
- $this->noop();
- }
- } else {
- /* A list of STATUS options (other than those handled directly
- * below) that require the mailbox to be explicitly opened. */
- $opened = ($flags & Horde_Imap_Client::STATUS_FIRSTUNSEEN) ||
- ($flags & Horde_Imap_Client::STATUS_FLAGS) ||
- ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) ||
- ($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY) ||
- /* Force mailboxes containing wildcards to be accessed via
- * STATUS so that wildcards do not return a bunch of
- * mailboxes in the LIST-STATUS response. */
- (strpbrk($name, '*%') !== false);
- }
-
- $ret[$name] = $master;
- $ptr = &$ret[$name];
-
- /* STATUS_PERMFLAGS requires a read/write mailbox. */
- if ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) {
- $this->openMailbox($val, Horde_Imap_Client::OPEN_READWRITE);
- $opened = true;
- }
-
- /* Handle SYNC related return options. These require the mailbox
- * to be opened at least once. */
- if ($flags & Horde_Imap_Client::STATUS_SYNCMODSEQ) {
- $this->openMailbox($val);
- $ptr['syncmodseq'] = $this->_mailboxOb($val)->getStatus(Horde_Imap_Client::STATUS_SYNCMODSEQ);
- $tmp_flags &= ~Horde_Imap_Client::STATUS_SYNCMODSEQ;
- $opened = true;
- }
-
- if ($flags & Horde_Imap_Client::STATUS_SYNCFLAGUIDS) {
- $this->openMailbox($val);
- $ptr['syncflaguids'] = $this->getIdsOb($this->_mailboxOb($val)->getStatus(Horde_Imap_Client::STATUS_SYNCFLAGUIDS));
- $tmp_flags &= ~Horde_Imap_Client::STATUS_SYNCFLAGUIDS;
- $opened = true;
- }
-
- if ($flags & Horde_Imap_Client::STATUS_SYNCVANISHED) {
- $this->openMailbox($val);
- $ptr['syncvanished'] = $this->getIdsOb($this->_mailboxOb($val)->getStatus(Horde_Imap_Client::STATUS_SYNCVANISHED));
- $tmp_flags &= ~Horde_Imap_Client::STATUS_SYNCVANISHED;
- $opened = true;
- }
-
- /* Handle RECENT_TOTAL option. */
- if ($flags & Horde_Imap_Client::STATUS_RECENT_TOTAL) {
- $this->openMailbox($val);
- $ptr['recent_total'] = $this->_mailboxOb($val)->getStatus(Horde_Imap_Client::STATUS_RECENT_TOTAL);
- $tmp_flags &= ~Horde_Imap_Client::STATUS_RECENT_TOTAL;
- $opened = true;
- }
-
- if ($opened) {
- if ($tmp_flags) {
- $tmp = $this->_status(array($val), $tmp_flags);
- $ptr += reset($tmp);
- }
- } else {
- $to_process[] = $val;
- }
</del><ins>+ if ($flags & Horde_Imap_Client::STATUS_SYNCVANISHED) {
+ $this->openMailbox($mailbox);
+ $ret['syncvanished'] = $this->getIdsOb($this->_mailboxOb($mailbox)->getStatus(Horde_Imap_Client::STATUS_SYNCVANISHED));
+ $flags &= ~Horde_Imap_Client::STATUS_SYNCVANISHED;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- if ($flags && !empty($to_process)) {
- if ((count($to_process) > 1) &&
- $this->queryCapability('LIST-STATUS')) {
- foreach ($this->listMailboxes($to_process, Horde_Imap_Client::MBOX_ALL, array('status' => $flags)) as $key => $val) {
- if (isset($val['status'])) {
- $ret[$key] += $val['status'];
- }
- }
- } else {
- foreach ($this->_status($to_process, $flags) as $key => $val) {
- $ret[$key] += $val;
- }
- }
</del><ins>+ /* UIDNEXT return options. */
+ if ($flags & Horde_Imap_Client::STATUS_UIDNEXT_FORCE) {
+ $flags |= Horde_Imap_Client::STATUS_UIDNEXT;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- if (!$opts['sort'] || (count($ret) == 1)) {
- return $ret_array
- ? $ret
- : reset($ret);
</del><ins>+ if (!$flags) {
+ return $ret;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- $list_ob = new Horde_Imap_Client_Mailbox_List(array_keys($ret));
- $sorted = $list_ob->sort(array(
- 'delimiter' => $opts['sort_delimiter']
- ));
-
- $out = array();
- foreach ($sorted as $val) {
- $out[$val] = $ret[$val];
</del><ins>+ /* STATUS_PERMFLAGS requires a read/write mailbox. */
+ if ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) {
+ $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_READWRITE);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return $out;
</del><ins>+ return array_merge($ret, $this->_status($mailbox, $flags));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Obtain status information for mailboxes.
</del><ins>+ * Obtain status information for a mailbox.
</ins><span class="cx"> *
</span><del>- * @param array $mboxes The list of mailbox objects to query.
- * @param integer $flags A bitmask of information requested from the
- * server.
</del><ins>+ * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to query.
+ * @param integer $flags A bitmask of information
+ * requested from the server.
</ins><span class="cx"> *
</span><del>- * @return array See array return for status().
</del><ins>+ * @return array See status().
</ins><span class="cx"> *
</span><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><del>- abstract protected function _status($mboxes, $flags);
</del><ins>+ abstract protected function _status(Horde_Imap_Client_Mailbox $mailbox,
+ $flags);
</ins><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Perform a STATUS call on multiple mailboxes at the same time.
</span><span class="lines">@@ -1850,8 +1663,6 @@
</span><span class="cx"> * This method leverages the LIST-EXTENDED and LIST-STATUS extensions on
</span><span class="cx"> * the IMAP server to improve the efficiency of this operation.
</span><span class="cx"> *
</span><del>- * @deprecated Use status() instead.
- *
</del><span class="cx"> * @param array $mailboxes The mailboxes to query. Either
</span><span class="cx"> * Horde_Imap_Client_Mailbox objects, strings
</span><span class="cx"> * (UTF-8), or a combination of the two.
</span><span class="lines">@@ -1871,7 +1682,76 @@
</span><span class="cx"> $flags = Horde_Imap_Client::STATUS_ALL,
</span><span class="cx"> array $opts = array())
</span><span class="cx"> {
</span><del>- return $this->status($mailboxes, $flags, $opts);
</del><ins>+ if (empty($mailboxes)) {
+ return array();
+ }
+
+ $this->login();
+
+ $opts = array_merge(array(
+ 'sort' => false,
+ 'sort_delimiter' => '.'
+ ), $opts);
+
+ $need_status = true;
+ $ret = array();
+
+ /* Optimization: If there is one mailbox in list, and we are already
+ * in that mailbox, we should just do a straight STATUS call. */
+ if ($this->queryCapability('LIST-STATUS') &&
+ ((count($mailboxes) != 1) ||
+ !Horde_Imap_Client_Mailbox::get(reset($mailboxes))->equals($this->_selected))) {
+ $status = $to_process = array();
+ foreach ($mailboxes as $val) {
+ // Force mailboxes containing wildcards to be accessed via
+ // STATUS so that wildcards do not return a bunch of mailboxes
+ // in the LIST-STATUS response.
+ if (strpbrk($val, '*%') === false) {
+ $to_process[] = $val;
+ }
+ $status[strval($val)] = 1;
+ }
+
+ try {
+ foreach ($this->listMailboxes($to_process, Horde_Imap_Client::MBOX_ALL, array_merge($opts, array('status' => $flags))) as $val) {
+ if (isset($val['status'])) {
+ $ret[strval($val['mailbox'])] = $val['status'];
+ }
+ unset($status[strval($val['mailbox'])]);
+ }
+ } catch (Horde_Imap_Client_Exception $e) {}
+
+ if (empty($status)) {
+ $need_status = false;
+ } else {
+ $mailboxes = array_keys($status);
+ }
+ }
+
+ if ($need_status) {
+ foreach ($mailboxes as $val) {
+ $val = Horde_Imap_Client_Mailbox::get($val);
+ try {
+ $ret[strval($val)] = $this->status($val, $flags);
+ } catch (Horde_Imap_Client_Exception $e) {}
+ }
+ }
+
+ if (!$opts['sort']) {
+ return $ret;
+ }
+
+ $list_ob = new Horde_Imap_Client_Mailbox_List(array_keys($ret));
+ $sorted = $list_ob->sort(array(
+ 'delimiter' => $opts['sort_delimiter']
+ ));
+
+ $out = array();
+ foreach ($sorted as $val) {
+ $out[$val] = $ret[$val];
+ }
+
+ return $out;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -2064,12 +1944,8 @@
</span><span class="cx"> * Horde_Imap_Client_Mailbox object or a string
</span><span class="cx"> * (UTF-8).
</span><span class="cx"> * @param array $options Additional options:
</span><del>- * - delete: (boolean) If true, will flag all messages in 'ids' as
- * deleted (since 2.10.0).
- * DEFAULT: false
- * - ids: (Horde_Imap_Client_Ids) A list of messages to expunge. These
- * messages must already be flagged as deleted (unless 'delete'
- * is true).
</del><ins>+ * - ids: (Horde_Imap_Client_Ids) A list of messages to expunge, but
+ * only if they are also flagged as deleted.
</ins><span class="cx"> * DEFAULT: All messages marked as deleted will be expunged.
</span><span class="cx"> * - list: (boolean) If true, returns the list of expunged messages
</span><span class="cx"> * (UIDs only).
</span><span class="lines">@@ -2245,8 +2121,6 @@
</span><span class="cx"> Horde_Imap_Client::SEARCH_RESULTS_MATCH,
</span><span class="cx"> Horde_Imap_Client::SEARCH_RESULTS_COUNT
</span><span class="cx"> );
</span><del>- } elseif (!in_array(Horde_Imap_Client::SEARCH_RESULTS_COUNT, $options['results'])) {
- $options['results'][] = Horde_Imap_Client::SEARCH_RESULTS_COUNT;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Default to an ALL search.
</span><span class="lines">@@ -2338,7 +2212,7 @@
</span><span class="cx"> $cache = null;
</span><span class="cx"> if (empty($options['nocache']) &&
</span><span class="cx"> $this->_initCache(true) &&
</span><del>- (isset($this->_temp['enabled']['CONDSTORE']) ||
</del><ins>+ (isset($this->_init['enabled']['CONDSTORE']) ||
</ins><span class="cx"> !$query->flagSearch())) {
</span><span class="cx"> $cache = $this->_getSearchCache('search', $options);
</span><span class="cx"> if (isset($cache['data'])) {
</span><span class="lines">@@ -2365,14 +2239,12 @@
</span><span class="cx">
</span><span class="cx"> $ret = $this->_search($query, $options);
</span><span class="cx"> } else {
</span><del>- $ret = array();
</del><ins>+ $ret = array(
+ 'count' => 0
+ );
</ins><span class="cx">
</span><span class="cx"> foreach ($options['results'] as $val) {
</span><span class="cx"> switch ($val) {
</span><del>- case Horde_Imap_Client::SEARCH_RESULTS_COUNT:
- $ret['count'] = 0;
- break;
-
</del><span class="cx"> case Horde_Imap_Client::SEARCH_RESULTS_MATCH:
</span><span class="cx"> $ret['match'] = $this->getIdsOb();
</span><span class="cx"> break;
</span><span class="lines">@@ -2436,7 +2308,7 @@
</span><span class="cx"> public function setComparator($comparator = null)
</span><span class="cx"> {
</span><span class="cx"> $comp = is_null($comparator)
</span><del>- ? $this->getParam('comparator')
</del><ins>+ ? (empty($this->_params['comparator']) ? null : $this->_params['comparator'])
</ins><span class="cx"> : $comparator;
</span><span class="cx"> if (is_null($comp)) {
</span><span class="cx"> return;
</span><span class="lines">@@ -2544,7 +2416,7 @@
</span><span class="cx"> * that don't involve flags. See search() for similar caching. */
</span><span class="cx"> $cache = null;
</span><span class="cx"> if ($this->_initCache(true) &&
</span><del>- (isset($this->_temp['enabled']['CONDSTORE']) ||
</del><ins>+ (isset($this->_init['enabled']['CONDSTORE']) ||
</ins><span class="cx"> empty($options['search']) ||
</span><span class="cx"> !$options['search']->flagSearch())) {
</span><span class="cx"> $cache = $this->_getSearchCache('thread', $options);
</span><span class="lines">@@ -2666,7 +2538,7 @@
</span><span class="cx">
</span><span class="cx"> $modseq_check = !empty($options['changedsince']);
</span><span class="cx"> if ($query->contains(Horde_Imap_Client::FETCH_MODSEQ)) {
</span><del>- if (!isset($this->_temp['enabled']['CONDSTORE'])) {
</del><ins>+ if (!isset($this->_init['enabled']['CONDSTORE'])) {
</ins><span class="cx"> unset($query[Horde_Imap_Client::FETCH_MODSEQ]);
</span><span class="cx"> } elseif (empty($options['changedsince'])) {
</span><span class="cx"> $modseq_check = true;
</span><span class="lines">@@ -2684,7 +2556,8 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /* Determine if caching is available and if anything in $query is
</span><del>- * cacheable. */
</del><ins>+ * cacheable.
+ * TODO: Re-add base headertext caching. */
</ins><span class="cx"> foreach ($cf as $k => $v) {
</span><span class="cx"> if (isset($query[$k])) {
</span><span class="cx"> switch ($k) {
</span><span class="lines">@@ -2720,8 +2593,7 @@
</span><span class="cx">
</span><span class="cx"> /* If nothing is cacheable, we can do a straight search. */
</span><span class="cx"> if (empty($cache_array)) {
</span><del>- $options['_query'] = $query;
- $this->_fetch($ret, array($options));
</del><ins>+ $this->_fetch($ret, $query, $options);
</ins><span class="cx"> return $ret;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -2732,9 +2604,6 @@
</span><span class="cx"> /* Convert special searches to UID lists and create mapping. */
</span><span class="cx"> $ids = $this->resolveIds($this->_selected, $options['ids'], empty($options['exists']) ? 1 : 2);
</span><span class="cx">
</span><del>- /* Add non-user settable cache fields. */
- $cache_array[Horde_Imap_Client::FETCH_DOWNGRADED] = self::CACHE_DOWNGRADED;
-
</del><span class="cx"> /* Get the cached values. */
</span><span class="cx"> $data = $this->_cache->get($this->_selected, $ids->ids, array_values($cache_array), $mbox_ob->getStatus(Horde_Imap_Client::STATUS_UIDVALIDITY));
</span><span class="cx">
</span><span class="lines">@@ -2765,12 +2634,6 @@
</span><span class="cx">
</span><span class="cx"> foreach ($cache_array as $key => $cid) {
</span><span class="cx"> switch ($key) {
</span><del>- case Horde_Imap_Client::FETCH_DOWNGRADED:
- if (!empty($data[$uid][$cid])) {
- $entry->setDowngraded(true);
- }
- break;
-
</del><span class="cx"> case Horde_Imap_Client::FETCH_ENVELOPE:
</span><span class="cx"> if (isset($data[$uid][$cid]) &&
</span><span class="cx"> ($data[$uid][$cid] instanceof Horde_Imap_Client_Data_Envelope)) {
</span><span class="lines">@@ -2788,6 +2651,7 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case Horde_Imap_Client::FETCH_HEADERS:
</span><ins>+ /* HEADERS caching. */
</ins><span class="cx"> foreach ($header_cache as $hkey => $hval) {
</span><span class="cx"> if (isset($data[$uid][$cid][$hval])) {
</span><span class="cx"> /* We have found a cached entry with the same
</span><span class="lines">@@ -2838,21 +2702,15 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $to_fetch = array();
</del><span class="cx"> foreach ($new_query as $val) {
</span><span class="cx"> $ids_ob = $this->getIdsOb(null, $sequence);
</span><span class="cx"> $ids_ob->duplicates = true;
</span><span class="cx"> $ids_ob->add($val['i']);
</span><del>- $to_fetch[] = array_merge($options, array(
- '_query' => $val['c'],
</del><ins>+ $this->_fetch(is_null($cs_ret) ? $ret : $cs_ret, $val['c'], array_merge($options, array(
</ins><span class="cx"> 'ids' => $ids_ob
</span><del>- ));
</del><ins>+ )));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- if (!empty($to_fetch)) {
- $this->_fetch(is_null($cs_ret) ? $ret : $cs_ret, $to_fetch);
- }
-
</del><span class="cx"> if (is_null($cs_ret)) {
</span><span class="cx"> return $ret;
</span><span class="cx"> }
</span><span class="lines">@@ -2889,18 +2747,15 @@
</span><span class="cx"> /**
</span><span class="cx"> * Fetch message data.
</span><span class="cx"> *
</span><del>- * Fetch queries should be grouped in the $queries argument. Each value
- * is an array of fetch options, with the fetch query stored in the
- * '_query' parameter. IMPORTANT: All queries must have the same ID
- * type (either sequence or UID).
- *
</del><span class="cx"> * @param Horde_Imap_Client_Fetch_Results $results Fetch results.
</span><del>- * @param array $queries The list of queries.
</del><ins>+ * @param Horde_Imap_Client_Fetch_Query $query Fetch query object.
+ * @param array $options Additional options.
</ins><span class="cx"> *
</span><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><span class="cx"> abstract protected function _fetch(Horde_Imap_Client_Fetch_Results $results,
</span><del>- $queries);
</del><ins>+ Horde_Imap_Client_Fetch_Query $query,
+ $options);
</ins><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Get the list of vanished messages (UIDs that have been expunged since a
</span><span class="lines">@@ -3020,7 +2875,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (!empty($options['unchangedsince'])) {
</span><del>- if (!isset($this->_temp['enabled']['CONDSTORE'])) {
</del><ins>+ if (!isset($this->_init['enabled']['CONDSTORE'])) {
</ins><span class="cx"> throw new Horde_Imap_Client_Exception_NoSupportExtension('CONDSTORE');
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -3570,7 +3425,7 @@
</span><span class="cx"> */
</span><span class="cx"> public function getCacheId($mailbox, array $addl = array())
</span><span class="cx"> {
</span><del>- return Horde_Imap_Client_Base_Deprecated::getCacheId($this, $mailbox, isset($this->_temp['enabled']['CONDSTORE']), $addl);
</del><ins>+ return Horde_Imap_Client_Base_Deprecated::getCacheId($this, $mailbox, isset($this->_init['enabled']['CONDSTORE']), $addl);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -3616,9 +3471,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> $convert = 2;
</span><del>- } elseif (!$convert ||
- (!$ids->sequence && ($convert == 1)) ||
- $ids->isEmpty()) {
</del><ins>+ } elseif (!$convert || (!$ids->sequence && ($convert == 1))) {
</ins><span class="cx"> return clone $ids;
</span><span class="cx"> } else {
</span><span class="cx"> /* Do an all or nothing: either we have all the numbers/UIDs in
</span><span class="lines">@@ -3652,7 +3505,7 @@
</span><span class="cx"> return $res['match'];
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $map->update(array_combine(array_slice($ids->ids, 0, count($res['match'])), $res['match']->ids));
</del><ins>+ $map->update(array_combine($ids->ids, $res['match']->ids));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return $res['match'];
</span><span class="lines">@@ -3782,8 +3635,7 @@
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $c = $this->getParam('cache');
- if (in_array(strval($this->_selected), $c['fetch_ignore'])) {
</del><ins>+ if (in_array(strval($this->_selected), $this->_params['cache']['fetch_ignore'])) {
</ins><span class="cx"> $this->_debug->info(sprintf("CACHE: Ignoring FETCH data (mailbox: %s)", $this->_selected));
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="lines">@@ -3808,10 +3660,6 @@
</span><span class="cx">
</span><span class="cx"> $tmp = array();
</span><span class="cx">
</span><del>- if ($v->isDowngraded()) {
- $tmp[self::CACHE_DOWNGRADED] = true;
- }
-
</del><span class="cx"> foreach ($cf as $key => $val) {
</span><span class="cx"> if ($v->exists($key)) {
</span><span class="cx"> switch ($key) {
</span><span class="lines">@@ -3888,8 +3736,7 @@
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $c = $this->getParam('cache');
- if (in_array(strval($to), $c['fetch_ignore'])) {
</del><ins>+ if (in_array(strval($to), $this->_params['cache']['fetch_ignore'])) {
</ins><span class="cx"> $this->_debug->info(sprintf("CACHE: Ignoring moving FETCH data (%s => %s)", $this->_selected, $to));
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="lines">@@ -3914,15 +3761,12 @@
</span><span class="cx"> * @param Horde_Imap_Client_Mailbox $mailbox The mailbox.
</span><span class="cx"> * @param Horde_Imap_Client_Ids $ids The list of IDs to delete in
</span><span class="cx"> * $mailbox.
</span><del>- * @param array $opts Additional options (not used
- * in base class).
</del><span class="cx"> *
</span><span class="cx"> * @return Horde_Imap_Client_Ids UIDs that were deleted.
</span><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><span class="cx"> protected function _deleteMsgs(Horde_Imap_Client_Mailbox $mailbox,
</span><del>- Horde_Imap_Client_Ids $ids,
- array $opts = array())
</del><ins>+ Horde_Imap_Client_Ids $ids)
</ins><span class="cx"> {
</span><span class="cx"> if (!$this->_initCache()) {
</span><span class="cx"> return $ids;
</span><span class="lines">@@ -4078,12 +3922,9 @@
</span><span class="cx"> $fquery->flags();
</span><span class="cx">
</span><span class="cx"> /* Update flags in cache. Cache will be updated in _fetch(). */
</span><del>- $this->_fetch(new Horde_Imap_Client_Fetch_Results(), array(
- array(
- '_query' => $fquery,
- 'changedsince' => $modseq,
- 'ids' => $uids_ob
- )
</del><ins>+ $this->_fetch(new Horde_Imap_Client_Fetch_Results(), $fquery, array(
+ 'changedsince' => $modseq,
+ 'ids' => $uids_ob
</ins><span class="cx"> ));
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -4105,10 +3946,9 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _cacheFields()
</span><span class="cx"> {
</span><del>- $c = $this->getParam('cache');
- $out = $c['fields'];
</del><ins>+ $out = $this->_params['cache']['fields'];
</ins><span class="cx">
</span><del>- if (!isset($this->_temp['enabled']['CONDSTORE'])) {
</del><ins>+ if (!isset($this->_init['enabled']['CONDSTORE'])) {
</ins><span class="cx"> unset($out[Horde_Imap_Client::FETCH_FLAGS]);
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="2013codebykatpostbyemailtrunkincludeHordeImapClientSocketPop3php"></a>
<div class="modfile"><h4>Modified: 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Socket/Pop3.php (2317 => 2318)</h4>
<pre class="diff"><span>
<span class="info">--- 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Socket/Pop3.php 2013-09-16 02:11:45 UTC (rev 2317)
+++ 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Socket/Pop3.php 2013-09-16 02:11:57 UTC (rev 2318)
</span><span class="lines">@@ -61,8 +61,7 @@
</span><span class="cx"> * - RFC 2595/4616: PLAIN authentication
</span><span class="cx"> * - RFC 2831: DIGEST-MD5 SASL Authentication (obsoleted by RFC 6331)
</span><span class="cx"> * - RFC 3206: AUTH/SYS response codes
</span><del>- * - RFC 4616: AUTH=PLAIN
- * - RFC 5034: POP3 SASL
</del><ins>+ * - RFC 1734/5034: POP3 SASL
</ins><span class="cx"> *
</span><span class="cx"> * @author Richard Heyes <richard@phpguru.org>
</span><span class="cx"> * @author Michael Slusarz <slusarz@horde.org>
</span><span class="lines">@@ -75,13 +74,6 @@
</span><span class="cx"> class Horde_Imap_Client_Socket_Pop3 extends Horde_Imap_Client_Base
</span><span class="cx"> {
</span><span class="cx"> /**
</span><del>- * The default ports to use for a connection.
- *
- * @var array
- */
- protected $_defaultPorts = array(110, 995);
-
- /**
</del><span class="cx"> * The list of deleted messages.
</span><span class="cx"> *
</span><span class="cx"> * @var array
</span><span class="lines">@@ -96,7 +88,27 @@
</span><span class="cx"> protected $_fetchDataClass = 'Horde_Imap_Client_Data_Fetch_Pop3';
</span><span class="cx">
</span><span class="cx"> /**
</span><ins>+ * The socket connection to the POP3 server.
+ *
+ * @var resource
</ins><span class="cx"> */
</span><ins>+ protected $_stream = null;
+
+ /**
+ */
+ public function __construct(array $params = array())
+ {
+ parent::__construct($params);
+
+ if (empty($params['port'])) {
+ $this->_params['port'] = (isset($this->_params['secure']) && in_array($this->_params['secure'], array('ssl', 'sslv2', 'sslv3')))
+ ? 995
+ : 110;
+ }
+ }
+
+ /**
+ */
</ins><span class="cx"> protected function _initCache($current = false)
</span><span class="cx"> {
</span><span class="cx"> return parent::_initCache($current) &&
</span><span class="lines">@@ -119,39 +131,36 @@
</span><span class="cx"> $capability = array();
</span><span class="cx">
</span><span class="cx"> try {
</span><del>- $res = $this->_sendLine('CAPA', array(
- 'multiline' => 'array'
- ));
</del><ins>+ $this->_sendLine('CAPA');
</ins><span class="cx">
</span><del>- foreach ($res['data'] as $val) {
</del><ins>+ foreach ($this->_getMultiline(true) as $val) {
</ins><span class="cx"> $prefix = explode(' ', $val);
</span><ins>+
</ins><span class="cx"> $capability[strtoupper($prefix[0])] = (count($prefix) > 1)
</span><span class="cx"> ? array_slice($prefix, 1)
</span><span class="cx"> : true;
</span><span class="cx"> }
</span><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {
</span><del>- $this->_temp['no_capa'] = true;
-
</del><span class="cx"> /* Need to probe for capabilities if CAPA command is not
</span><span class="cx"> * available. */
</span><del>- $capability = array('USER' => true);
</del><ins>+ $capability = array('USER', 'SASL');
</ins><span class="cx">
</span><del>- /* Capability sniffing only guaranteed after authentication is
- * completed (if any). */
- if (!empty($this->_init['authmethod'])) {
- $this->_pop3Cache('uidl');
- if (empty($this->_temp['no_uidl'])) {
- $capability['UIDL'] = true;
- }
</del><ins>+ try {
+ $this->_sendLine('UIDL');
+ fclose($this->_getMultiline());
+ $capability[] = 'UIDL';
+ } catch (Horde_Imap_Client_Exception $e) {}
</ins><span class="cx">
</span><del>- $this->_pop3Cache('top', 1);
- if (empty($this->_temp['no_top'])) {
- $capability['TOP'] = true;
- }
- }
</del><ins>+ try {
+ $this->_sendLine('TOP 1 0');
+ fclose($this->_getMultiline());
+ $capability[] = 'TOP';
+ } catch (Horde_Imap_Client_Exception $e) {}
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> $this->_setInit('capability', $capability);
</span><ins>+
+ return $this->_init['capability'];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -182,37 +191,33 @@
</span><span class="cx"> {
</span><span class="cx"> $this->_connect();
</span><span class="cx">
</span><del>- $secure = $this->getParam('secure');
-
</del><span class="cx"> // Switch to secure channel if using TLS.
</span><del>- if (!$this->isSecureConnection() &&
- (($secure === 'tls') || $secure === true)) {
</del><ins>+ if (!$this->_isSecure &&
+ ($this->_params['secure'] == 'tls')) {
</ins><span class="cx"> // Switch over to a TLS connection.
</span><span class="cx"> if (!$this->queryCapability('STLS')) {
</span><del>- if ($secure === 'tls') {
- throw new Horde_Imap_Client_Exception(
- Horde_Imap_Client_Translation::t("Could not open secure connection to the POP3 server.") . ' ' . Horde_Imap_Client_Translation::t("Server does not support secure connections."),
- Horde_Imap_Client_Exception::LOGIN_TLSFAILURE
- );
- } else {
- $this->setParam('secure', false);
- }
- } else {
- $this->_sendLine('STLS');
</del><ins>+ throw new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Could not open secure connection to the POP3 server.") . ' ' . Horde_Imap_Client_Translation::t("Server does not support secure connections."),
+ Horde_Imap_Client_Exception::LOGIN_TLSFAILURE
+ );
+ }
</ins><span class="cx">
</span><del>- $this->setParam('secure', 'tls');
</del><ins>+ $this->_sendLine('STLS');
</ins><span class="cx">
</span><del>- if (!$this->_connection->startTls()) {
- $this->logout();
- throw new Horde_Imap_Client_Exception(
- Horde_Imap_Client_Translation::t("Could not open secure connection to the POP3 server."),
- Horde_Imap_Client_Exception::LOGIN_TLSFAILURE
- );
- }
</del><ins>+ $res = @stream_socket_enable_crypto($this->_stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
+
+ if (!$res) {
+ $this->logout();
+ throw new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Could not open secure connection to the POP3 server."),
+ Horde_Imap_Client_Exception::LOGIN_TLSFAILURE
+ );
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Expire cached CAPABILITY information
</span><span class="cx"> $this->_setInit('capability');
</span><ins>+
+ $this->_isSecure = true;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (empty($this->_init['authmethod'])) {
</span><span class="lines">@@ -233,12 +238,6 @@
</span><span class="cx"> try {
</span><span class="cx"> $this->_tryLogin($method);
</span><span class="cx"> $this->_setInit('authmethod', $method);
</span><del>-
- if (!empty($this->_temp['no_capa']) ||
- !$this->queryCapability('UIDL')) {
- $this->_capability();
- }
-
</del><span class="cx"> return true;
</span><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {
</span><span class="cx"> if (!empty($this->_init['authmethod'])) {
</span><span class="lines">@@ -261,16 +260,47 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _connect()
</span><span class="cx"> {
</span><del>- if (!is_null($this->_connection)) {
</del><ins>+ if (!is_null($this->_stream)) {
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $this->_connection = new Horde_Imap_Client_Socket_Connection_Pop3($this, $this->_debug);
</del><ins>+ if (!empty($this->_params['secure']) && !extension_loaded('openssl')) {
+ new InvalidArgumentException('Secure connections require the PHP openssl extension.');
+ }
</ins><span class="cx">
</span><del>- $line = $this->_getResponse();
</del><ins>+ switch ($this->_params['secure']) {
+ case 'ssl':
+ case 'sslv2':
+ case 'sslv3':
+ $conn = $this->_params['secure'] . '://';
+ $this->_isSecure = true;
+ break;
</ins><span class="cx">
</span><ins>+ case 'tls':
+ default:
+ $conn = 'tcp://';
+ break;
+ }
+
+ $this->_stream = @stream_socket_client($conn . $this->_params['hostspec'] . ':' . $this->_params['port'], $error_number, $error_string, $this->_params['timeout']);
+
+ if ($this->_stream === false) {
+ $this->_stream = null;
+ $this->_isSecure = false;
+ $e = new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Error connecting to POP3 server."),
+ Horde_Imap_Client_Exception::SERVER_CONNECT
+ );
+ $e->details = sprintf("[%u] %s.", $error_number, $error_string);
+ throw $e;
+ }
+
+ stream_set_timeout($this->_stream, $this->_params['timeout']);
+
+ $line = $this->_getLine();
+
</ins><span class="cx"> // Check for string matching APOP timestamp
</span><del>- if (preg_match('/<.+@.+>/U', $line['resp'], $matches)) {
</del><ins>+ if (preg_match('/<.+@.+>/U', $line['line'], $matches)) {
</ins><span class="cx"> $this->_temp['pop3timestamp'] = $matches[0];
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -284,9 +314,6 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _tryLogin($method)
</span><span class="cx"> {
</span><del>- $username = $this->getParam('username');
- $password = $this->getParam('password');
-
</del><span class="cx"> switch ($method) {
</span><span class="cx"> case 'CRAM-MD5':
</span><span class="cx"> case 'CRAM-SHA1':
</span><span class="lines">@@ -294,9 +321,9 @@
</span><span class="cx"> // RFC 5034: CRAM-MD5
</span><span class="cx"> // CRAM-SHA1 & CRAM-SHA256 supported by Courier SASL library
</span><span class="cx"> $challenge = $this->_sendLine('AUTH ' . $method);
</span><del>- $response = base64_encode($username . ' ' . hash_hmac(strtolower(substr($method, 5)), base64_decode(substr($challenge['resp'], 2)), $password, true));
</del><ins>+ $response = base64_encode($this->_params['username'] . ' ' . hash_hmac(strtolower(substr($method, 5)), base64_decode(substr($challenge['line'], 2)), $this->getParam('password'), true));
</ins><span class="cx"> $this->_sendLine($response, array(
</span><del>- 'debug' => sprintf('[%s Response - username: %s]', $method, $username)
</del><ins>+ 'debug' => '[' . $method . ' Response]'
</ins><span class="cx"> ));
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="lines">@@ -304,16 +331,16 @@
</span><span class="cx"> // RFC 2831; Obsoleted by RFC 6331
</span><span class="cx"> $challenge = $this->_sendLine('AUTH DIGEST-MD5');
</span><span class="cx"> $response = base64_encode(new Horde_Imap_Client_Auth_DigestMD5(
</span><del>- $username,
- $password,
- base64_decode(substr($challenge['resp'], 2)),
- $this->getParam('hostspec'),
</del><ins>+ $this->_params['username'],
+ $this->getParam('password'),
+ base64_decode(substr($challenge['line'], 2)),
+ $this->_params['hostspec'],
</ins><span class="cx"> 'pop3'
</span><span class="cx"> ));
</span><span class="cx"> $sresponse = $this->_sendLine($response, array(
</span><del>- 'debug' => sprintf('[%s Response - username: %s]', $method, $username)
</del><ins>+ 'debug' => '[DIGEST-MD5 Response]'
</ins><span class="cx"> ));
</span><del>- if (stripos(base64_decode(substr($sresponse['resp'], 2)), 'rspauth=') === false) {
</del><ins>+ if (stripos(base64_decode(substr($sresponse['line'], 2)), 'rspauth=') === false) {
</ins><span class="cx"> throw new Horde_Imap_Client_Exception(
</span><span class="cx"> Horde_Imap_Client_Translation::t("Unexpected response from server when authenticating."),
</span><span class="cx"> Horde_Imap_Client_Exception::SERVER_CONNECT
</span><span class="lines">@@ -325,36 +352,30 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'LOGIN':
</span><del>- // RFC 4616 (AUTH=PLAIN) & 5034 (POP3 SASL)
</del><ins>+ // RFC 5034
</ins><span class="cx"> $this->_sendLine('AUTH LOGIN');
</span><del>- $this->_sendLine(base64_encode($username), array(
- 'debug' => sprintf('[AUTH LOGIN Command - username: %s]', $username)
- ));
- $this->_sendLine(base64_encode($password), array(
</del><ins>+ $this->_sendLine(base64_encode($this->_params['username']));
+ $this->_sendLine(base64_encode($this->getParam('password')), array(
</ins><span class="cx"> 'debug' => '[AUTH LOGIN Command - password]'
</span><span class="cx"> ));
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'PLAIN':
</span><span class="cx"> // RFC 5034
</span><del>- $this->_sendLine('AUTH PLAIN ' . base64_encode(implode("\0", array(
- $username,
- $username,
- $password
- ))), array(
- 'debug' => sprintf('[AUTH PLAIN Command - username: %s]', $username)
</del><ins>+ $this->_sendLine('AUTH PLAIN ' . base64_encode(implode("\0", array($this->_params['username'], $this->getParam('password')))), array(
+ 'debug' => sprintf('[AUTH PLAIN Command - username: %s]', $this->_params['username'])
</ins><span class="cx"> ));
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'APOP':
</span><span class="cx"> // RFC 1939 [7]
</span><del>- $this->_sendLine('APOP ' . $username . ' ' . hash('md5', $this->_temp['pop3timestamp'] . $password));
</del><ins>+ $this->_sendLine('APOP ' . $this->_params['username'] . ' ' . hash('md5', $this->_temp['pop3timestamp'] . $this->_params['password']));
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'USER':
</span><span class="cx"> // RFC 1939 [7]
</span><del>- $this->_sendLine('USER ' . $username);
- $this->_sendLine('PASS ' . $password, array(
</del><ins>+ $this->_sendLine('USER ' . $this->_params['username']);
+ $this->_sendLine('PASS ' . $this->getParam('password'), array(
</ins><span class="cx"> 'debug' => '[USER Command - password]'
</span><span class="cx"> ));
</span><span class="cx"> break;
</span><span class="lines">@@ -371,10 +392,14 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _logout()
</span><span class="cx"> {
</span><del>- try {
- $this->_sendLine('QUIT');
- } catch (Horde_Imap_Client_Exception $e) {}
- $this->_deleted = array();
</del><ins>+ if (!is_null($this->_stream)) {
+ try {
+ $this->_sendLine('QUIT');
+ } catch (Horde_Imap_Client_Exception $e) {}
+ fclose($this->_stream);
+ $this->_stream = null;
+ $this->_deleted = array();
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -417,7 +442,7 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _openMailbox(Horde_Imap_Client_Mailbox $mailbox, $mode)
</span><span class="cx"> {
</span><del>- if ($mailbox != 'INBOX') {
</del><ins>+ if (strcasecmp($mailbox, 'INBOX') !== 0) {
</ins><span class="cx"> throw new Horde_Imap_Client_Exception_NoSupportPop3('Mailboxes other than INBOX');
</span><span class="cx"> }
</span><span class="cx"> $this->_changeSelected($mailbox, $mode);
</span><span class="lines">@@ -480,14 +505,10 @@
</span><span class="cx"> * under Horde_Imap_Client::STATUS_ALL.
</span><span class="cx"> * @throws Horde_Imap_Client_Exception_NoSupportPop3
</span><span class="cx"> */
</span><del>- protected function _status($mboxes, $flags)
</del><ins>+ protected function _status(Horde_Imap_Client_Mailbox $mailbox, $flags)
</ins><span class="cx"> {
</span><del>- if ((count($mboxes) > 1) || (reset($mboxes) != 'INBOX')) {
- throw new Horde_Imap_Client_Exception_NoSupportPop3('Mailboxes other than INBOX');
- }
</del><ins>+ $this->openMailbox($mailbox);
</ins><span class="cx">
</span><del>- $this->openMailbox('INBOX');
-
</del><span class="cx"> $ret = array();
</span><span class="cx">
</span><span class="cx"> if ($flags & Horde_Imap_Client::STATUS_MESSAGES) {
</span><span class="lines">@@ -517,7 +538,7 @@
</span><span class="cx"> $ret['unseen'] = 0;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return array('INBOX' => $ret);
</del><ins>+ return $ret;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -636,26 +657,12 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><ins>+ * @throws Horde_Imap_Client_Exception_NoSupportPop3
</ins><span class="cx"> */
</span><span class="cx"> protected function _fetch(Horde_Imap_Client_Fetch_Results $results,
</span><del>- $queries)
</del><ins>+ Horde_Imap_Client_Fetch_Query $query,
+ $options)
</ins><span class="cx"> {
</span><del>- foreach ($queries as $options) {
- $this->_fetchCmd($results, $options);
- }
-
- $this->_updateCache($results);
- }
-
- /**
- * Fetch data for a given fetch query.
- *
- * @param Horde_Imap_Client_Fetch_Results $results Fetch results.
- * @param array $options Fetch query options.
- */
- protected function _fetchCmd(Horde_Imap_Client_Fetch_Results $results,
- $options)
- {
</del><span class="cx"> // Grab sequence IDs - IDs will always be the message number for
</span><span class="cx"> // POP3 fetch commands.
</span><span class="cx"> $seq_ids = $this->_getSeqIds($options['ids']);
</span><span class="lines">@@ -667,7 +674,7 @@
</span><span class="cx"> ? array_combine($seq_ids, $seq_ids)
</span><span class="cx"> : $this->_pop3Cache('uidl');
</span><span class="cx">
</span><del>- foreach ($options['_query'] as $type => $c_val) {
</del><ins>+ foreach ($query as $type => $c_val) {
</ins><span class="cx"> switch ($type) {
</span><span class="cx"> case Horde_Imap_Client::FETCH_FULLMSG:
</span><span class="cx"> foreach ($seq_ids as $id) {
</span><span class="lines">@@ -761,7 +768,7 @@
</span><span class="cx"> foreach ($seq_ids as $id) {
</span><span class="cx"> if ($ptr = $this->_pop3Cache('msg', $id)) {
</span><span class="cx"> try {
</span><del>- $results->get($lookup[$id])->setStructure(Horde_Mime_Part::parseMessage(stream_get_contents($ptr), array('no_body' => true)));
</del><ins>+ $results->get($lookup[$id])->setStructure(Horde_Mime_Part::parseMessage(stream_get_contents($ptr)));
</ins><span class="cx"> } catch (Horde_Exception $e) {}
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -815,13 +822,15 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><ins>+
+ $this->_updateCache($results);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Retrieve locally cached message data.
</span><span class="cx"> *
</span><span class="cx"> * @param string $type Either 'hdr', 'hdrob', 'msg', 'size', 'stat',
</span><del>- * 'top', or 'uidl'.
</del><ins>+ * or 'uidl'.
</ins><span class="cx"> * @param integer $index The message index.
</span><span class="cx"> * @param mixed $data Additional information needed.
</span><span class="cx"> *
</span><span class="lines">@@ -841,22 +850,15 @@
</span><span class="cx">
</span><span class="cx"> switch ($type) {
</span><span class="cx"> case 'hdr':
</span><del>- case 'top':
</del><span class="cx"> $data = null;
</span><del>- if ($this->queryCapability('TOP') || ($type == 'top')) {
</del><ins>+ if ($this->queryCapability('TOP')) {
</ins><span class="cx"> try {
</span><del>- $res = $this->_sendLine('TOP ' . $index . ' 0', array(
- 'multiline' => 'stream'
- ));
- rewind($res['data']);
- $data = stream_get_contents($res['data']);
- fclose($res['data']);
- } catch (Horde_Imap_Client_Exception $e) {
- $this->_temp['no_top'] = true;
- if ($type == 'top') {
- return null;
- }
- }
</del><ins>+ $resp = $this->_sendLine('TOP ' . $index . ' 0');
+ $ptr = $this->_getMultiline();
+ rewind($ptr);
+ $data = stream_get_contents($ptr);
+ fclose($ptr);
+ } catch (Horde_Imap_Client_Exception $e) {}
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (is_null($data)) {
</span><span class="lines">@@ -869,10 +871,8 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'msg':
</span><del>- $res = $this->_sendLine('RETR ' . $index, array(
- 'multiline' => 'stream'
- ));
- $data = $res['data'];
</del><ins>+ $resp = $this->_sendLine('RETR ' . $index);
+ $data = $this->_getMultiline();
</ins><span class="cx"> rewind($data);
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="lines">@@ -880,23 +880,17 @@
</span><span class="cx"> case 'uidl':
</span><span class="cx"> $data = array();
</span><span class="cx"> try {
</span><del>- $res = $this->_sendLine(($type == 'size') ? 'LIST' : 'UIDL', array(
- 'multiline' => 'array'
- ));
- foreach ($res['data'] as $val) {
</del><ins>+ $this->_sendLine(($type == 'size') ? 'LIST' : 'UIDL');
+ foreach ($this->_getMultiline(true) as $val) {
</ins><span class="cx"> $resp_data = explode(' ', $val, 2);
</span><span class="cx"> $data[$resp_data[0]] = $resp_data[1];
</span><span class="cx"> }
</span><del>- } catch (Horde_Imap_Client_Exception $e) {
- if ($type == 'uidl') {
- $this->_temp['no_uidl'] = true;
- }
- }
</del><ins>+ } catch (Horde_Imap_Client_Exception $e) {}
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'stat':
</span><span class="cx"> $resp = $this->_sendLine('STAT');
</span><del>- $resp_data = explode(' ', $resp['resp'], 2);
</del><ins>+ $resp_data = explode(' ', $resp['line'], 2);
</ins><span class="cx"> $data = array('msgs' => $resp_data[0], 'size' => $resp_data[1]);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -967,7 +961,6 @@
</span><span class="cx"> foreach ($this->_getSeqIds($options['ids']) as $id) {
</span><span class="cx"> try {
</span><span class="cx"> $this->_sendLine('DELE ' . $id);
</span><del>- $this->_deleted[] = $id;
</del><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {}
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -1074,186 +1067,165 @@
</span><span class="cx"> return null;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- /**
- */
- public function resolveIds(Horde_Imap_Client_Mailbox $mailbox,
- Horde_Imap_Client_Ids $ids, $convert = 0)
- {
- if (!$ids->special &&
- (!$convert ||
- (!$ids->sequence && ($convert == 1)) ||
- $ids->isEmpty())) {
- return clone $ids;
- }
-
- $uids = $this->_pop3Cache('uidl');
-
- return $this->getIdsOb(
- $ids->all ? array_values($uids) : array_intersect_keys($uids, $ids->ids)
- );
- }
-
</del><span class="cx"> /* Internal functions. */
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Perform a command on the server. A connection to the server must have
</span><span class="cx"> * already been made.
</span><span class="cx"> *
</span><del>- * @param string $cmd The command to execute.
</del><ins>+ * @param string $query The command to execute.
</ins><span class="cx"> * @param array $options Additional options:
</span><del>- * <pre>
</del><span class="cx"> * - debug: (string) When debugging, send this string instead of the
</span><span class="cx"> * actual command/data sent.
</span><span class="cx"> * DEFAULT: Raw data output to debug stream.
</span><del>- * - multiline: (mixed) 'array', 'none', or 'stream'.
- * </pre>
- *
- * @return array See _getResponse().
- *
- * @throws Horde_Imap_Client_Exception
</del><span class="cx"> */
</span><del>- protected function _sendLine($cmd, $options = array())
</del><ins>+ protected function _sendLine($query, $options = array())
</ins><span class="cx"> {
</span><del>- $old_debug = $this->_debug->debug;
- if (!empty($options['debug'])) {
- $this->_debug->raw($options['debug'] . "\n");
- $this->_debug->debug = false;
- }
</del><ins>+ $this->_debug->client(empty($options['debug']) ? $query : $options['debug']);
</ins><span class="cx">
</span><del>- try {
- $this->_connection->write($cmd);
- } catch (Horde_Imap_Client_Exception $e) {
- $this->_debug->debug = $old_debug;
- throw $e;
- }
</del><ins>+ fwrite($this->_stream, $query . "\r\n");
</ins><span class="cx">
</span><del>- $this->_debug->debug = $old_debug;
-
- return $this->_getResponse(
- empty($options['multiline']) ? false : $options['multiline']
- );
</del><ins>+ return $this->_getLine();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Gets a line from the stream and parses it.
</span><span class="cx"> *
</span><del>- * @param mixed $multiline 'array', 'none', 'stream', or null.
- *
</del><span class="cx"> * @return array An array with the following keys:
</span><del>- * - data: (mixed) Stream, array, or null.
- * - resp: (string) The server response text.
</del><ins>+ * - line: (string) The server response text.
+ * - response: (string) Either 'OK', 'END', '+', or ''.
</ins><span class="cx"> *
</span><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><del>- protected function _getResponse($multiline = false)
</del><ins>+ protected function _getLine()
</ins><span class="cx"> {
</span><del>- $ob = array('resp' => '');
</del><ins>+ $ob = array('line' => '', 'response' => '');
</ins><span class="cx">
</span><del>- $read = explode(' ', rtrim($this->_connection->read(), "\r\n"), 2);
- if (!in_array($read[0], array('+OK', '-ERR', '+'))) {
- $this->_debug->info("ERROR: IMAP read/timeout error.");
</del><ins>+ if (feof($this->_stream)) {
+ $this->logout();
</ins><span class="cx"> throw new Horde_Imap_Client_Exception(
</span><del>- Horde_Imap_Client_Translation::t("Error when communicating with the mail server."),
- Horde_Imap_Client_Exception::SERVER_READERROR
</del><ins>+ Horde_Imap_Client_Translation::t("POP3 Server closed the connection unexpectedly."),
+ Horde_Imap_Client_Exception::DISCONNECT
</ins><span class="cx"> );
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $respcode = null;
- if (isset($read[1]) &&
- isset($this->_init['capability']) &&
- $this->queryCapability('RESP-CODES')) {
- $respcode = $this->_parseResponseCode($read[1]);
</del><ins>+ $read = rtrim(fgets($this->_stream));
+ if (empty($read)) {
+ return;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ $this->_debug->server($read);
+
+ $orig_read = $read;
+ $read = explode(' ', $read, 2);
+
</ins><span class="cx"> switch ($read[0]) {
</span><span class="cx"> case '+OK':
</span><del>- case '+':
- if ($respcode) {
- $ob['resp'] = $respcode->text;
- } elseif (isset($read[1])) {
- $ob['resp'] = $read[1];
</del><ins>+ $ob['response'] = 'OK';
+ if (isset($read[1])) {
+ if ($this->queryCapability('RESP-CODES')) {
+ $response = $this->_parseResponseCode($read[1]);
+ $ob['line'] = $response->text;
+ } else {
+ $ob['line'] = $read[1];
+ }
</ins><span class="cx"> }
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case '-ERR':
</span><span class="cx"> $errcode = 0;
</span><del>- if ($respcode) {
- $errtext = $respcode->text;
</del><ins>+ if (isset($read[1])) {
+ if ($this->queryCapability('RESP-CODES')) {
+ $response = $this->_parseResponseCode($read[1]);
+ $errtext = $response->text;
</ins><span class="cx">
</span><del>- if (isset($respcode->code)) {
- switch ($respcode->code) {
- // RFC 2449 [8.1.1]
- case 'IN-USE':
- // RFC 2449 [8.1.2]
- case 'LOGIN-DELAY':
- $errcode = Horde_Imap_Client_Exception::LOGIN_UNAVAILABLE;
- break;
</del><ins>+ if (isset($response->code)) {
+ switch ($response->code) {
+ // RFC 2449 [8.1.1]
+ case 'IN-USE':
+ // RFC 2449 [8.1.2]
+ case 'LOGIN-DELAY':
+ $errcode = Horde_Imap_Client_Exception::LOGIN_UNAVAILABLE;
+ break;
</ins><span class="cx">
</span><del>- // RFC 3206 [4]
- case 'SYS/TEMP':
- $errcode = Horde_Imap_Client_Exception::POP3_TEMP_ERROR;
- break;
</del><ins>+ // RFC 3206 [4]
+ case 'SYS/TEMP':
+ $errcode = Horde_Imap_Client_Exception::POP3_TEMP_ERROR;
+ break;
</ins><span class="cx">
</span><del>- // RFC 3206 [4]
- case 'SYS/PERM':
- $errcode = Horde_Imap_Client_Exception::POP3_PERM_ERROR;
- break;
</del><ins>+ // RFC 3206 [4]
+ case 'SYS/PERM':
+ $errcode = Horde_Imap_Client_Exception::POP3_PERM_ERROR;
+ break;
</ins><span class="cx">
</span><del>- // RFC 3206 [5]
- case 'AUTH':
- $errcode = Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED;
- break;
</del><ins>+ // RFC 3206 [5]
+ case 'AUTH':
+ $errcode = Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED;
+ break;
+ }
</ins><span class="cx"> }
</span><ins>+ } else {
+ $errtext = $read[1];
</ins><span class="cx"> }
</span><del>- } elseif (isset($read[1])) {
- $errtext = $read[1];
</del><span class="cx"> } else {
</span><span class="cx"> $errtext = '[No error message provided by server]';
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $e = new Horde_Imap_Client_Exception(
</del><ins>+ throw new Horde_Imap_Client_Exception_ServerResponse(
</ins><span class="cx"> Horde_Imap_Client_Translation::t("POP3 error reported by server."),
</span><del>- $errcode
</del><ins>+ $errcode,
+ '-ERR',
+ $errtext
</ins><span class="cx"> );
</span><del>- $e->details = $errtext;
- throw $e;
- }
</del><span class="cx">
</span><del>- switch ($multiline) {
- case 'array':
- $ob['data'] = array();
</del><ins>+ case '.':
+ $ob['response'] = 'END';
</ins><span class="cx"> break;
</span><span class="cx">
</span><del>- case 'none':
- $ob['data'] = null;
</del><ins>+ case '+':
+ $ob['response'] = '+';
</ins><span class="cx"> break;
</span><span class="cx">
</span><del>- case 'stream':
- $ob['data'] = fopen('php://temp', 'r+');
</del><ins>+ default:
+ $ob['line'] = $orig_read;
</ins><span class="cx"> break;
</span><del>-
- default:
- return $ob;
</del><span class="cx"> }
</span><span class="cx">
</span><ins>+ return $ob;
+ }
+
+ /**
+ * Obtain multiline input.
+ *
+ * @param boolean $retarray Return an array?
+ *
+ * @return mixed An array if $retarray is true, a stream resource
+ * otherwise.
+ *
+ * @throws Horde_Imap_Client_Exception
+ */
+ protected function _getMultiline($retarray = false)
+ {
+ $data = $retarray
+ ? array()
+ : fopen('php://temp', 'r+');
+
</ins><span class="cx"> do {
</span><del>- $orig_read = $this->_connection->read();
- $read = rtrim($orig_read, "\r\n");
</del><ins>+ $line = $this->_getLine();
+ if (empty($line['response'])) {
+ if (substr($line['line'], 0, 2) == '..') {
+ $line['line'] = substr($line['line'], 1);
+ }
</ins><span class="cx">
</span><del>- if ($read == '.') {
- break;
- } elseif (substr($read, 0, 2) == '..') {
- $read = substr($read, 1);
</del><ins>+ if ($retarray) {
+ $data[] = $line['line'];
+ } else {
+ fwrite($data, $line['line'] . "\r\n");
+ }
</ins><span class="cx"> }
</span><ins>+ } while ($line['response'] != 'END');
</ins><span class="cx">
</span><del>- if (is_array($ob['data'])) {
- $ob['data'][] = $read;
- } elseif (!is_null($ob['data'])) {
- fwrite($ob['data'], $orig_read);
- }
- } while (true);
-
- return $ob;
</del><ins>+ return $data;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span></span></pre></div>
<a id="2013codebykatpostbyemailtrunkincludeHordeImapClientSocketphp"></a>
<div class="modfile"><h4>Modified: 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Socket.php (2317 => 2318)</h4>
<pre class="diff"><span>
<span class="info">--- 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Socket.php 2013-09-16 02:11:45 UTC (rev 2317)
+++ 2013/codebykat/post-by-email/trunk/include/Horde/Imap/Client/Socket.php 2013-09-16 02:11:57 UTC (rev 2318)
</span><span class="lines">@@ -61,7 +61,6 @@
</span><span class="cx"> * - RFC 6154: SPECIAL-USE/CREATE-SPECIAL-USE
</span><span class="cx"> * - RFC 6203: SEARCH=FUZZY
</span><span class="cx"> * - RFC 6851: MOVE
</span><del>- * - RFC 6858: DOWNGRADED response code
</del><span class="cx"> *
</span><span class="cx"> * Implements the following non-RFC extensions:
</span><span class="cx"> * <ul>
</span><span class="lines">@@ -76,11 +75,6 @@
</span><span class="cx"> * </li>
</span><span class="cx"> * </ul>
</span><span class="cx"> * </li>
</span><del>- * <li>AUTH=XOAUTH2
- * <ul>
- * <li>https://developers.google.com/gmail/xoauth2_protocol</li>
- * </ul>
- * </li>
</del><span class="cx"> * </ul>
</span><span class="cx"> *
</span><span class="cx"> * TODO (or not necessary?):
</span><span class="lines">@@ -106,8 +100,8 @@
</span><span class="cx"> * <li>RFC 5267: CONTEXT=SEARCH; CONTEXT=SORT</li>
</span><span class="cx"> * <li>RFC 5465: NOTIFY</li>
</span><span class="cx"> * <li>RFC 5466: FILTERS</li>
</span><ins>+ * <li>RFC 5738: UTF8 (Experimental; Very limited support currently)</li>
</ins><span class="cx"> * <li>RFC 6237: MULTISEARCH (Experimental)</li>
</span><del>- * <li>RFC 6855: UTF8
</del><span class="cx"> * </ul>
</span><span class="cx"> *
</span><span class="cx"> * @author Michael Slusarz <slusarz@horde.org>
</span><span class="lines">@@ -123,20 +117,13 @@
</span><span class="cx"> const CACHE_FLAGS = 'HICflags';
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Queued commands to send to the server.
</del><ins>+ * Fetch cached entries.
</ins><span class="cx"> *
</span><del>- * @var array
</del><ins>+ * @var Horde_Imap_Client_Fetch_Results
</ins><span class="cx"> */
</span><del>- protected $_cmdQueue = array();
</del><ins>+ protected $_fetch;
</ins><span class="cx">
</span><span class="cx"> /**
</span><del>- * The default ports to use for a connection.
- *
- * @var array
- */
- protected $_defaultPorts = array(143, 993);
-
- /**
</del><span class="cx"> * Mapping of status fields to IMAP names.
</span><span class="cx"> *
</span><span class="cx"> * @var array
</span><span class="lines">@@ -155,6 +142,13 @@
</span><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> /**
</span><ins>+ * The socket connection to the IMAP server.
+ *
+ * @var resource
+ */
+ protected $_stream = null;
+
+ /**
</ins><span class="cx"> * The unique tag to use when making an IMAP query.
</span><span class="cx"> *
</span><span class="cx"> * @var integer
</span><span class="lines">@@ -170,37 +164,31 @@
</span><span class="cx"> * - envelope_addrs: (integer) The maximum number of address entries to
</span><span class="cx"> * read for FETCH ENVELOPE address fields.
</span><span class="cx"> * DEFAULT: 1000
</span><del>- * - envelope_string: (integer) The maximum length of string fields
</del><ins>+ * * envelope_string: (integer) The maximum length of string fields
</ins><span class="cx"> * returned by the FETCH ENVELOPE command.
</span><span class="cx"> * DEFAULT: 2048
</span><del>- * - xoauth2_token: (mixed) If set, will authenticate via the XOAUTH2
- * mechanism (if available) with this token. Either a
- * string (since 2.13.0) or a
- * Horde_Imap_Client_Base_Password object (since
- * 2.14.0).
</del><span class="cx"> */
</span><span class="cx"> public function __construct(array $params = array())
</span><span class="cx"> {
</span><del>- parent::__construct(array_merge(array(
</del><ins>+ $params = array_merge(array(
</ins><span class="cx"> 'debug_literal' => false,
</span><span class="cx"> 'envelope_addrs' => 1000,
</span><span class="cx"> 'envelope_string' => 2048
</span><del>- ), $params));
</del><ins>+ ), $params);
+
+ parent::__construct($params);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><del>- public function getParam($key)
</del><ins>+ protected function _initOb()
</ins><span class="cx"> {
</span><del>- switch ($key) {
- case 'xoauth2_token':
- if ($this->_params[$key] instanceof Horde_Imap_Client_Base_Password) {
- return $this->_params[$key]->getPassword();
- }
- break;
- }
</del><ins>+ parent::_initOb();
</ins><span class="cx">
</span><del>- return parent::getParam($key);
</del><ins>+ $this->_fetch = new Horde_Imap_Client_Fetch_Results(
+ $this->_fetchDataClass,
+ Horde_Imap_Client_Fetch_Results::SEQUENCE
+ );
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -214,30 +202,33 @@
</span><span class="cx"> // It is possible the server provided capability information on
</span><span class="cx"> // connect, so check for it now.
</span><span class="cx"> if (!isset($this->_init['capability'])) {
</span><del>- $this->_sendCmd($this->_command('CAPABILITY'));
</del><ins>+ $this->_sendLine($this->_clientCommand('CAPABILITY'));
</ins><span class="cx"> }
</span><ins>+
+ return isset($this->_init['capability'])
+ ? $this->_init['capability']
+ : array();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse a CAPABILITY Response (RFC 3501 [7.2.1]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param array $data An array of CAPABILITY strings.
</span><span class="cx"> */
</span><del>- protected function _parseCapability(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- $data
- )
</del><ins>+ protected function _parseCapability($data)
</ins><span class="cx"> {
</span><span class="cx"> if (!empty($this->_temp['no_cap'])) {
</span><ins>+ unset($this->_temp['no_cap']);
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $pipeline->data['capability_set'] = true;
</del><ins>+ if (empty($this->_temp['in_login'])) {
+ $c = array();
+ } else {
+ $c = $this->_init['capability'];
+ $this->_temp['logincapset'] = true;
+ }
</ins><span class="cx">
</span><del>- $c = array();
-
</del><span class="cx"> foreach ($data as $val) {
</span><span class="cx"> $cap_list = explode('=', $val);
</span><span class="cx"> $cap_list[0] = strtoupper($cap_list[0]);
</span><span class="lines">@@ -271,33 +262,28 @@
</span><span class="cx"> protected function _noop()
</span><span class="cx"> {
</span><span class="cx"> // NOOP doesn't return any specific response
</span><del>- $this->_sendCmd($this->_command('NOOP'));
</del><ins>+ $this->_sendLine($this->_clientCommand('NOOP'));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><span class="cx"> protected function _getNamespaces()
</span><span class="cx"> {
</span><del>- $data = $this->queryCapability('NAMESPACE')
- ? $this->_sendCmd($this->_command('NAMESPACE'))->data
- : array();
</del><ins>+ if (!$this->queryCapability('NAMESPACE')) {
+ return array();
+ }
</ins><span class="cx">
</span><del>- return isset($data['namespace'])
- ? $data['namespace']
- : array();
</del><ins>+ $this->_sendLine($this->_clientCommand('NAMESPACE'));
+
+ return $this->_temp['namespace'];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse a NAMESPACE response (RFC 2342 [5] & RFC 5255 [3.4]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The NAMESPACE data.
</span><span class="cx"> */
</span><del>- protected function _parseNamespace(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseNamespace(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><span class="cx"> $namespace_array = array(
</span><span class="cx"> Horde_Imap_Client::NS_PERSONAL,
</span><span class="lines">@@ -305,6 +291,7 @@
</span><span class="cx"> Horde_Imap_Client::NS_SHARED
</span><span class="cx"> );
</span><span class="cx">
</span><ins>+ $c = &$this->_temp['namespace'];
</ins><span class="cx"> $c = array();
</span><span class="cx">
</span><span class="cx"> // Per RFC 2342, response from NAMESPACE command is:
</span><span class="lines">@@ -340,8 +327,6 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> }
</span><del>-
- $pipeline->data['namespace'] = $c;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -367,15 +352,14 @@
</span><span class="cx"> $this->_connect();
</span><span class="cx">
</span><span class="cx"> $first_login = empty($this->_init['authmethod']);
</span><del>- $secure = $this->getParam('secure');
</del><ins>+ $t = &$this->_temp;
</ins><span class="cx">
</span><span class="cx"> // Switch to secure channel if using TLS.
</span><del>- if (!$this->isSecureConnection() &&
- (($secure === 'tls') ||
- (($secure === true) && $this->queryCapability('LOGINDISABLED')))) {
</del><ins>+ if (!$this->_isSecure &&
+ ($this->_params['secure'] == 'tls')) {
</ins><span class="cx"> if ($first_login && !$this->queryCapability('STARTTLS')) {
</span><del>- /* We should never hit this - STARTTLS is required pursuant to
- * RFC 3501 [6.2.1]. */
</del><ins>+ // We should never hit this - STARTTLS is required pursuant
+ // to RFC 3501 [6.2.1].
</ins><span class="cx"> throw new Horde_Imap_Client_Exception(
</span><span class="cx"> Horde_Imap_Client_Translation::t("Server does not support TLS connections."),
</span><span class="cx"> Horde_Imap_Client_Exception::LOGIN_TLSFAILURE
</span><span class="lines">@@ -384,9 +368,9 @@
</span><span class="cx">
</span><span class="cx"> // Switch over to a TLS connection.
</span><span class="cx"> // STARTTLS returns no untagged response.
</span><del>- $this->_sendCmd($this->_command('STARTTLS'));
</del><ins>+ $this->_sendLine($this->_clientCommand('STARTTLS'));
</ins><span class="cx">
</span><del>- if (!$this->_connection->startTls()) {
</del><ins>+ if (@stream_socket_enable_crypto($this->_stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT) !== true) {
</ins><span class="cx"> $this->logout();
</span><span class="cx"> throw new Horde_Imap_Client_Exception(
</span><span class="cx"> Horde_Imap_Client_Translation::t("Could not open secure TLS connection to the IMAP server."),
</span><span class="lines">@@ -394,8 +378,6 @@
</span><span class="cx"> );
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $this->setParam('secure', 'tls');
-
</del><span class="cx"> if ($first_login) {
</span><span class="cx"> // Expire cached CAPABILITY information (RFC 3501 [6.2.1])
</span><span class="cx"> $this->_setInit('capability');
</span><span class="lines">@@ -408,106 +390,111 @@
</span><span class="cx"> if (!empty($this->_init['imapproxy'])) {
</span><span class="cx"> $this->setLanguage();
</span><span class="cx"> }
</span><ins>+
+ $this->_isSecure = true;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if ($first_login) {
</span><del>- // Add authentication methods.
- $auth_mech = array();
</del><ins>+ $imap_auth_mech = array();
</ins><span class="cx">
</span><del>- $auth = ($auth = $this->queryCapability('AUTH'))
- ? array_flip($auth)
- : array();
</del><ins>+ $auth_methods = $this->queryCapability('AUTH');
+ if (!empty($auth_methods)) {
+ // Add SASL methods. Prefer CRAM-MD5 over DIGEST-MD5, as the
+ // latter has been obsoleted (RFC 6331).
+ $imap_auth_mech = array_intersect(array('CRAM-MD5', 'DIGEST-MD5'), $auth_methods);
</ins><span class="cx">
</span><del>- // XOAUTH2
- if (isset($auth['XOAUTH2']) && $this->getParam('xoauth2_token')) {
- $auth_mech[] = 'XOAUTH2';
- unset($auth['XOAUTH2']);
</del><ins>+ // Next, try 'PLAIN' authentication.
+ if (in_array('PLAIN', $auth_methods)) {
+ $imap_auth_mech[] = 'PLAIN';
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- // 'PLAIN' authentication always exists if under TLS. Use it over
- // all over authentication methods.
- if ($this->isSecureConnection()) {
- $auth_mech[] = 'PLAIN';
- unset($auth['PLAIN']);
- }
-
- // Prefer CRAM-MD5 over DIGEST-MD5, as the latter has been
- // obsoleted (RFC 6331).
- if (isset($auth['CRAM-MD5'])) {
- $auth_mech[] = 'CRAM-MD5';
- } elseif (isset($auth['DIGEST-MD5'])) {
- $auth_mech[] = 'DIGEST-MD5';
- }
- unset($auth['CRAM-MD5'], $auth['DIGEST-MD5']);
-
</del><span class="cx"> // Fall back to 'LOGIN' if available.
</span><del>- $auth_mech = array_merge($auth_mech, array_keys($auth));
</del><span class="cx"> if (!$this->queryCapability('LOGINDISABLED')) {
</span><del>- $auth_mech[] = 'LOGIN';
</del><ins>+ $imap_auth_mech[] = 'LOGIN';
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- if (empty($auth_mech)) {
</del><ins>+ if (empty($imap_auth_mech)) {
</ins><span class="cx"> throw new Horde_Imap_Client_Exception(
</span><span class="cx"> Horde_Imap_Client_Translation::t("No supported IMAP authentication method could be found."),
</span><span class="cx"> Horde_Imap_Client_Exception::LOGIN_NOAUTHMETHOD
</span><span class="cx"> );
</span><span class="cx"> }
</span><ins>+
+ /* Use MD5 authentication first, if available. But no need to use
+ * special authentication if we are already using an encrypted
+ * connection. */
+ if ($this->_isSecure) {
+ $imap_auth_mech = array_reverse($imap_auth_mech);
+ }
</ins><span class="cx"> } else {
</span><del>- $auth_mech = array($this->_init['authmethod']);
</del><ins>+ $imap_auth_mech = array($this->_init['authmethod']);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- $login_err = null;
</del><ins>+ /* Default to AUTHENTICATIONFAILED error (see RFC 5530[3]). */
+ $t['loginerr'] = new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Mail server denied authentication."),
+ Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED
+ );
</ins><span class="cx">
</span><del>- foreach ($auth_mech as $method) {
</del><ins>+ foreach ($imap_auth_mech as $method) {
+ $t['referral'] = null;
+
+ /* Set a flag indicating whether we have received a CAPABILITY
+ * response after we successfully login. Since capabilities may
+ * be different after login, we need to merge this information into
+ * the current CAPABILITY array (since some servers, e.g. Cyrus,
+ * may not include authentication capabilities that are still
+ * needed in the event this object is eventually serialized). */
+ $t['in_login'] = true;
+
</ins><span class="cx"> try {
</span><del>- $resp = $this->_tryLogin($method);
- $data = $resp->data;
</del><ins>+ $this->_tryLogin($method);
+ $success = true;
</ins><span class="cx"> $this->_setInit('authmethod', $method);
</span><del>- unset($this->_temp['referralcount']);
- } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
- $data = $e->resp_data;
- if (isset($data['loginerr'])) {
- $login_err = $data['loginerr'];
- }
- $resp = false;
</del><ins>+ unset($t['referralcount']);
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {
</span><del>- $resp = false;
</del><ins>+ $success = false;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ unset($t['in_login']);
+
</ins><span class="cx"> // Check for login referral (RFC 2221) response - can happen for
</span><span class="cx"> // an OK, NO, or BYE response.
</span><del>- if (isset($data['referral'])) {
</del><ins>+ if (!is_null($t['referral'])) {
</ins><span class="cx"> foreach (array('hostspec', 'port', 'username') as $val) {
</span><del>- if (!is_null($data['referral']->$val)) {
- $this->setParam($val, $data['referral']->$val);
</del><ins>+ if (!is_null($t['referral']->$val)) {
+ $this->_params[$val] = $t['referral']->$val;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (!is_null($data['referral']->auth)) {
- $this->_setInit('authmethod', $data['referral']->auth);
</del><ins>+ if (!is_null($t['referral']->auth)) {
+ $this->_setInit('authmethod', $t['referral']->auth);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- if (!isset($this->_temp['referralcount'])) {
- $this->_temp['referralcount'] = 0;
</del><ins>+ if (!isset($t['referralcount'])) {
+ $t['referralcount'] = 0;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // RFC 2221 [3] - Don't follow more than 10 levels of referral
</span><span class="cx"> // without consulting the user.
</span><del>- if (++$this->_temp['referralcount'] < 10) {
</del><ins>+ if (++$t['referralcount'] < 10) {
</ins><span class="cx"> $this->logout();
</span><span class="cx"> $this->_setInit('capability');
</span><span class="cx"> $this->_setInit('namespace', array());
</span><span class="cx"> return $this->login();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- unset($this->_temp['referralcount']);
</del><ins>+ unset($t['referralcount']);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- if ($resp) {
- return $this->_loginTasks($first_login, $resp->data);
</del><ins>+ if ($success) {
+ return $this->_loginTasks($first_login);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ $ex = $t['loginerr'];
+
</ins><span class="cx"> /* Try again from scratch if authentication failed in an established,
</span><span class="cx"> * previously-authenticated object. */
</span><span class="cx"> if (!empty($this->_init['authmethod'])) {
</span><span class="lines">@@ -517,15 +504,7 @@
</span><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {}
</span><span class="cx"> }
</span><span class="cx">
</span><del>- /* Default to AUTHENTICATIONFAILED error (see RFC 5530[3]). */
- if (is_null($login_err)) {
- throw new Horde_Imap_Client_Exception(
- Horde_Imap_Client_Translation::t("Mail server denied authentication."),
- Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED
- );
- }
-
- throw $login_err;
</del><ins>+ throw $ex;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -535,21 +514,53 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _connect()
</span><span class="cx"> {
</span><del>- if (!is_null($this->_connection)) {
</del><ins>+ if (!is_null($this->_stream)) {
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $this->_connection = new Horde_Imap_Client_Socket_Connection_Socket($this, $this->_debug);
</del><ins>+ if (!empty($this->_params['secure']) && !extension_loaded('openssl')) {
+ throw new InvalidArgumentException('Secure connections require the PHP openssl extension.');
+ }
</ins><span class="cx">
</span><ins>+ switch ($this->_params['secure']) {
+ case 'ssl':
+ case 'sslv2':
+ case 'sslv3':
+ $conn = $this->_params['secure'] . '://';
+ $this->_isSecure = true;
+ break;
+
+ case 'tls':
+ default:
+ $conn = 'tcp://';
+ break;
+ }
+
+ $this->_stream = @stream_socket_client($conn . $this->_params['hostspec'] . ':' . $this->_params['port'], $error_number, $error_string, $this->_params['timeout']);
+
+ if ($this->_stream === false) {
+ $this->_stream = null;
+ $this->_isSecure = false;
+ $e = new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Error connecting to mail server."),
+ Horde_Imap_Client_Exception::SERVER_CONNECT
+ );
+ $e->details = sprintf("[%u] %s", $error_number, $error_string);
+ throw $e;
+ }
+
+ stream_set_timeout($this->_stream, $this->_params['timeout']);
+
</ins><span class="cx"> // If we already have capability information, don't re-set with
</span><del>- // (possibly) limited information sent in the initial banner.
</del><ins>+ // (possibly) limited information sent in the inital banner.
</ins><span class="cx"> if (isset($this->_init['capability'])) {
</span><span class="cx"> $this->_temp['no_cap'] = true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- /* Get greeting information (untagged response). */
</del><ins>+ /* Get greeting information. This is untagged so we need to specially
+ * deal with it here. */
</ins><span class="cx"> try {
</span><del>- $this->_getLine($this->_pipeline());
</del><ins>+ $this->_getLine();
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
</span><span class="cx"> if ($e->status == Horde_Imap_Client_Interaction_Server::BYE) {
</span><span class="cx"> /* Server is explicitly rejecting our connection (RFC 3501
</span><span class="lines">@@ -588,103 +599,89 @@
</span><span class="cx"> *
</span><span class="cx"> * @param string $method IMAP login method.
</span><span class="cx"> *
</span><del>- * @return Horde_Imap_Client_Interaction_Pipeline Pipeline object.
- *
</del><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><span class="cx"> protected function _tryLogin($method)
</span><span class="cx"> {
</span><del>- $username = $this->getParam('username');
- $password = $this->getParam('password');
-
- $authenticate_cmd = false;
-
</del><span class="cx"> switch ($method) {
</span><span class="cx"> case 'CRAM-MD5':
</span><span class="cx"> case 'CRAM-SHA1':
</span><span class="cx"> case 'CRAM-SHA256':
</span><span class="cx"> // RFC 2195: CRAM-MD5
</span><span class="cx"> // CRAM-SHA1 & CRAM-SHA256 supported by Courier SASL library
</span><ins>+ $ob = $this->_sendLine(
+ $this->_clientCommand(array('AUTHENTICATE', $method))
+ );
</ins><span class="cx">
</span><del>- // Need $args because PHP 5.3 doesn't allow access to $this in
- // anonymous functions.
- $args = array(
- $username,
- strtolower(substr($method, 5)),
- $password
</del><ins>+ $cmd = new Horde_Imap_Client_Data_Format_List(
+ base64_encode($this->_params['username'] . ' ' . hash_hmac(strtolower(substr($method, 5)), base64_decode($ob->token->current()), $this->getParam('password'), false))
</ins><span class="cx"> );
</span><del>-
- $cmd = $this->_command('AUTHENTICATE')->add(array(
- $method,
- new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) use ($args) {
- return new Horde_Imap_Client_Data_Format_List(
- base64_encode($args[0] . ' ' . hash_hmac($args[1], base64_decode($ob->token->current()), $args[2], false))
- );
- })
</del><ins>+ $this->_sendLine($cmd, array(
+ 'debug' => '[' . $method . ' Response]'
</ins><span class="cx"> ));
</span><del>- $cmd->debug = sprintf('[AUTHENTICATE %s Command - username: %s]', $method, $username);
</del><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'DIGEST-MD5':
</span><span class="cx"> // RFC 2831/4422; obsoleted by RFC 6331
</span><ins>+ $ob = $this->_sendLine(
+ $this->_clientCommand(array('AUTHENTICATE', $method))
+ );
</ins><span class="cx">
</span><del>- // Need $args because PHP 5.3 doesn't allow access to $this in
- // anonymous functions.
- $args = array(
- $username,
- $password,
- $this->getParam('hostspec')
</del><ins>+ $cmd = new Horde_Imap_Client_Data_Format_List(
+ base64_encode(new Horde_Imap_Client_Auth_DigestMD5(
+ $this->_params['username'],
+ $this->getParam('password'),
+ base64_decode($ob->token->current()),
+ $this->_params['hostspec'],
+ 'imap'
+ ))
</ins><span class="cx"> );
</span><ins>+ $ob = $this->_sendLine($cmd, array(
+ 'debug' => '[DIGEST-MD5 Response]'
+ ));
</ins><span class="cx">
</span><del>- $cmd = $this->_command('AUTHENTICATE')->add(array(
- $method,
- new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) use ($args) {
- return new Horde_Imap_Client_Data_Format_List(
- base64_encode(new Horde_Imap_Client_Auth_DigestMD5(
- $args[0],
- $args[1],
- base64_decode($ob->token->current()),
- $args[2],
- 'imap'
- ))
- );
- }),
- new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) {
- if (strpos(base64_decode($ob->token->current()), 'rspauth=') === false) {
- throw new Horde_Imap_Client_Exception(
- Horde_Imap_Client_Translation::t("Unexpected response from server when authenticating."),
- Horde_Imap_Client_Exception::SERVER_CONNECT
- );
- }
-
- return new Horde_Imap_Client_Data_Format_List();
- })
- ));
- $cmd->debug = sprintf('[AUTHENTICATE DIGEST-MD5 Command - username: %s]', $username);
</del><ins>+ if (strpos(base64_decode($ob->token->current()), 'rspauth=') === false) {
+ throw new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Unexpected response from server when authenticating."),
+ Horde_Imap_Client_Exception::SERVER_CONNECT
+ );
+ }
+ $this->_sendLine(new Horde_Imap_Client_Data_Format_List());
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'LOGIN':
</span><del>- $cmd = $this->_command('LOGIN')->add(array(
- new Horde_Imap_Client_Data_Format_Astring($username),
- new Horde_Imap_Client_Data_Format_Astring($password)
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'LOGIN',
+ new Horde_Imap_Client_Data_Format_Astring($this->_params['username']),
+ new Horde_Imap_Client_Data_Format_Astring($this->getParam('password'))
</ins><span class="cx"> ));
</span><del>- $cmd->debug = sprintf('[LOGIN Command - username: %s]', $username);
</del><ins>+ $this->_sendLine($cmd, array(
+ 'debug' => sprintf('[LOGIN Command - username: %s]', $this->_params['username'])
+ ));
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'PLAIN':
</span><span class="cx"> // RFC 2595/4616 - PLAIN SASL mechanism
</span><del>- $auth = base64_encode(implode("\0", array(
- $username,
- $username,
- $password
- )));
- $authenticate_cmd = true;
- break;
</del><ins>+ $auth = base64_encode(implode("\0", array($this->_params['username'], $this->_params['username'], $this->getParam('password'))));
+ $cmd = $this->_clientCommand(array(
+ 'AUTHENTICATE',
+ 'PLAIN'
+ ));
</ins><span class="cx">
</span><del>- case 'XOAUTH2':
- // Google XOAUTH2
- $auth = $this->getParam('xoauth2_token');
- $authenticate_cmd = true;
</del><ins>+ if ($this->queryCapability('SASL-IR')) {
+ // IMAP Extension for SASL Initial Client Response (RFC 4959)
+ $cmd->add($auth);
+ $this->_sendLine($cmd, array(
+ 'debug' => sprintf('[SASL-IR AUTHENTICATE Command - username: %s]', $this->_params['username'])
+ ));
+ } else {
+ $this->_sendLine($cmd);
+
+ $cmd = new Horde_Imap_Client_Data_Format_List($auth);
+ $this->_sendLine($cmd, array(
+ 'debug' => sprintf('[AUTHENTICATE Command - username: %s]', $this->_params['username'])
+ ));
+ }
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> default:
</span><span class="lines">@@ -693,71 +690,35 @@
</span><span class="cx"> Horde_Imap_Client_Exception::SERVER_CONNECT
</span><span class="cx"> );
</span><span class="cx"> }
</span><del>-
- if ($authenticate_cmd) {
- $cmd = $this->_command('AUTHENTICATE')->add($method);
-
- if ($this->queryCapability('SASL-IR')) {
- // IMAP Extension for SASL Initial Client Response (RFC 4959)
- $cmd->add($auth);
- $cmd->debug = sprintf('[SASL-IR AUTHENTICATE Command - method: %s, username: %s]', $method, $username);
- } else {
- $cmd->add(new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) use ($auth) {
- return new Horde_Imap_Client_Data_Format_List($auth);
- }));
- $cmd->debug = sprintf('[AUTHENTICATE Command - method: %s, username: %s]', $method, $username);
- }
-
- /* This is an optional command continuation. E.g. XOAUTH2 will
- * return error information in continuation response. */
- $error_continuation = new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) {
- return new Horde_Imap_Client_Data_Format_List();
- });
- $error_continuation->optional = true;
- $cmd->add($error_continuation);
- }
-
- return $this->_sendCmd($this->_pipeline($cmd));
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Perform login tasks.
</span><span class="cx"> *
</span><span class="cx"> * @param boolean $firstlogin Is this the first login?
</span><del>- * @param array $resp The data response from the login command.
- * May include:
- * - capability_set: (boolean) True if CAPABILITY was set after login.
- * - proxyreuse: (boolean) True if re-used connection via imapproxy.
</del><span class="cx"> *
</span><span class="cx"> * @return boolean True if global login tasks should be performed.
</span><span class="cx"> */
</span><del>- protected function _loginTasks($firstlogin = true, array $resp = array())
</del><ins>+ protected function _loginTasks($firstlogin = true)
</ins><span class="cx"> {
</span><span class="cx"> /* If reusing an imapproxy connection, no need to do any of these
</span><span class="cx"> * login tasks again. */
</span><del>- if (!$firstlogin && !empty($resp['proxyreuse'])) {
- if (isset($this->_init['enabled'])) {
- $this->_temp['enabled'] = $this->_init['enabled'];
- }
-
</del><ins>+ if (!$firstlogin && !empty($this->_temp['proxyreuse'])) {
</ins><span class="cx"> // If we have not yet set the language, set it now.
</span><span class="cx"> if (!isset($this->_init['lang'])) {
</span><del>- $this->_temp['lang_queue'] = true;
</del><span class="cx"> $this->setLanguage();
</span><del>- unset($this->_temp['lang_queue']);
</del><span class="cx"> }
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ $this->_setInit('enabled', array());
+
</ins><span class="cx"> /* If we logged in for first time, and server did not return
</span><del>- * capability information, we need to mark for retrieval. */
- if ($firstlogin && empty($resp['capability_set'])) {
</del><ins>+ * capability information, we need to grab it now. */
+ if ($firstlogin && empty($this->_temp['logincapset'])) {
</ins><span class="cx"> $this->_setInit('capability');
</span><span class="cx"> }
</span><del>-
- $this->_temp['lang_queue'] = true;
</del><span class="cx"> $this->setLanguage();
</span><del>- unset($this->_temp['lang_queue']);
</del><span class="cx">
</span><span class="cx"> /* Only active QRESYNC/CONDSTORE if caching is enabled. */
</span><span class="cx"> if ($this->_initCache()) {
</span><span class="lines">@@ -775,30 +736,28 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _logout()
</span><span class="cx"> {
</span><del>- if (empty($this->_temp['logout'])) {
- /* If using imapproxy, force sending these commands, since they
- * may not be sent again if they are (likely) initialization
- * commands. */
- if (!empty($this->_cmdQueue) &&
- !empty($this->_init['imapproxy'])) {
- $this->_sendCmd($this->_pipeline());
</del><ins>+ if (!is_null($this->_stream)) {
+ if (empty($this->_temp['logout'])) {
+ $this->_temp['logout'] = true;
+ try {
+ $this->_sendLine($this->_clientCommand('LOGOUT'));
+ } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
+ // Ignore server errors
+ }
</ins><span class="cx"> }
</span><del>-
- $this->_temp['logout'] = true;
- try {
- $this->_sendCmd($this->_command('LOGOUT'));
- } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
- // Ignore server errors
- }
</del><span class="cx"> unset($this->_temp['logout']);
</span><ins>+ @fclose($this->_stream);
+ $this->_stream = null;
</ins><span class="cx"> }
</span><ins>+
+ unset($this->_temp['proxyreuse']);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><span class="cx"> protected function _sendID($info)
</span><span class="cx"> {
</span><del>- $cmd = $this->_command('ID');
</del><ins>+ $cmd = $this->_clientCommand('ID');
</ins><span class="cx">
</span><span class="cx"> if (empty($info)) {
</span><span class="cx"> $cmd->add(new Horde_Imap_Client_Data_Format_Nil());
</span><span class="lines">@@ -813,32 +772,25 @@
</span><span class="cx"> $cmd->add($tmp);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $this->_temp['id'] = $this->_sendCmd($cmd)->data['id'];
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Parse an ID response (RFC 2971 [3.2]).
</del><ins>+ * Parse an ID response (RFC 2971 [3.2])
</ins><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response.
</span><span class="cx"> */
</span><del>- protected function _parseID(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseID(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><del>- $ids = array();
</del><ins>+ $this->_temp['id'] = array();
</ins><span class="cx">
</span><span class="cx"> if (!is_null($data->next())) {
</span><span class="cx"> while (($curr = $data->next()) !== false) {
</span><span class="cx"> if (!is_null($id = $data->next())) {
</span><del>- $ids[$curr] = $id;
</del><ins>+ $this->_temp['id'][$curr] = $id;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> }
</span><del>-
- $pipeline->data['id'] = $ids;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -848,7 +800,6 @@
</span><span class="cx"> if (!isset($this->_temp['id'])) {
</span><span class="cx"> $this->sendID();
</span><span class="cx"> }
</span><del>-
</del><span class="cx"> return $this->_temp['id'];
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -856,18 +807,13 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _setLanguage($langs)
</span><span class="cx"> {
</span><del>- $cmd = $this->_command('LANGUAGE');
</del><ins>+ $cmd = $this->_clientCommand('LANGUAGE');
</ins><span class="cx"> foreach ($langs as $lang) {
</span><span class="cx"> $cmd->add(new Horde_Imap_Client_Data_Format_Astring($lang));
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (!empty($this->_temp['lang_queue'])) {
- $this->_cmdQueue[] = $cmd;
- return array();
- }
-
</del><span class="cx"> try {
</span><del>- $this->_sendCmd($cmd);
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {
</span><span class="cx"> $this->_setInit('lang', false);
</span><span class="cx"> return null;
</span><span class="lines">@@ -888,7 +834,7 @@
</span><span class="cx">
</span><span class="cx"> if (!isset($this->_init['langavail'])) {
</span><span class="cx"> try {
</span><del>- $this->_sendCmd($this->_command('LANGUAGE'));
</del><ins>+ $this->_sendLine($this->_clientCommand('LANGUAGE'));
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {
</span><span class="cx"> $this->_setInit('langavail', array());
</span><span class="cx"> }
</span><span class="lines">@@ -925,11 +871,14 @@
</span><span class="cx"> protected function _enable($exts)
</span><span class="cx"> {
</span><span class="cx"> if ($this->queryCapability('ENABLE')) {
</span><del>- // Only enable non-enabled extensions.
- $exts = array_diff($exts, array_keys($this->_temp['enabled']));
</del><ins>+ // Only enable non-enabled extensions
+ $exts = array_diff($exts, array_keys($this->_init['enabled']));
</ins><span class="cx"> if (!empty($exts)) {
</span><del>- $this->_cmdQueue[] = $this->_command('ENABLE')->add($exts);
- $this->_enabled($exts, 1);
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'ENABLE',
+ $exts
+ ));
+ $this->_sendLine($cmd);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -941,32 +890,22 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _parseEnabled(Horde_Imap_Client_Tokenize $data)
</span><span class="cx"> {
</span><del>- $this->_enabled($data->flushIterator(), 2);
</del><ins>+ $this->_setInit('enabled', array_merge(
+ $this->_init['enabled'],
+ array_flip($data->flushIterator())
+ ));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><del>- protected function _enabled($exts, $status)
- {
- parent::_enabled($exts, $status);
-
- if (($status == 2) && !empty($this->_init['imapproxy'])) {
- $this->_setInit('enabled', $this->_temp['enabled']);
- }
- }
-
- /**
- */
</del><span class="cx"> protected function _openMailbox(Horde_Imap_Client_Mailbox $mailbox, $mode)
</span><span class="cx"> {
</span><del>- $qresync = isset($this->_temp['enabled']['QRESYNC']);
</del><ins>+ $qresync = isset($this->_init['enabled']['QRESYNC']);
</ins><span class="cx">
</span><del>- $cmd = $this->_command(
- ($mode == Horde_Imap_Client::OPEN_READONLY) ? 'EXAMINE' : 'SELECT'
- )->add(
</del><ins>+ $cmd = $this->_clientCommand(array(
+ ($mode == Horde_Imap_Client::OPEN_READONLY) ? 'EXAMINE' : 'SELECT',
</ins><span class="cx"> new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
</span><del>- );
- $pipeline = $this->_pipeline($cmd);
</del><ins>+ ));
</ins><span class="cx">
</span><span class="cx"> /* If QRESYNC is available, synchronize the mailbox. */
</span><span class="cx"> if ($qresync) {
</span><span class="lines">@@ -1011,24 +950,27 @@
</span><span class="cx"> /* Let the 'CLOSED' response code handle mailbox switching if
</span><span class="cx"> * QRESYNC is active. */
</span><span class="cx"> if ($this->_selected) {
</span><del>- $pipeline->data['qresyncmbox'] = array($mailbox, $mode);
</del><ins>+ $this->_temp['qresyncmbox'] = array($mailbox, $mode);
</ins><span class="cx"> } else {
</span><span class="cx"> $this->_changeSelected($mailbox, $mode);
</span><span class="cx"> }
</span><span class="cx"> } else {
</span><del>- if (!isset($this->_temp['enabled']['CONDSTORE']) &&
</del><ins>+ if (!isset($this->_init['enabled']['CONDSTORE']) &&
</ins><span class="cx"> $this->_initCache() &&
</span><span class="cx"> $this->queryCapability('CONDSTORE')) {
</span><span class="cx"> /* Activate CONDSTORE now if ENABLE is not available. */
</span><span class="cx"> $cmd->add(new Horde_Imap_Client_Data_Format_List('CONDSTORE'));
</span><del>- $this->_enabled(array('CONDSTORE'), 2);
</del><ins>+ $this->_setInit('enabled', array_merge(
+ $this->_init['enabled'],
+ array('CONDSTORE' => true)
+ ));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> $this->_changeSelected($mailbox, $mode);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> try {
</span><del>- $this->_sendCmd($pipeline);
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
</span><span class="cx"> // An EXAMINE/SELECT failure with a return of 'NO' will cause the
</span><span class="cx"> // current mailbox to be unselected.
</span><span class="lines">@@ -1055,9 +997,10 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _createMailbox(Horde_Imap_Client_Mailbox $mailbox, $opts)
</span><span class="cx"> {
</span><del>- $cmd = $this->_command('CREATE')->add(
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'CREATE',
</ins><span class="cx"> new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
</span><del>- );
</del><ins>+ ));
</ins><span class="cx">
</span><span class="cx"> if (!empty($opts['special_use'])) {
</span><span class="cx"> $cmd->add(array(
</span><span class="lines">@@ -1067,7 +1010,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // CREATE returns no untagged information (RFC 3501 [6.3.3])
</span><del>- $this->_sendCmd($cmd);
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -1080,21 +1023,29 @@
</span><span class="cx"> $this->close();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $cmd = $this->_command('DELETE')->add(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
- );
-
</del><span class="cx"> try {
</span><span class="cx"> // DELETE returns no untagged information (RFC 3501 [6.3.4])
</span><del>- $this->_sendCmd($cmd);
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'DELETE',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
+ ));
+ $this->_sendLine($cmd);
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {
</span><span class="cx"> // Some IMAP servers won't allow a mailbox delete unless all
</span><span class="cx"> // messages in that mailbox are deleted.
</span><del>- $this->expunge($mailbox, array(
- 'delete' => true
- ));
- $this->_sendCmd($cmd);
</del><ins>+ if (!empty($this->_temp['deleteretry'])) {
+ unset($this->_temp['deleteretry']);
+ throw $e;
+ }
+
+ $this->store($mailbox, array('add' => array(Horde_Imap_Client::FLAG_DELETED)));
+ $this->expunge($mailbox);
+
+ $this->_temp['deleteretry'] = true;
+ $this->deleteMailbox($mailbox);
</ins><span class="cx"> }
</span><ins>+
+ unset($this->_temp['deleteretry']);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -1109,12 +1060,12 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // RENAME returns no untagged information (RFC 3501 [6.3.5])
</span><del>- $this->_sendCmd(
- $this->_command('RENAME')->add(array(
- new Horde_Imap_Client_Data_Format_Mailbox($old),
- new Horde_Imap_Client_Data_Format_Mailbox($new)
- ))
- );
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'RENAME',
+ new Horde_Imap_Client_Data_Format_Mailbox($old),
+ new Horde_Imap_Client_Data_Format_Mailbox($new)
+ ));
+ $this->_sendLine($cmd);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -1124,13 +1075,11 @@
</span><span class="cx"> {
</span><span class="cx"> // SUBSCRIBE/UNSUBSCRIBE returns no untagged information (RFC 3501
</span><span class="cx"> // [6.3.6 & 6.3.7])
</span><del>- $this->_sendCmd(
- $this->_command(
- $subscribe ? 'SUBSCRIBE' : 'UNSUBSCRIBE'
- )->add(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
- )
- );
</del><ins>+ $cmd = $this->_clientCommand(array(
+ $subscribe ? 'SUBSCRIBE' : 'UNSUBSCRIBE',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
+ ));
+ $this->_sendLine($cmd);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -1195,24 +1144,22 @@
</span><span class="cx"> {
</span><span class="cx"> $check = (($mode != Horde_Imap_Client::MBOX_ALL) && !is_null($subscribed));
</span><span class="cx">
</span><del>- // Setup entry for use in _parseList().
- $pipeline = $this->_pipeline();
- $pipeline->data['mailboxlist'] = array(
</del><ins>+ // Setup cache entry for use in _parseList()
+ $t = &$this->_temp;
+ $t['mailboxlist'] = array(
</ins><span class="cx"> 'check' => $check,
</span><span class="cx"> 'ext' => false,
</span><span class="cx"> 'options' => $options,
</span><span class="cx"> 'subexist' => ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS),
</span><span class="cx"> 'subscribed' => ($check ? array_flip(array_map('strval', $subscribed)) : null)
</span><span class="cx"> );
</span><del>- $pipeline->data['listresponse'] = array();
-
- $cmds = array();
</del><ins>+ $t['listresponse'] = array();
</ins><span class="cx"> $return_opts = new Horde_Imap_Client_Data_Format_List();
</span><span class="cx">
</span><span class="cx"> if ($this->queryCapability('LIST-EXTENDED') &&
</span><span class="cx"> empty($options['no_listext'])) {
</span><del>- $cmd = $this->_command('LIST');
- $pipeline->data['mailboxlist']['ext'] = true;
</del><ins>+ $cmd = $this->_clientCommand('LIST');
+ $t['mailboxlist']['ext'] = true;
</ins><span class="cx">
</span><span class="cx"> $select_opts = new Horde_Imap_Client_Data_Format_List();
</span><span class="cx">
</span><span class="lines">@@ -1248,17 +1195,18 @@
</span><span class="cx"> if (!empty($options['special_use'])) {
</span><span class="cx"> $return_opts->add('SPECIAL-USE');
</span><span class="cx"> }
</span><del>-
- $cmds[] = $cmd;
- } else {
</del><ins>+ } elseif (count($pattern) > 1) {
+ $return_array = array();
</ins><span class="cx"> foreach ($pattern as $val) {
</span><del>- $cmds[] = $this->_command(
- ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ? 'LSUB' : 'LIST'
- )->add(array(
- '',
- new Horde_Imap_Client_Data_Format_ListMailbox($val)
- ));
</del><ins>+ $return_array = array_merge($return_array, $this->_getMailboxList(array($val), $mode, $options, $subscribed));
</ins><span class="cx"> }
</span><ins>+ return $return_array;
+ } else {
+ $cmd = $this->_clientCommand(array(
+ ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ? 'LSUB' : 'LIST',
+ '',
+ new Horde_Imap_Client_Data_Format_ListMailbox(reset($pattern))
+ ));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /* LIST-STATUS does NOT depend on LIST-EXTENDED. */
</span><span class="lines">@@ -1290,19 +1238,15 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- foreach ($cmds as $val) {
- if (count($return_opts)) {
- $val->add(array(
- 'RETURN',
- $return_opts
- ));
- }
-
- $pipeline->add($val);
</del><ins>+ if (count($return_opts)) {
+ $cmd->add(array(
+ 'RETURN',
+ $return_opts
+ ));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> try {
</span><del>- $lr = $this->_sendCmd($pipeline)->data['listresponse'];
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
</span><span class="cx"> /* Archiveopteryx 3.1.3 can't process empty list-select-opts list.
</span><span class="cx"> * Retry using base IMAP4rev1 functionality. */
</span><span class="lines">@@ -1316,42 +1260,43 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (!empty($options['flat'])) {
</span><del>- return array_values($lr);
</del><ins>+ return array_values($t['listresponse']);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /* Add in STATUS return, if needed. */
</span><span class="cx"> if (!empty($options['status'])) {
</span><span class="cx"> foreach ($pattern as $val) {
</span><span class="cx"> $val_utf8 = Horde_Imap_Client_Utf7imap::Utf7ImapToUtf8($val);
</span><del>- if (isset($lr[$val_utf8])) {
- $lr[$val_utf8]['status'] = $this->_prepareStatusResponse($status_opts, $val_utf8);
</del><ins>+ if (isset($t['listresponse'][$val_utf8])) {
+ $t['listresponse'][$val_utf8]['status'] = $this->_prepareStatusResponse($status_opts, $val_utf8);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return $lr;
</del><ins>+ $out = $t['listresponse'];
+ unset($t['listresponse']);
+
+ return $out;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse a LIST/LSUB response (RFC 3501 [7.2.2 & 7.2.3]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response (includes
</span><span class="cx"> * type as first token).
</span><span class="cx"> *
</span><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><del>- protected function _parseList(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseList(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><ins>+ $ml = $this->_temp['mailboxlist'];
+ $mlo = $ml['options'];
+ $lr = &$this->_temp['listresponse'];
+
</ins><span class="cx"> $data->next();
</span><span class="cx"> $attr = $data->flushIterator();
</span><span class="cx"> $delimiter = $data->next();
</span><span class="cx"> $mbox = Horde_Imap_Client_Mailbox::get($data->next(), true);
</span><del>- $ml = $pipeline->data['mailboxlist'];
</del><span class="cx">
</span><span class="cx"> if ($ml['check'] &&
</span><span class="cx"> $ml['subexist'] &&
</span><span class="lines">@@ -1359,8 +1304,7 @@
</span><span class="cx"> !isset($ml['subscribed'][strval($mbox)])) {
</span><span class="cx"> return;
</span><span class="cx"> } elseif ((!$ml['check'] && $ml['subexist']) ||
</span><del>- (empty($ml['options']['flat']) &&
- !empty($ml['options']['attributes']))) {
</del><ins>+ (empty($mlo['flat']) && !empty($mlo['attributes']))) {
</ins><span class="cx"> $attr = array_flip(array_map('strtolower', $attr));
</span><span class="cx"> if ($ml['subexist'] &&
</span><span class="cx"> !$ml['check'] &&
</span><span class="lines">@@ -1369,12 +1313,12 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (empty($ml['options']['flat'])) {
</del><ins>+ if (empty($mlo['flat'])) {
</ins><span class="cx"> $tmp = array(
</span><span class="cx"> 'mailbox' => $mbox
</span><span class="cx"> );
</span><span class="cx">
</span><del>- if (!empty($ml['options']['attributes'])) {
</del><ins>+ if (!empty($mlo['attributes'])) {
</ins><span class="cx"> /* RFC 5258 [3.4]: inferred attributes. */
</span><span class="cx"> if ($ml['ext']) {
</span><span class="cx"> if (isset($attr['\\noinferiors'])) {
</span><span class="lines">@@ -1386,127 +1330,118 @@
</span><span class="cx"> }
</span><span class="cx"> $tmp['attributes'] = array_keys($attr);
</span><span class="cx"> }
</span><del>- if (!empty($ml['options']['delimiter'])) {
</del><ins>+ if (!empty($mlo['delimiter'])) {
</ins><span class="cx"> $tmp['delimiter'] = $delimiter;
</span><span class="cx"> }
</span><span class="cx"> if ($data->next() !== false) {
</span><span class="cx"> $tmp['extended'] = $data->flushIterator();
</span><span class="cx"> }
</span><del>- $pipeline->data['listresponse'][strval($mbox)] = $tmp;
</del><ins>+ $lr[strval($mbox)] = $tmp;
</ins><span class="cx"> } else {
</span><del>- $pipeline->data['listresponse'][] = $mbox;
</del><ins>+ $lr[] = $mbox;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><del>- protected function _status($mboxes, $flags)
</del><ins>+ protected function _status(Horde_Imap_Client_Mailbox $mailbox, $flags)
</ins><span class="cx"> {
</span><del>- $out = $to_process = array();
- $pipeline = $this->_pipeline();
</del><ins>+ $data = $query = array();
</ins><span class="cx"> $unseen_flags = array(
</span><span class="cx"> Horde_Imap_Client::STATUS_FIRSTUNSEEN,
</span><span class="cx"> Horde_Imap_Client::STATUS_UNSEEN
</span><span class="cx"> );
</span><span class="cx">
</span><del>- foreach ($mboxes as $mailbox) {
- /* If FLAGS/PERMFLAGS/UIDNOTSTICKY/FIRSTUNSEEN are needed, we must
- * do a SELECT/EXAMINE to get this information (data will be
- * caught in the code below). */
- if (($flags & Horde_Imap_Client::STATUS_FIRSTUNSEEN) ||
- ($flags & Horde_Imap_Client::STATUS_FLAGS) ||
- ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) ||
- ($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY)) {
- $this->openMailbox($mailbox);
</del><ins>+ /* If FLAGS/PERMFLAGS/UIDNOTSTICKY/FIRSTUNSEEN are needed, we must do
+ * a SELECT/EXAMINE to get this information (data will be caught in
+ * the code below). */
+ if (($flags & Horde_Imap_Client::STATUS_FIRSTUNSEEN) ||
+ ($flags & Horde_Imap_Client::STATUS_FLAGS) ||
+ ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) ||
+ ($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY)) {
+ $this->openMailbox($mailbox);
+ }
+
+ $mbox_ob = $this->_mailboxOb($mailbox);
+
+ foreach ($this->_statusFields as $key => $val) {
+ if (!($val & $flags)) {
+ continue;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- $mbox_ob = $this->_mailboxOb($mailbox);
- $data = $query = array();
-
- foreach ($this->_statusFields as $key => $val) {
- if (!($val & $flags)) {
</del><ins>+ if ($val == Horde_Imap_Client::STATUS_HIGHESTMODSEQ) {
+ /* Don't include modseq returns if server does not support
+ * it. */
+ if (!$this->queryCapability('CONDSTORE')) {
</ins><span class="cx"> continue;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if ($val == Horde_Imap_Client::STATUS_HIGHESTMODSEQ) {
- /* Don't include modseq returns if server does not support
- * it. */
- if (!$this->queryCapability('CONDSTORE')) {
- continue;
- }
-
- /* Even though CONDSTORE is available, it may not yet have
- * been enabled. */
- if (!isset($this->_temp['enabled']['CONDSTORE'])) {
- $this->_enabled(array('CONDSTORE'), 2);
- }
</del><ins>+ /* Even though CONDSTORE is available, it may not yet have
+ * been enabled. */
+ if (!isset($this->_init['enabled']['CONDSTORE'])) {
+ $this->_setInit('enabled', array_merge(
+ $this->_init['enabled'],
+ array('CONDSTORE' => true)
+ ));
</ins><span class="cx"> }
</span><ins>+ }
</ins><span class="cx">
</span><del>- if ($mailbox->equals($this->_selected)) {
- if (!is_null($tmp = $mbox_ob->getStatus($val))) {
- $data[$key] = $tmp;
- } elseif (($val == Horde_Imap_Client::STATUS_UIDNEXT) &&
- ($flags & Horde_Imap_Client::STATUS_UIDNEXT_FORCE)) {
- /* UIDNEXT is not mandatory. */
- if ($mbox_ob->getStatus(Horde_Imap_Client::STATUS_MESSAGES) == 0) {
- $data[$key] = 0;
- } else {
- $fquery = new Horde_Imap_Client_Fetch_Query();
- $fquery->uid();
- $fetch_res = $this->fetch($this->_selected, $fquery, array(
- 'ids' => $this->getIdsOb(Horde_Imap_Client_Ids::LARGEST)
- ));
- $data[$key] = $fetch_res->first()->getUid() + 1;
- }
- } elseif (in_array($val, $unseen_flags)) {
- /* RFC 3501 [6.3.1] - FIRSTUNSEEN information is not
- * mandatory. If missing in EXAMINE/SELECT results, we
- * need to do a search. An UNSEEN count also requires
- * a search. */
- $squery = new Horde_Imap_Client_Search_Query();
- $squery->flag(Horde_Imap_Client::FLAG_SEEN, false);
- $search = $this->search($mailbox, $squery, array(
- 'results' => array(
- Horde_Imap_Client::SEARCH_RESULTS_MIN,
- Horde_Imap_Client::SEARCH_RESULTS_COUNT
- ),
- 'sequence' => true
</del><ins>+ if ($mailbox->equals($this->_selected)) {
+ if (!is_null($tmp = $mbox_ob->getStatus($val))) {
+ $data[$key] = $tmp;
+ } elseif (($val == Horde_Imap_Client::STATUS_UIDNEXT) &&
+ ($flags & Horde_Imap_Client::STATUS_UIDNEXT_FORCE)) {
+ /* UIDNEXT is not mandatory. */
+ if ($mbox_ob->getStatus(Horde_Imap_Client::STATUS_MESSAGES) == 0) {
+ $data[$key] = 0;
+ } else {
+ $fquery = new Horde_Imap_Client_Fetch_Query();
+ $fquery->uid();
+ $fetch_res = $this->fetch($this->_selected, $fquery, array(
+ 'ids' => $this->getIdsOb(Horde_Imap_Client_Ids::LARGEST)
</ins><span class="cx"> ));
</span><ins>+ $data[$key] = $fetch_res->first()->getUid() + 1;
+ }
+ } elseif (in_array($val, $unseen_flags)) {
+ /* RFC 3501 [6.3.1] - FIRSTUNSEEN information is not
+ * mandatory. If missing in EXAMINE/SELECT results, we
+ * need to do a search. An UNSEEN count also requires a
+ * search. */
+ $squery = new Horde_Imap_Client_Search_Query();
+ $squery->flag(Horde_Imap_Client::FLAG_SEEN, false);
+ $search = $this->search($mailbox, $squery, array(
+ 'results' => array(
+ Horde_Imap_Client::SEARCH_RESULTS_MIN,
+ Horde_Imap_Client::SEARCH_RESULTS_COUNT
+ ),
+ 'sequence' => true
+ ));
</ins><span class="cx">
</span><del>- $mbox_ob->setStatus(Horde_Imap_Client::STATUS_FIRSTUNSEEN, $search['min']);
- $mbox_ob->setStatus(Horde_Imap_Client::STATUS_UNSEEN, $search['count']);
</del><ins>+ $mbox_ob->setStatus(Horde_Imap_Client::STATUS_FIRSTUNSEEN, $search['min']);
+ $mbox_ob->setStatus(Horde_Imap_Client::STATUS_UNSEEN, $search['count']);
</ins><span class="cx">
</span><del>- $data[$key] = $mbox_ob->getStatus($val);
- }
- } else {
- $query[] = $key;
</del><ins>+ $data[$key] = $mbox_ob->getStatus($val);
</ins><span class="cx"> }
</span><ins>+ } else {
+ $query[] = $key;
</ins><span class="cx"> }
</span><ins>+ }
</ins><span class="cx">
</span><del>- $out[strval($mailbox)] = $data;
-
- if (count($query)) {
- $pipeline->add(
- $this->_command('STATUS')->add(array(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
- new Horde_Imap_Client_Data_Format_List(
- array_map('strtoupper', $query)
- )
- ))
- );
- $to_process[] = array($query, $mailbox);
- }
</del><ins>+ if (!count($query)) {
+ return $data;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- if (count($pipeline)) {
- $this->_sendCmd($pipeline);
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'STATUS',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
+ new Horde_Imap_Client_Data_Format_List(
+ array_map('strtoupper', $query)
+ )
+ ));
</ins><span class="cx">
</span><del>- foreach ($to_process as $val) {
- $out[strval($val[1])] += $this->_prepareStatusResponse($val[0], $val[1]);
- }
- }
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx">
</span><del>- return $out;
</del><ins>+ return $this->_prepareStatusResponse($query, $mailbox);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -1571,12 +1506,15 @@
</span><span class="cx"> // Check for CATENATE extension (RFC 4469)
</span><span class="cx"> $catenate = $this->queryCapability('CATENATE');
</span><span class="cx">
</span><del>- $asize = 0;
</del><ins>+ $t = &$this->_temp;
+ $t['appendsize'] = 0;
+ $t['appenduid'] = true;
+ $t['trycreate'] = null;
</ins><span class="cx">
</span><del>- $cmd = $this->_command('APPEND')->add(
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'APPEND',
</ins><span class="cx"> new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
</span><del>- );
- $cmd->literal8 = true;
</del><ins>+ ));
</ins><span class="cx">
</span><span class="cx"> foreach (array_keys($data) as $key) {
</span><span class="cx"> if (!empty($data[$key]['flags'])) {
</span><span class="lines">@@ -1609,7 +1547,7 @@
</span><span class="cx"> if ($catenate) {
</span><span class="cx"> $tmp->add(array(
</span><span class="cx"> 'TEXT',
</span><del>- $this->_appendData($v['v'], $asize)
</del><ins>+ $this->_appendData($v['v'])
</ins><span class="cx"> ));
</span><span class="cx"> } else {
</span><span class="cx"> if (is_resource($v['v'])) {
</span><span class="lines">@@ -1635,21 +1573,23 @@
</span><span class="cx"> if ($catenate) {
</span><span class="cx"> $cmd->add($tmp);
</span><span class="cx"> } else {
</span><del>- $cmd->add($this->_appendData($data_stream->stream, $asize));
</del><ins>+ $cmd->add($this->_appendData($data_stream->stream));
</ins><span class="cx"> }
</span><span class="cx"> } else {
</span><del>- $cmd->add($this->_appendData($data[$key]['data'], $asize));
</del><ins>+ $cmd->add($this->_appendData($data[$key]['data']));
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /* Although it is normally more efficient to use LITERAL+, disable if
</span><span class="cx"> * payload is over 0.5 MB because it allows the server to throw error
</span><span class="cx"> * before we potentially push a lot of data to server that would
</span><del>- * otherwise be ignored (see RFC 4549 [4.2.2.3]).
- * Additionally, if using BINARY, since so many IMAP servers have
- * issues with APPEND + BINARY, don't use LITERAL+ since servers may
- * send BAD after initial command. */
- $cmd->literalplus = (($asize < 524288) && !$this->queryCapability('BINARY'));
</del><ins>+ * otherwise be ignored (see RFC 4549 [4.2.2.3]). */
+ if (!($noliteralplus = ($this->_temp['appendsize'] > 524288))) {
+ /* Additionally, if using BINARY, since so many IMAP servers have
+ * issues with APPEND + BINARY, don't use LITERAL+ since servers
+ * may send BAD after initial command. */
+ $noliteralplus = $this->queryCapability('BINARY');
+ }
</ins><span class="cx">
</span><span class="cx"> // If the mailbox is currently selected read-only, we need to close
</span><span class="cx"> // because some IMAP implementations won't allow an append. And some
</span><span class="lines">@@ -1658,7 +1598,9 @@
</span><span class="cx"> $this->close();
</span><span class="cx">
</span><span class="cx"> try {
</span><del>- $resp = $this->_sendCmd($cmd);
</del><ins>+ $this->_sendLine($cmd, array(
+ 'noliteralplus' => $noliteralplus
+ ));
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {
</span><span class="cx"> switch ($e->getCode()) {
</span><span class="cx"> case $e::CATENATE_BADURL:
</span><span class="lines">@@ -1680,8 +1622,7 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (!empty($options['create']) &&
- !empty($e->resp_data['trycreate'])) {
</del><ins>+ if (!empty($options['create']) && $this->_temp['trycreate']) {
</ins><span class="cx"> $this->createMailbox($mailbox);
</span><span class="cx"> unset($options['create']);
</span><span class="cx"> return $this->_append($mailbox, $data, $options);
</span><span class="lines">@@ -1706,21 +1647,18 @@
</span><span class="cx">
</span><span class="cx"> /* If we reach this point and have data in 'appenduid', UIDPLUS (RFC
</span><span class="cx"> * 4315) has done the dirty work for us. */
</span><del>- return isset($resp->data['appenduid'])
- ? $resp->data['appenduid']
- : true;
</del><ins>+ return $t['appenduid'];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Prepares append message data for insertion into the IMAP command
</span><span class="cx"> * string.
</span><span class="cx"> *
</span><del>- * @param mixed $data Either a resource or a string.
- * @param integer &$asize Total append size.
</del><ins>+ * @param mixed $data Either a resource or a string.
</ins><span class="cx"> *
</span><span class="cx"> * @return Horde_Imap_Client_Data_Format_String The data object.
</span><span class="cx"> */
</span><del>- protected function _appendData($data, &$asize)
</del><ins>+ protected function _appendData($data)
</ins><span class="cx"> {
</span><span class="cx"> if (is_resource($data)) {
</span><span class="cx"> rewind($data);
</span><span class="lines">@@ -1731,10 +1669,11 @@
</span><span class="cx"> 'skipscan' => true
</span><span class="cx"> ));
</span><span class="cx">
</span><del>- // APPEND data MUST be sent in a literal (RFC 3501 [6.3.11]).
- $ob->forceLiteral();
</del><ins>+ // Force output to binary. Not much we can do if server doesn't
+ // support, so just deal with it at send-time.
+ $ob->forceBinary();
</ins><span class="cx">
</span><del>- $asize += $ob->length();
</del><ins>+ $this->_temp['appendsize'] += $ob->length();
</ins><span class="cx">
</span><span class="cx"> return $ob;
</span><span class="cx"> }
</span><span class="lines">@@ -1784,7 +1723,7 @@
</span><span class="cx"> protected function _check()
</span><span class="cx"> {
</span><span class="cx"> // CHECK returns no untagged information (RFC 3501 [6.4.1])
</span><del>- $this->_sendCmd($this->_command('CHECK'));
</del><ins>+ $this->_sendLine($this->_clientCommand('CHECK'));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -1794,19 +1733,15 @@
</span><span class="cx"> if (empty($options['expunge'])) {
</span><span class="cx"> if ($this->queryCapability('UNSELECT')) {
</span><span class="cx"> // RFC 3691 defines 'UNSELECT' for precisely this purpose
</span><del>- $this->_sendCmd($this->_command('UNSELECT'));
</del><ins>+ $this->_sendLine($this->_clientCommand('UNSELECT'));
</ins><span class="cx"> } else {
</span><del>- /* RFC 3501 [6.4.2]: to close a mailbox without expunge,
- * select a non-existent mailbox. */
</del><ins>+ // RFC 3501 [6.4.2]: to close a mailbox without expunge,
+ // select a non-existent mailbox. Selecting a null mailbox
+ // should do the trick.
</ins><span class="cx"> try {
</span><del>- $this->_sendCmd($this->_command('EXAMINE')->add(
- new Horde_Imap_Client_Data_Format_Mailbox("\24nonexist\24")
- ));
-
- /* Not pipelining, since the odds that this CLOSE is even
- * needed is tiny; and it returns BAD, which should be
- * avoided, if possible. */
- $this->_sendCmd($this->_command('CLOSE'));
</del><ins>+ $cmd = $this->_clientCommand('SELECT');
+ $cmd->add('');
+ $this->_sendLine($cmd);
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
</span><span class="cx"> // Ignore error; it is expected.
</span><span class="cx"> }
</span><span class="lines">@@ -1819,7 +1754,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // CLOSE returns no untagged information (RFC 3501 [6.4.2])
</span><del>- $this->_sendCmd($this->_command('CLOSE'));
</del><ins>+ $this->_sendLine($this->_clientCommand('CLOSE'));
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1835,7 +1770,7 @@
</span><span class="cx"> $use_cache = $this->_initCache(true);
</span><span class="cx">
</span><span class="cx"> if ($ids->all) {
</span><del>- if (!$uidplus || $list_msgs || $use_cache) {
</del><ins>+ if (!$uidplus && ($list_msgs || $use_cache)) {
</ins><span class="cx"> $ids = $this->resolveIds($this->_selected, $ids, 2);
</span><span class="cx"> }
</span><span class="cx"> } elseif ($uidplus) {
</span><span class="lines">@@ -1846,10 +1781,11 @@
</span><span class="cx"> * even if the server returns EXPUNGEs instead, we can use
</span><span class="cx"> * vanished() to grab the list. */
</span><span class="cx"> unset($this->_temp['search_save']);
</span><del>- if (isset($this->_temp['enabled']['QRESYNC'])) {
</del><ins>+ if (isset($this->_init['enabled']['QRESYNC'])) {
</ins><span class="cx"> $ids = $this->resolveIds($this->_selected, $ids, 1);
</span><span class="cx"> if ($list_msgs) {
</span><span class="cx"> $modseq = $this->_mailboxOb()->getStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ);
</span><ins>+ unset($this->_temp['expunge_seen']);
</ins><span class="cx"> }
</span><span class="cx"> } else {
</span><span class="cx"> $ids = $this->resolveIds($this->_selected, $ids, ($list_msgs || $use_cache) ? 2 : 1);
</span><span class="lines">@@ -1887,42 +1823,20 @@
</span><span class="cx">
</span><span class="cx"> /* Always use UID EXPUNGE if available. */
</span><span class="cx"> if ($uidplus) {
</span><del>- /* We can only pipeline STORE w/ EXPUNGE if using UIDs and UIDPLUS
- * is available. */
- if (empty($options['delete'])) {
- $pipeline = $this->_pipeline();
- } else {
- $pipeline = $this->_storeCmd(array(
- 'add' => array(
- Horde_Imap_Client::FLAG_DELETED
- ),
- 'ids' => $ids
- ));
- }
-
</del><span class="cx"> foreach ($ids->split(2000) as $val) {
</span><del>- $pipeline->add(
- $this->_command('UID EXPUNGE')->add($val)
- );
</del><ins>+ $this->_sendLine($this->_clientCommand(array(
+ 'UID',
+ 'EXPUNGE',
+ $val
+ )));
</ins><span class="cx"> }
</span><del>-
- $resp = $this->_sendCmd($pipeline);
</del><ins>+ } elseif ($use_cache || $list_msgs) {
+ $this->_sendLine($this->_clientCommand('EXPUNGE'));
</ins><span class="cx"> } else {
</span><del>- if (!empty($options['delete'])) {
- $this->store($this->_selected, array(
- 'add' => array(Horde_Imap_Client::FLAG_DELETED),
- 'ids' => $ids
- ));
- }
-
- if ($use_cache || $list_msgs) {
- $this->_sendCmd($this->_command('EXPUNGE'));
- } else {
- /* This is faster than an EXPUNGE because the server will not
- * return untagged EXPUNGE responses. We can only do this if
- * we are not updating cache information. */
- $this->close(array('expunge' => true));
- }
</del><ins>+ /* This is faster than an EXPUNGE because the server will not
+ * return untagged EXPUNGE responses. We can only do this if
+ * we are not updating cache information. */
+ $this->close(array('expunge' => true));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> unset($this->_temp['expunged']);
</span><span class="lines">@@ -1934,16 +1848,14 @@
</span><span class="cx"> ));
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (!is_null($modseq) && !empty($resp->data['expunge_seen'])) {
</del><ins>+ if (!is_null($modseq) && !empty($this->_temp['expunge_seen'])) {
</ins><span class="cx"> /* There's a chance we actually did a full map of sequence -> UID,
</span><span class="cx"> * but this code should never be reached in the first place so
</span><span class="cx"> * be ultra-safe and just do a full VANISHED search. */
</span><span class="cx"> $expunged_ob = $this->vanished($this->_selected, $modseq, array(
</span><span class="cx"> 'ids' => $ids
</span><span class="cx"> ));
</span><del>- $this->_deleteMsgs($this->_selected, $expunged_ob, array(
- 'pipeline' => $resp
- ));
</del><ins>+ $this->_deleteMsgs($this->_selected, $expunged_ob);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return $expunged_ob;
</span><span class="lines">@@ -1952,14 +1864,9 @@
</span><span class="cx"> /**
</span><span class="cx"> * Parse a VANISHED response (RFC 5162 [3.6]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The response data.
</span><span class="cx"> */
</span><del>- protected function _parseVanished(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseVanished(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><span class="cx"> /* There are two forms of VANISHED. VANISHED (EARLIER) will be sent
</span><span class="cx"> * in a FETCH (VANISHED) or SELECT/EXAMINE (QRESYNC) call.
</span><span class="lines">@@ -1973,21 +1880,16 @@
</span><span class="cx"> * QRESYNC. */
</span><span class="cx"> $data->next();
</span><span class="cx"> $vanished = $this->getIdsOb($data->next());
</span><del>- if (isset($pipeline->data['vanished'])) {
- $pipeline->data['vanished']->add($vanished);
</del><ins>+ if (isset($this->_temp['vanished'])) {
+ $this->_temp['vanished']->add($vanished);
</ins><span class="cx"> } else {
</span><del>- $this->_deleteMsgs($this->_selected, $vanished, array(
- 'pipeline' => $pipeline
- ));
</del><ins>+ $this->_deleteMsgs($this->_selected, $vanished);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> } else {
</span><span class="cx"> /* The second form is just VANISHED. This is analogous to EXPUNGE
</span><span class="cx"> * and requires the message count to decrement. */
</span><del>- $this->_deleteMsgs($this->_selected, $this->getIdsOb($curr), array(
- 'decrement' => true,
- 'pipeline' => $pipeline
- ));
</del><ins>+ $this->_deleteMsgs($this->_selected, $this->getIdsOb($curr), true);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1997,6 +1899,8 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _search($query, $options)
</span><span class="cx"> {
</span><ins>+ $cmd = $this->_clientCommand(empty($options['sequence']) ? 'UID' : null);
+
</ins><span class="cx"> $sort_criteria = array(
</span><span class="cx"> Horde_Imap_Client::SORT_ARRIVAL => 'ARRIVAL',
</span><span class="cx"> Horde_Imap_Client::SORT_CC => 'CC',
</span><span class="lines">@@ -2067,9 +1971,7 @@
</span><span class="cx"> : $options['_query']['charset'];
</span><span class="cx">
</span><span class="cx"> if ($server_sort) {
</span><del>- $cmd = $this->_command(
- empty($options['sequence']) ? 'UID SORT' : 'SORT'
- );
</del><ins>+ $cmd->add('SORT');
</ins><span class="cx"> $results = array();
</span><span class="cx">
</span><span class="cx"> // Use ESEARCH (RFC 4466) response if server supports.
</span><span class="lines">@@ -2121,12 +2023,11 @@
</span><span class="cx"> // Charset is mandatory for SORT (RFC 5256 [3]).
</span><span class="cx"> $cmd->add($charset);
</span><span class="cx"> } else {
</span><del>- $cmd = $this->_command(
- empty($options['sequence']) ? 'UID SEARCH' : 'SEARCH'
- );
</del><span class="cx"> $esearch = false;
</span><span class="cx"> $results = array();
</span><span class="cx">
</span><ins>+ $cmd->add('SEARCH');
+
</ins><span class="cx"> // Check if the server supports ESEARCH (RFC 4731).
</span><span class="cx"> if ($this->queryCapability('ESEARCH')) {
</span><span class="cx"> foreach ($options['results'] as $val) {
</span><span class="lines">@@ -2170,18 +2071,20 @@
</span><span class="cx"> $options['_query']['charset']
</span><span class="cx"> ));
</span><span class="cx"> }
</span><ins>+
+ // SEARCHRES requires ESEARCH
+ unset($this->_temp['searchnotsaved']);
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ $er = &$this->_temp['esearchresp'];
+ $er = array();
+ $sr = &$this->_temp['searchresp'];
+ $sr = $this->getIdsOb(array(), !empty($options['sequence']));
+
</ins><span class="cx"> $cmd->add($options['_query']['query'], true);
</span><span class="cx">
</span><del>- $pipeline = $this->_pipeline($cmd);
- $pipeline->data['esearchresp'] = array();
- $er = &$pipeline->data['esearchresp'];
- $pipeline->data['searchresp'] = $this->getIdsOb(array(), !empty($options['sequence']));
- $sr = &$pipeline->data['searchresp'];
-
</del><span class="cx"> try {
</span><del>- $resp = $this->_sendCmd($pipeline);
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {
</span><span class="cx"> if (($e instanceof Horde_Imap_Client_Exception_ServerResponse) &&
</span><span class="cx"> ($e->status == Horde_Imap_Client_Interaction_Server::NO) &&
</span><span class="lines">@@ -2273,7 +2176,7 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case Horde_Imap_Client::SEARCH_RESULTS_SAVE:
</span><del>- $this->_temp['search_save'] = $ret['save'] = $esearch ? empty($resp->data['searchnotsaved']) : false;
</del><ins>+ $this->_temp['search_save'] = $ret['save'] = $esearch ? empty($this->_temp['searchnotsaved']) : false;
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -2286,7 +2189,8 @@
</span><span class="cx"> unset($this->_temp['search_retry']);
</span><span class="cx">
</span><span class="cx"> /* Check for EXPUNGEISSUED (RFC 2180 [4.3]/RFC 5530 [3]). */
</span><del>- if (!empty($resp->data['expungeissued'])) {
</del><ins>+ if (!empty($this->_temp['expungeissued'])) {
+ unset($this->_temp['expungeissued']);
</ins><span class="cx"> $this->noop();
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -2297,31 +2201,21 @@
</span><span class="cx"> * Parse a SEARCH/SORT response (RFC 3501 [7.2.5]; RFC 4466 [3];
</span><span class="cx"> * RFC 5256 [4]; RFC 5267 [3]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param array $data A list of IDs (message sequence numbers or UIDs).
</span><span class="cx"> */
</span><del>- protected function _parseSearch(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- $data
- )
</del><ins>+ protected function _parseSearch($data)
</ins><span class="cx"> {
</span><span class="cx"> /* More than one search response may be sent. */
</span><del>- $pipeline->data['searchresp']->add($data);
</del><ins>+ $this->_temp['searchresp']->add($data);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse an ESEARCH response (RFC 4466 [2.6.2])
</span><span class="cx"> * Format: (TAG "a567") UID COUNT 5 ALL 4:19,21,28
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response.
</span><span class="cx"> */
</span><del>- protected function _parseEsearch(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseEsearch(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><span class="cx"> // Ignore search correlator information
</span><span class="cx"> if ($data->next() === true) {
</span><span class="lines">@@ -2340,7 +2234,7 @@
</span><span class="cx">
</span><span class="cx"> switch ($tag) {
</span><span class="cx"> case 'ALL':
</span><del>- $this->_parseSearch($pipeline, $val);
</del><ins>+ $this->_parseSearch($val);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'COUNT':
</span><span class="lines">@@ -2348,13 +2242,13 @@
</span><span class="cx"> case 'MIN':
</span><span class="cx"> case 'MODSEQ':
</span><span class="cx"> case 'RELEVANCY':
</span><del>- $pipeline->data['esearchresp'][strtolower($tag)] = $val;
</del><ins>+ $this->_temp['esearchresp'][strtolower($tag)] = $val;
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'PARTIAL':
</span><span class="cx"> // RFC 5267 [4.4]
</span><span class="cx"> $partial = $val->flushIterator();
</span><del>- $this->_parseSearch($pipeline, end($partial));
</del><ins>+ $this->_parseSearch(end($partial));
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> } while (($current = $data->next()) !== false);
</span><span class="lines">@@ -2364,37 +2258,32 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _setComparator($comparator)
</span><span class="cx"> {
</span><del>- $cmd = $this->_command('COMPARATOR');
</del><ins>+ $cmd = $this->_clientCommand('COMPARATOR');
</ins><span class="cx"> foreach ($comparator as $val) {
</span><span class="cx"> $cmd->add(new Horde_Imap_Client_Data_Format_Astring($val));
</span><span class="cx"> }
</span><del>- $this->_sendCmd($cmd);
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><span class="cx"> protected function _getComparator()
</span><span class="cx"> {
</span><del>- $resp = $this->_sendCmd($this->_command('COMPARATOR'));
</del><ins>+ $this->_sendLine($this->_clientCommand('COMPARATOR'));
</ins><span class="cx">
</span><del>- return isset($resp->data['comparator'])
- ? $resp->data['comparator']
</del><ins>+ return isset($this->_temp['comparator'])
+ ? $this->_temp['comparator']
</ins><span class="cx"> : null;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse a COMPARATOR response (RFC 5255 [4.8])
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response.
</span><span class="cx"> */
</span><del>- protected function _parseComparator(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- $data
- )
</del><ins>+ protected function _parseComparator($data)
</ins><span class="cx"> {
</span><del>- $pipeline->data['comparator'] = $data->next();
</del><ins>+ $this->_temp['comparator'] = $data->next();
</ins><span class="cx"> // Ignore optional matching comparator list
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -2447,9 +2336,11 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $cmd = $this->_command(
- empty($options['sequence']) ? 'UID THREAD' : 'THREAD'
- )->add($tsort);
</del><ins>+ $cmd = $this->_clientCommand(array(
+ empty($options['sequence']) ? 'UID' : null,
+ 'THREAD',
+ $tsort
+ ));
</ins><span class="cx">
</span><span class="cx"> if (empty($options['search'])) {
</span><span class="cx"> $cmd->add(array(
</span><span class="lines">@@ -2462,23 +2353,17 @@
</span><span class="cx"> $cmd->add($search_query['query'], true);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return new Horde_Imap_Client_Data_Thread(
- $this->_sendCmd($cmd)->data['threadparse'],
- empty($options['sequence']) ? 'uid' : 'sequence'
- );
</del><ins>+ $this->_sendLine($cmd);
+
+ return new Horde_Imap_Client_Data_Thread($this->_temp['threadparse'], empty($options['sequence']) ? 'uid' : 'sequence');
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse a THREAD response (RFC 5256 [4]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data Thread data.
</span><span class="cx"> */
</span><del>- protected function _parseThread(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseThread(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><span class="cx"> $out = array();
</span><span class="cx">
</span><span class="lines">@@ -2488,7 +2373,7 @@
</span><span class="cx"> $out[] = $thread;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $pipeline->data['threadparse'] = $out;
</del><ins>+ $this->_temp['threadparse'] = $out;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -2514,54 +2399,11 @@
</span><span class="cx"> /**
</span><span class="cx"> */
</span><span class="cx"> protected function _fetch(Horde_Imap_Client_Fetch_Results $results,
</span><del>- $queries)
</del><ins>+ Horde_Imap_Client_Fetch_Query $query,
+ $options)
</ins><span class="cx"> {
</span><del>- $pipeline = $this->_pipeline();
- $pipeline->data['fetch_lookup'] = array();
-
- foreach ($queries as $options) {
- $this->_fetchCmd($pipeline, $options);
- $sequence = $options['ids']->sequence;
- }
-
- try {
- $resp = $this->_sendCmd($pipeline);
-
- /* Check for EXPUNGEISSUED (RFC 2180 [4.1]/RFC 5530 [3]). */
- if (!empty($resp->data['expungeissued'])) {
- $this->noop();
- }
- } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
- // A NO response, when coupled with a sequence FETCH, most
- // likely means that messages were expunged. RFC 2180 [4.1]
- if ($sequence &&
- ($e->status == Horde_Imap_Client_Interaction_Server::NO)) {
- $this->noop();
- }
- } catch (Exception $e) {
- // For any other error, ignore the Exception - fetch() is nice in
- // that the return value explicitly handles missing data for any
- // given message.
- }
-
- foreach ($resp->fetch as $k => $v) {
- $results->get($sequence ? $k : $v->getUid())->merge($v);
- }
- }
-
- /**
- * Add a FETCH command to the given pipeline.
- *
- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
- * @param array $options Fetch query
- * options
- */
- protected function _fetchCmd(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- $options
- )
- {
</del><ins>+ $t = &$this->_temp;
+ $t['fetchcmd'] = array();
</ins><span class="cx"> $fetch = new Horde_Imap_Client_Data_Format_List();
</span><span class="cx"> $sequence = $options['ids']->sequence;
</span><span class="cx">
</span><span class="lines">@@ -2593,7 +2435,7 @@
</span><span class="cx"> * RFC822.TEXT => BODY[TEXT]
</span><span class="cx"> */
</span><span class="cx">
</span><del>- foreach ($options['_query'] as $type => $c_val) {
</del><ins>+ foreach ($query as $type => $c_val) {
</ins><span class="cx"> switch ($type) {
</span><span class="cx"> case Horde_Imap_Client::FETCH_STRUCTURE:
</span><span class="cx"> $fetch->add('BODYSTRUCTURE');
</span><span class="lines">@@ -2654,7 +2496,7 @@
</span><span class="cx">
</span><span class="cx"> // Maintain a command -> label lookup so we can put
</span><span class="cx"> // the results in the proper location.
</span><del>- $pipeline->data['fetch_lookup'][$cmd] = $key;
</del><ins>+ $t['fetchcmd'][$cmd] = $key;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (empty($val['peek'])) {
</span><span class="lines">@@ -2698,15 +2540,15 @@
</span><span class="cx"> /* A UID FETCH will always return UID information (RFC 3501
</span><span class="cx"> * [6.4.8]). Don't add to query as it just creates a longer
</span><span class="cx"> * FETCH command. */
</span><del>- if ($sequence || (count($options['_query']) == 1)) {
</del><ins>+ if ($sequence || (count($query) == 1)) {
</ins><span class="cx"> $fetch->add('UID');
</span><span class="cx"> }
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case Horde_Imap_Client::FETCH_SEQ:
</span><del>- // Nothing we need to add to fetch request unless sequence is
- // the only criteria.
- if (count($options['_query']) == 1) {
</del><ins>+ // Nothing we need to add to fetch request unless sequence
+ // is the only criteria.
+ if (count($query) == 1) {
</ins><span class="cx"> $fetch->add('UID');
</span><span class="cx"> }
</span><span class="cx"> break;
</span><span class="lines">@@ -2748,15 +2590,42 @@
</span><span class="cx"> * approach this limit. For simplification, assume that the UID list
</span><span class="cx"> * is the limiting factor and split this list at a sequence comma
</span><span class="cx"> * delimiter if it exceeds 2000 characters. */
</span><ins>+ $cmd_list = array();
</ins><span class="cx"> foreach ($options['ids']->split(2000) as $val) {
</span><del>- $cmd = $this->_command(
- $sequence ? 'FETCH' : 'UID FETCH'
- )->add(array(
</del><ins>+ $cmd_list[] = $this->_clientCommand(array_filter(array(
+ $sequence ? null : 'UID',
+ 'FETCH',
</ins><span class="cx"> $val,
</span><span class="cx"> $fetch_cmd
</span><del>- ));
- $pipeline->add($cmd);
</del><ins>+ )));
</ins><span class="cx"> }
</span><ins>+
+ foreach ($cmd_list as $val) {
+ try {
+ $this->_sendLine($val, array(
+ 'keep_fetch' => true
+ ));
+ } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
+ // A NO response, when coupled with a sequence FETCH, most
+ // likely means that messages were expunged. RFC 2180 [4.1]
+ if ($sequence &&
+ ($e->status == Horde_Imap_Client_Interaction_Server::NO)) {
+ $this->_temp['expungeissued'] = true;
+ }
+ }
+ }
+
+ /* Check for EXPUNGEISSUED (RFC 2180 [4.1]/RFC 5530 [3]). */
+ if (!empty($this->_temp['expungeissued'])) {
+ unset($this->_temp['expungeissued']);
+ $this->noop();
+ }
+
+ foreach ($this->_fetch as $k => $v) {
+ $results->get($sequence ? $k : $v->getUid())->merge($v);
+ }
+
+ $this->_fetch->clear();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -2782,22 +2651,16 @@
</span><span class="cx"> * due to a FETCH command, or due to a change in a message's state (i.e.
</span><span class="cx"> * the flags change).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param integer $id The message sequence number.
</span><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response.
</span><span class="cx"> */
</span><del>- protected function _parseFetch(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- $id,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseFetch($id, Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><span class="cx"> if ($data->next() !== true) {
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $ob = $pipeline->fetch->get($id);
</del><ins>+ $ob = $this->_fetch->get($id);
</ins><span class="cx"> $ob->setSeq($id);
</span><span class="cx">
</span><span class="cx"> $flags = $modseq = $uid = false;
</span><span class="lines">@@ -2848,7 +2711,7 @@
</span><span class="cx">
</span><span class="cx"> /* Store MODSEQ value. It may be used as the highestmodseq
</span><span class="cx"> * once a tagged response is received (RFC 5162 [5]). */
</span><del>- $pipeline->data['modseqs'][] = $modseq;
</del><ins>+ $this->_temp['modseqs'][] = $modseq;
</ins><span class="cx"> }
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="lines">@@ -2859,7 +2722,7 @@
</span><span class="cx"> $tag = substr($tag, 5);
</span><span class="cx">
</span><span class="cx"> // BODY[HEADER.FIELDS] request
</span><del>- if (!empty($pipeline->data['fetch_lookup']) &&
</del><ins>+ if (!empty($this->_temp['fetchcmd']) &&
</ins><span class="cx"> (strpos($tag, 'HEADER.FIELDS') !== false)) {
</span><span class="cx"> $data->next();
</span><span class="cx"> $sig = $tag . ' (' . implode(' ', array_map('strtoupper', $data->flushIterator())) . ')';
</span><span class="lines">@@ -2867,7 +2730,7 @@
</span><span class="cx"> // Ignore the trailing bracket
</span><span class="cx"> $data->next();
</span><span class="cx">
</span><del>- $ob->setHeaders($pipeline->data['fetch_lookup'][$sig], $data->next());
</del><ins>+ $ob->setHeaders($this->_temp['fetchcmd'][$sig], $data->next());
</ins><span class="cx"> } else {
</span><span class="cx"> // Remove trailing bracket and octet start info
</span><span class="cx"> $tag = substr($tag, 0, strrpos($tag, ']'));
</span><span class="lines">@@ -2943,7 +2806,7 @@
</span><span class="cx"> * mailbox open so we only lose a bit of caching efficiency.
</span><span class="cx"> * Otherwise, we could end up with an inconsistent cached state. */
</span><span class="cx"> if ($flags && $modseq && !$uid) {
</span><del>- $pipeline->data['modseqs_nouid'][] = $id;
</del><ins>+ $this->_temp['modseqs_nouid'][] = $id;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -3115,8 +2978,8 @@
</span><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> $addr_ob = new Horde_Mail_Rfc822_Address();
</span><del>- $env_addrs = $this->getParam('envelope_addrs');
- $env_str = $this->getParam('envelope_string');
</del><ins>+ $env_addrs = $this->_params['envelope_addrs'];
+ $env_str = $this->_params['envelope_string'];
</ins><span class="cx"> $key = 0;
</span><span class="cx"> $ret = new Horde_Imap_Client_Data_Envelope();
</span><span class="cx">
</span><span class="lines">@@ -3183,127 +3046,118 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _vanished($modseq, Horde_Imap_Client_Ids $ids)
</span><span class="cx"> {
</span><del>- $pipeline = $this->_pipeline(
- $this->_command('UID FETCH')->add(array(
- strval($ids),
- 'UID',
- new Horde_Imap_Client_Data_Format_List(array(
- 'VANISHED',
- 'CHANGEDSINCE',
- new Horde_Imap_Client_Data_Format_Number($modseq)
- ))
</del><ins>+ $vanished_ob = $this->getIdsOb();
+ $this->_temp['vanished'] = $vanished_ob;
+
+ $cmd = $this->_clientCommand(array(
+ 'UID',
+ 'FETCH',
+ strval($ids),
+ 'UID',
+ new Horde_Imap_Client_Data_Format_List(array(
+ 'VANISHED',
+ 'CHANGEDSINCE',
+ new Horde_Imap_Client_Data_Format_Number($modseq)
</ins><span class="cx"> ))
</span><del>- );
- $pipeline->data['vanished'] = $this->getIdsOb();
</del><ins>+ ));
</ins><span class="cx">
</span><del>- return $this->_sendCmd($pipeline)->data['vanished'];
</del><ins>+ $this->_sendLine($cmd);
+
+ unset($this->_temp['vanished']);
+
+ return $vanished_ob;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><span class="cx"> protected function _store($options)
</span><span class="cx"> {
</span><del>- $pipeline = $this->_storeCmd($options);
- $pipeline->data['modified'] = $this->getIdsOb();
</del><ins>+ $cmd = $this->_clientCommand(array(
+ empty($options['sequence']) ? 'UID' : null,
+ 'STORE',
+ strval($options['ids'])
+ ));
</ins><span class="cx">
</span><del>- try {
- $resp = $this->_sendCmd($pipeline);
-
- /* Check for EXPUNGEISSUED (RFC 2180 [4.2]/RFC 5530 [3]). */
- if (!empty($resp->data['expungeissued'])) {
- $this->noop();
- }
-
- return $resp->data['modified'];
- } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
- /* A NO response, when coupled with a sequence STORE and
- * non-SILENT behavior, most likely means that messages were
- * expunged. RFC 2180 [4.2] */
- if (empty($pipeline->data['store_silent']) &&
- !empty($options['sequence']) &&
- ($e->status == Horde_Imap_Client_Interaction_Server::NO)) {
- $this->noop();
- }
-
- return $pipeline->data['modified'];
</del><ins>+ if (empty($options['unchangedsince'])) {
+ $silent = !($this->_debug->debug || $this->_initCache(true));
+ } else {
+ $cmd->add(new Horde_Imap_Client_Data_Format_List(array(
+ 'UNCHANGEDSINCE',
+ new Horde_Imap_Client_Data_Format_Number(intval($options['unchangedsince']))
+ )));
+ $silent = false;
</ins><span class="cx"> }
</span><del>- }
</del><span class="cx">
</span><del>- /**
- * Create a store command.
- *
- * @param array $options See Horde_Imap_Client_Base#_store().
- *
- * @return Horde_Imap_Client_Interaction_Pipeline Pipeline object.
- */
- protected function _storeCmd($options)
- {
</del><span class="cx"> $cmds = array();
</span><del>- $silent = empty($options['unchangedsince'])
- ? !($this->_debug->debug || $this->_initCache(true))
- : false;
</del><ins>+ $this->_temp['modified'] = $this->getIdsOb();
</ins><span class="cx">
</span><span class="cx"> if (!empty($options['replace'])) {
</span><del>- $cmds[] = array(
</del><ins>+ $cmd->add(array(
</ins><span class="cx"> 'FLAGS' . ($silent ? '.SILENT' : ''),
</span><span class="cx"> $options['replace']
</span><del>- );
</del><ins>+ ));
+ $cmds[] = $cmd;
</ins><span class="cx"> } else {
</span><span class="cx"> foreach (array('add' => '+', 'remove' => '-') as $k => $v) {
</span><span class="cx"> if (!empty($options[$k])) {
</span><del>- $cmds[] = array(
</del><ins>+ $cmdtmp = clone $cmd;
+ $cmdtmp->add(array(
</ins><span class="cx"> $v . 'FLAGS' . ($silent ? '.SILENT' : ''),
</span><span class="cx"> $options[$k]
</span><del>- );
</del><ins>+ ));
+ $cmds[] = $cmdtmp;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $pipeline = $this->_pipeline();
- $pipeline->data['store_silent'] = $silent;
-
</del><span class="cx"> foreach ($cmds as $val) {
</span><del>- $cmd = $this->_command(
- empty($options['sequence']) ? 'UID STORE' : 'STORE'
- )->add(strval($options['ids']));
- if (!empty($options['unchangedsince'])) {
- $cmd->add(new Horde_Imap_Client_Data_Format_List(array(
- 'UNCHANGEDSINCE',
- new Horde_Imap_Client_Data_Format_Number(intval($options['unchangedsince']))
- )));
</del><ins>+ try {
+ $this->_sendLine($val);
+ } catch (Horde_Imap_Client_Exception_ServerResponse $e) {
+ /* A NO response, when coupled with a sequence STORE and
+ * non-SILENT behavior, most likely means that messages were
+ * expunged. RFC 2180 [4.2] */
+ if (!$silent &&
+ !empty($options['sequence']) &&
+ ($e->status == Horde_Imap_Client_Interaction_Server::NO)) {
+ $this->_temp['expungeissued'] = true;
+ }
</ins><span class="cx"> }
</span><del>- $cmd->add($val);
</del><span class="cx">
</span><del>- $pipeline->add($cmd);
</del><ins>+ /* Check for EXPUNGEISSUED (RFC 2180 [4.2]/RFC 5530 [3]). */
+ if (!empty($this->_temp['expungeissued'])) {
+ unset($this->_temp['expungeissued']);
+ $this->noop();
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return $pipeline;
</del><ins>+ return $this->_temp['modified'];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><span class="cx"> protected function _copy(Horde_Imap_Client_Mailbox $dest, $options)
</span><span class="cx"> {
</span><ins>+ $this->_temp['copydest'] = $dest;
+ $this->_temp['copyuid'] = true;
+ $this->_temp['trycreate'] = null;
+
</ins><span class="cx"> /* Check for MOVE command (RFC 6851). */
</span><span class="cx"> $move_cmd = (!empty($options['move']) &&
</span><span class="cx"> $this->queryCapability('MOVE'));
</span><span class="cx">
</span><del>- $cmd = $this->_pipeline(
- $this->_command(
- ($options['ids']->sequence ? '' : 'UID ') . ($move_cmd ? 'MOVE' : 'COPY')
- )->add(array(
</del><ins>+ // COPY returns no untagged information (RFC 3501 [6.4.7])
+ try {
+ $cmd = $this->_clientCommand(array_filter(array(
+ $options['ids']->sequence ? null : 'UID',
+ $move_cmd ? 'MOVE' : 'COPY',
</ins><span class="cx"> strval($options['ids']),
</span><span class="cx"> new Horde_Imap_Client_Data_Format_Mailbox($dest)
</span><del>- ))
- );
- $cmd->data['copydest'] = $dest;
</del><ins>+ )));
</ins><span class="cx">
</span><del>- // COPY returns no untagged information (RFC 3501 [6.4.7])
- try {
- $resp = $this->_sendCmd($cmd);
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx"> } catch (Horde_Imap_Client_Exception $e) {
</span><del>- if (!empty($options['create']) &&
- !empty($e->resp_data['trycreate'])) {
</del><ins>+ if (!empty($options['create']) && $this->_temp['trycreate']) {
</ins><span class="cx"> $this->createMailbox($dest);
</span><span class="cx"> unset($options['create']);
</span><span class="cx"> return $this->_copy($dest, $options);
</span><span class="lines">@@ -3315,17 +3169,16 @@
</span><span class="cx"> // was moved.
</span><span class="cx"> if (!$move_cmd &&
</span><span class="cx"> !empty($options['move']) &&
</span><del>- (isset($resp->data['copyuid']) ||
- !$this->queryCapability('UIDPLUS'))) {
- $this->expunge($this->_selected, array(
- 'delete' => true,
- 'ids' => $options['ids']
- ));
</del><ins>+ (($this->_temp['copyuid'] !== true) ||
+ !$this->_queryCapability('UIDPLUS'))) {
+ $opts = array('ids' => $options['ids']);
+ $this->store($this->_selected, array_merge(array(
+ 'add' => array(Horde_Imap_Client::FLAG_DELETED)
+ ), $opts));
+ $this->expunge($this->_selected, $opts);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return isset($resp->data['copyuid'])
- ? $resp->data['copyuid']
- : true;
</del><ins>+ return $this->_temp['copyuid'];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -3341,41 +3194,39 @@
</span><span class="cx"> ));
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $this->_sendCmd(
- $this->_command('SETQUOTA')->add(array(
- new Horde_Imap_Client_Data_Format_Mailbox($root),
- $limits
- ))
- );
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'SETQUOTA',
+ new Horde_Imap_Client_Data_Format_Mailbox($root),
+ $limits
+ ));
+
+ $this->_sendLine($cmd);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><span class="cx"> protected function _getQuota(Horde_Imap_Client_Mailbox $root)
</span><span class="cx"> {
</span><del>- $pipeline = $this->_pipeline(
- $this->_command('GETQUOTA')->add(
- new Horde_Imap_Client_Data_Format_Mailbox($root)
- )
- );
- $pipeline->data['quotaresp'] = array();
</del><ins>+ $this->_temp['quotaresp'] = array();
</ins><span class="cx">
</span><del>- return reset($this->_sendCmd($pipeline)->data['quotaresp']);
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'GETQUOTA',
+ new Horde_Imap_Client_Data_Format_Mailbox($root)
+ ));
+
+ $this->_sendLine($cmd);
+
+ return reset($this->_temp['quotaresp']);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse a QUOTA response (RFC 2087 [5.1]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response.
</span><span class="cx"> */
</span><del>- protected function _parseQuota(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseQuota(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><del>- $c = &$pipeline->data['quotaresp'];
</del><ins>+ $c = &$this->_temp['quotaresp'];
</ins><span class="cx">
</span><span class="cx"> $root = $data->next();
</span><span class="cx"> $c[$root] = array();
</span><span class="lines">@@ -3394,14 +3245,16 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _getQuotaRoot(Horde_Imap_Client_Mailbox $mailbox)
</span><span class="cx"> {
</span><del>- $pipeline = $this->_pipeline(
- $this->_command('GETQUOTAROOT')->add(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
- )
- );
- $pipeline->data['quotaresp'] = array();
</del><ins>+ $this->_temp['quotaresp'] = array();
</ins><span class="cx">
</span><del>- return $this->_sendCmd($pipeline)->data['quotaresp'];
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'GETQUOTAROOT',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
+ ));
+
+ $this->_sendLine($cmd);
+
+ return $this->_temp['quotaresp'];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -3410,13 +3263,14 @@
</span><span class="cx"> $options)
</span><span class="cx"> {
</span><span class="cx"> // SETACL returns no untagged information (RFC 4314 [3.1]).
</span><del>- $this->_sendCmd(
- $this->_command('SETACL')->add(array(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
- new Horde_Imap_Client_Data_Format_Astring($identifier),
- new Horde_Imap_Client_Data_Format_Astring($options['rights'])
- ))
- );
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'SETACL',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
+ new Horde_Imap_Client_Data_Format_Astring($identifier),
+ new Horde_Imap_Client_Data_Format_Astring($options['rights'])
+ ));
+
+ $this->_sendLine($cmd);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -3424,38 +3278,39 @@
</span><span class="cx"> protected function _deleteACL(Horde_Imap_Client_Mailbox $mailbox, $identifier)
</span><span class="cx"> {
</span><span class="cx"> // DELETEACL returns no untagged information (RFC 4314 [3.2]).
</span><del>- $this->_sendCmd(
- $this->_command('DELETEACL')->add(array(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
- new Horde_Imap_Client_Data_Format_Astring($identifier)
- ))
- );
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'DELETEACL',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
+ new Horde_Imap_Client_Data_Format_Astring($identifier)
+ ));
+
+ $this->_sendLine($cmd);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> */
</span><span class="cx"> protected function _getACL(Horde_Imap_Client_Mailbox $mailbox)
</span><span class="cx"> {
</span><del>- return $this->_sendCmd(
- $this->_command('GETACL')->add(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
- )
- )->data['getacl'];
</del><ins>+ $this->_temp['getacl'] = array();
+
+ $cmd = $this->_clientCommand(array(
+ 'GETACL',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
+ ));
+
+ $this->_sendLine($cmd);
+
+ return $this->_temp['getacl'];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse an ACL response (RFC 4314 [3.6]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response.
</span><span class="cx"> */
</span><del>- protected function _parseACL(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseACL(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><del>- $acl = array();
</del><ins>+ $acl = &$this->_temp['getacl'];
</ins><span class="cx">
</span><span class="cx"> // Ignore mailbox argument -> index 1
</span><span class="cx"> $data->next();
</span><span class="lines">@@ -3465,8 +3320,6 @@
</span><span class="cx"> ? new Horde_Imap_Client_Data_AclNegative($data->next())
</span><span class="cx"> : new Horde_Imap_Client_Data_Acl($data->next());
</span><span class="cx"> }
</span><del>-
- $pipeline->data['getacl'] = $acl;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -3474,35 +3327,33 @@
</span><span class="cx"> protected function _listACLRights(Horde_Imap_Client_Mailbox $mailbox,
</span><span class="cx"> $identifier)
</span><span class="cx"> {
</span><del>- $resp = $this->_sendCmd(
- $this->_command('LISTRIGHTS')->add(array(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
- new Horde_Imap_Client_Data_Format_Astring($identifier)
- ))
- );
</del><ins>+ unset($this->_temp['listaclrights']);
</ins><span class="cx">
</span><del>- return isset($resp->data['listaclrights'])
- ? $resp->data['listaclrights']
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'LISTRIGHTS',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
+ new Horde_Imap_Client_Data_Format_Astring($identifier)
+ ));
+
+ $this->_sendLine($cmd);
+
+ return isset($this->_temp['listaclrights'])
+ ? $this->_temp['listaclrights']
</ins><span class="cx"> : new Horde_Imap_Client_Data_AclRights();
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse a LISTRIGHTS response (RFC 4314 [3.7]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response.
</span><span class="cx"> */
</span><del>- protected function _parseListRights(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseListRights(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><span class="cx"> // Ignore mailbox and identifier arguments
</span><span class="cx"> $data->next();
</span><span class="cx"> $data->next();
</span><span class="cx">
</span><del>- $pipeline->data['listaclrights'] = new Horde_Imap_Client_Data_AclRights(
</del><ins>+ $this->_temp['listaclrights'] = new Horde_Imap_Client_Data_AclRights(
</ins><span class="cx"> str_split($data->next()),
</span><span class="cx"> $data->flushIterator()
</span><span class="cx"> );
</span><span class="lines">@@ -3512,33 +3363,31 @@
</span><span class="cx"> */
</span><span class="cx"> protected function _getMyACLRights(Horde_Imap_Client_Mailbox $mailbox)
</span><span class="cx"> {
</span><del>- $resp = $this->_sendCmd(
- $this->_command('MYRIGHTS')->add(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
- )
- );
</del><ins>+ unset($this->_temp['myrights']);
</ins><span class="cx">
</span><del>- return isset($resp->data['myrights'])
- ? $resp->data['myrights']
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'MYRIGHTS',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
+ ));
+
+ $this->_sendLine($cmd);
+
+ return isset($this->_temp['myrights'])
+ ? $this->_temp['myrights']
</ins><span class="cx"> : new Horde_Imap_Client_Data_Acl();
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Parse a MYRIGHTS response (RFC 4314 [3.8]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response.
</span><span class="cx"> */
</span><del>- protected function _parseMyRights(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseMyRights(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><span class="cx"> // Ignore 1st token (mailbox name)
</span><span class="cx"> $data->next();
</span><span class="cx">
</span><del>- $pipeline->data['myrights'] = new Horde_Imap_Client_Data_Acl($data->next());
</del><ins>+ $this->_temp['myrights'] = new Horde_Imap_Client_Data_Acl($data->next());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -3546,8 +3395,7 @@
</span><span class="cx"> protected function _getMetadata(Horde_Imap_Client_Mailbox $mailbox,
</span><span class="cx"> $entries, $options)
</span><span class="cx"> {
</span><del>- $pipeline = $this->_pipeline();
- $pipeline->data['metadata'] = array();
</del><ins>+ $this->_temp['metadata'] = array();
</ins><span class="cx">
</span><span class="cx"> if ($this->queryCapability('METADATA') ||
</span><span class="cx"> ((strlen($mailbox) == 0) &&
</span><span class="lines">@@ -3572,44 +3420,51 @@
</span><span class="cx"> $queries->add(new Horde_Imap_Client_Data_Format_Astring($md_entry));
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $cmd = $this->_command('GETMETADATA')->add(
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'GETMETADATA',
</ins><span class="cx"> new Horde_Imap_Client_Data_Format_Mailbox($mailbox)
</span><del>- );
</del><ins>+ ));
</ins><span class="cx"> if (count($cmd_options)) {
</span><span class="cx"> $cmd->add($cmd_options);
</span><span class="cx"> }
</span><span class="cx"> $cmd->add($queries);
</span><span class="cx">
</span><del>- $pipeline->add($cmd);
- } else {
- if (!$this->queryCapability('ANNOTATEMORE') &&
- !$this->queryCapability('ANNOTATEMORE2')) {
- throw new Horde_Imap_Client_Exception_NoSupportExtension('METADATA');
- }
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx">
</span><del>- $queries = array();
- foreach ($entries as $md_entry) {
- list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry);
</del><ins>+ return $this->_temp['metadata'];
+ }
</ins><span class="cx">
</span><del>- if (!isset($queries[$type])) {
- $queries[$type] = new Horde_Imap_Client_Data_Format_List();
- }
- $queries[$type]->add(new Horde_Imap_Client_Data_Format_String($entry));
- }
</del><ins>+ if (!$this->queryCapability('ANNOTATEMORE') &&
+ !$this->queryCapability('ANNOTATEMORE2')) {
+ throw new Horde_Imap_Client_Exception_NoSupportExtension('METADATA');
+ }
</ins><span class="cx">
</span><del>- foreach ($queries as $key => $val) {
- // TODO: Honor maxsize and depth options.
- $pipeline->add(
- $this->_command('GETANNOTATION')->add(array(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
- $val,
- new Horde_Imap_Client_Data_Format_String($key)
- ))
- );
</del><ins>+ $queries = array();
+ foreach ($entries as $md_entry) {
+ list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry);
+
+ if (!isset($queries[$type])) {
+ $queries[$type] = new Horde_Imap_Client_Data_Format_List();
</ins><span class="cx"> }
</span><ins>+ $queries[$type]->add(new Horde_Imap_Client_Data_Format_String($entry));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return $this->_sendCmd($pipeline)->data['metadata'];
</del><ins>+ $result = array();
+ foreach ($queries as $key => $val) {
+ // TODO: Honor maxsize and depth options.
+ $cmd = $this->_clientCommand(array(
+ 'GETANNOTATION',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
+ $val,
+ new Horde_Imap_Client_Data_Format_String($key)
+ ));
+
+ $this->_sendLine($cmd);
+
+ $result = array_merge($result, $this->_temp['metadata']);
+ }
+
+ return $result;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -3653,120 +3508,104 @@
</span><span class="cx"> ));
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $cmd = $this->_command('SETMETADATA')->add(array(
</del><ins>+ $cmd = $this->_clientCommand(array(
+ 'SETMETADATA',
</ins><span class="cx"> new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
</span><span class="cx"> $data_elts
</span><span class="cx"> ));
</span><del>- } else {
- if (!$this->queryCapability('ANNOTATEMORE') &&
- !$this->queryCapability('ANNOTATEMORE2')) {
- throw new Horde_Imap_Client_Exception_NoSupportExtension('METADATA');
- }
</del><span class="cx">
</span><del>- $cmd = $this->_pipeline();
</del><ins>+ $this->_sendLine($cmd);
</ins><span class="cx">
</span><del>- foreach ($data as $md_entry => $value) {
- list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry);
</del><ins>+ return;
+ }
</ins><span class="cx">
</span><del>- $cmd->add(
- $this->_command('SETANNOTATION')->add(array(
- new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
- new Horde_Imap_Client_Data_Format_String($entry),
- new Horde_Imap_Client_Data_Format_List(array(
- new Horde_Imap_Client_Data_Format_String($type),
- new Horde_Imap_Client_Data_Format_Nstring($value)
- ))
- ))
- );
- }
</del><ins>+ if (!$this->queryCapability('ANNOTATEMORE') &&
+ !$this->queryCapability('ANNOTATEMORE2')) {
+ throw new Horde_Imap_Client_Exception_NoSupportExtension('METADATA');
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- $this->_sendCmd($cmd);
</del><ins>+ foreach ($data as $md_entry => $value) {
+ list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry);
+
+ $cmd = $this->_clientCommand(array(
+ 'SETANNOTATION',
+ new Horde_Imap_Client_Data_Format_Mailbox($mailbox),
+ new Horde_Imap_Client_Data_Format_String($entry),
+ new Horde_Imap_Client_Data_Format_List(array(
+ new Horde_Imap_Client_Data_Format_String($type),
+ new Horde_Imap_Client_Data_Format_Nstring($value)
+ ))
+ ));
+
+ $this->_sendLine($cmd);
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Parse an ANNOTATION response (ANNOTATEMORE/ANNOTATEMORE2).
</del><ins>+ * Parse a METADATA response (RFC 5464 [4.4]).
</ins><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
</del><span class="cx"> * @param Horde_Imap_Client_Tokenize $data The server response.
</span><span class="cx"> *
</span><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><del>- protected function _parseAnnotation(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
</del><ins>+ protected function _parseMetadata(Horde_Imap_Client_Tokenize $data)
</ins><span class="cx"> {
</span><del>- // Mailbox name is in UTF7-IMAP.
- $mbox = Horde_Imap_Client_Mailbox::get($data->next(), true);
- $entry = $data->next();
</del><ins>+ switch ($data->current()) {
+ case 'ANNOTATION':
+ $mbox = $data->next();
+ $entry = $data->next();
</ins><span class="cx">
</span><del>- // Ignore unsolicited responses.
- if ($data->next() !== true) {
- return;
- }
-
- while (($type = $data->next()) !== false) {
- switch ($type) {
- case 'value.priv':
- $pipeline->data['metadata'][strval($mbox)]['/private' . $entry] = $data->next();
</del><ins>+ // Ignore unsolicited responses.
+ if ($data->next() !== true) {
</ins><span class="cx"> break;
</span><ins>+ }
</ins><span class="cx">
</span><del>- case 'value.shared':
- $pipeline->data['metadata'][strval($mbox)]['/shared' . $entry] = $data->next();
- break;
</del><ins>+ while (($type = $data->next()) !== false) {
+ switch ($type) {
+ case 'value.priv':
+ $this->_temp['metadata'][$mbox]['/private' . $entry] = $data->next();
+ break;
</ins><span class="cx">
</span><del>- default:
- throw new Horde_Imap_Client_Exception(
- sprintf(Horde_Imap_Client_Translation::t("Invalid METADATA value type \"%s\"."), $type),
- Horde_Imap_Client_Exception::METADATA_INVALID
- );
</del><ins>+ case 'value.shared':
+ $this->_temp['metadata'][$mbox]['/shared' . $entry] = $data->next();
+ break;
+
+ default:
+ throw new Horde_Imap_Client_Exception(
+ sprintf(Horde_Imap_Client_Translation::t("Invalid METADATA value type \"%s\"."), $type),
+ Horde_Imap_Client_Exception::METADATA_INVALID
+ );
+ }
</ins><span class="cx"> }
</span><del>- }
- }
</del><ins>+ break;
</ins><span class="cx">
</span><del>- /**
- * Parse a METADATA response (RFC 5464 [4.4]).
- *
- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
- * @param Horde_Imap_Client_Tokenize $data The server response.
- *
- * @throws Horde_Imap_Client_Exception
- */
- protected function _parseMetadata(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Tokenize $data
- )
- {
- // Mailbox name is in UTF7-IMAP.
- $mbox = Horde_Imap_Client_Mailbox::get($data->next(), true);
</del><ins>+ case 'METADATA':
+ $mbox = $data->next();
</ins><span class="cx">
</span><del>- // Ignore unsolicited responses.
- if ($data->next() === true) {
</del><ins>+ // Ignore unsolicited responses.
+ if ($data->next() !== true) {
+ break;
+ }
+
</ins><span class="cx"> while (($entry = $data->next()) !== false) {
</span><del>- $pipeline->data['metadata'][strval($mbox)][$entry] = $data->next();
</del><ins>+ $this->_temp['metadata'][$mbox][$entry] = $data->next();
</ins><span class="cx"> }
</span><ins>+ break;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /* Overriden methods. */
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * @param array $opts Options:
- * - decrement: (boolean) If true, decrement the message count.
- * - pipeline: (Horde_Imap_Client_Interaction_Pipeline) Pipeline object.
</del><ins>+ * @param boolean $decrement If true, decrement the message count.
</ins><span class="cx"> */
</span><span class="cx"> protected function _deleteMsgs(Horde_Imap_Client_Mailbox $mailbox,
</span><span class="cx"> Horde_Imap_Client_Ids $ids,
</span><del>- array $opts = array())
</del><ins>+ $decrement = false)
</ins><span class="cx"> {
</span><span class="cx"> /* If there are pending FETCH cache writes, we need to write them
</span><span class="cx"> * before the UID -> sequence number mapping changes. */
</span><del>- if (isset($opts['pipeline'])) {
- $this->_updateCache($opts['pipeline']->fetch);
- }
</del><ins>+ $this->_updateCache($this->_fetch);
</ins><span class="cx">
</span><span class="cx"> $res = parent::_deleteMsgs($mailbox, $ids);
</span><span class="cx">
</span><span class="lines">@@ -3774,7 +3613,7 @@
</span><span class="cx"> $this->_temp['expunged']->add($res);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (!empty($opts['decrement'])) {
</del><ins>+ if ($decrement) {
</ins><span class="cx"> $mbox_ob = $this->_mailboxOb();
</span><span class="cx"> $mbox_ob->setStatus(
</span><span class="cx"> Horde_Imap_Client::STATUS_MESSAGES,
</span><span class="lines">@@ -3786,326 +3625,274 @@
</span><span class="cx"> /* Internal functions. */
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Sends command(s) to the IMAP server. A connection to the server must
</del><ins>+ * Perform a command on the IMAP server. A connection to the server must
</ins><span class="cx"> * have already been made.
</span><span class="cx"> *
</span><del>- * @param mixed $cmd Either a Command object or a Pipeline object.
</del><ins>+ * RFC 3501 allows the sending of multiple commands at once. For
+ * simplicity of implementation, we will execute commands one at a time.
+ * This allows us to easily determine data meant for a command while
+ * scanning for untagged responses unilaterally sent by the server.
+ * The only advantage of pipelining commands is to reduce the (small)
+ * amount of overhead needed to send commands. Modern IMAP servers do not
+ * meaningfully optimize response order internally, so that is not a
+ * worthwhile reason to implement pipelining. Even the IMAP gurus admit
+ * that pipelining is probably more trouble than it is worth.
</ins><span class="cx"> *
</span><del>- * @return Horde_Imap_Client_Interaction_Pipeline A pipeline object.
</del><ins>+ * @param Horde_Imap_Client_Data_Format_List $data The IMAP commands to
+ * execute.
+ * @param array $opts Additional options:
+ * - debug: (string) When debugging, send this string instead of the
+ * actual command/data sent.
+ * DEFAULT: Raw data output to debug stream.
+ * - keep_fetch: (boolean) Don't delete fetch cache object.
+ * DEFAULT: false
+ * - noliteralplus: (boolean) If true, don't use LITERAL+ extension.
+ * DEFAULT: false
+ *
+ * @return Horde_Imap_Client_Interaction_Server Server object.
+ *
</ins><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><del>- protected function _sendCmd($cmd)
</del><ins>+ protected function _sendLine(Horde_Imap_Client_Data_Format_List $data,
+ array $opts = array())
</ins><span class="cx"> {
</span><del>- $pipeline = ($cmd instanceof Horde_Imap_Client_Interaction_Command)
- ? $this->_pipeline($cmd)
- : $cmd;
</del><ins>+ /* Initialize internal data items at the beginning of a command. */
+ if ($data instanceof Horde_Imap_Client_Interaction_Client) {
+ $this->_fetch->clear();
+ $this->_temp['lastcmd'] = $data;
+ $this->_temp['modseqs'] = array();
+ $this->_temp['modseqs_nouid'] = array();
+ }
</ins><span class="cx">
</span><del>- if (!empty($this->_cmdQueue)) {
- /* Add commands in reverse order. */
- foreach (array_reverse($this->_cmdQueue) as $val) {
- $pipeline->add($val, true);
- }
</del><ins>+ try {
+ $this->_debug->client('', false);
</ins><span class="cx">
</span><del>- $this->_cmdQueue = array();
- }
</del><ins>+ $this->_processSendList($data, $opts);
</ins><span class="cx">
</span><del>- $cmd_list = array();
-
- foreach ($pipeline as $val) {
- if ($val->continuation) {
- $this->_sendCmdChunk($pipeline, $cmd_list);
- $this->_sendCmdChunk($pipeline, array($val));
- $cmd_list = array();
- } else {
- $cmd_list[] = $val;
</del><ins>+ if (!empty($opts['debug'])) {
+ $this->_debug->raw($opts['debug']);
</ins><span class="cx"> }
</span><del>- }
</del><span class="cx">
</span><del>- $this->_sendCmdChunk($pipeline, $cmd_list);
-
- /* If any FLAGS responses contain MODSEQs but not UIDs, don't
- * cache any data and immediately close the mailbox. */
- foreach ($pipeline->data['modseqs_nouid'] as $val) {
- if (!$pipeline->fetch[$val]->getUid()) {
- $this->_debug->info('Server provided FLAGS MODSEQ without providing UID.');
- $this->close();
- return $pipeline;
</del><ins>+ $this->_writeStream('', array('eol' => true));
+ } catch (Horde_Imap_Client_Exception $e) {
+ switch ($e->getCode()) {
+ case Horde_Imap_Client_Exception::SERVER_WRITEERROR:
+ $this->_temp['logout'] = true;
+ $this->logout();
+ break;
</ins><span class="cx"> }
</span><del>- }
</del><span class="cx">
</span><del>- /* Update HIGHESTMODSEQ value. */
- if (!empty($pipeline->data['modseqs'])) {
- $modseq = max($pipeline->data['modseqs']);
- $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ, $modseq);
- $this->_updateModSeq($modseq);
</del><ins>+ throw $e;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- /* Update cache items. */
- $this->_updateCache($pipeline->fetch);
</del><ins>+ while ($ob = $this->_getLine()) {
+ switch (get_class($ob)) {
+ case 'Horde_Imap_Client_Interaction_Server_Continuation':
+ break 2;
</ins><span class="cx">
</span><del>- return $pipeline;
- }
-
- /**
- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline The pipeline
- * object.
- * @param array $chunk List of commands to send.
- *
- * @throws Horde_Imap_Client_Exception
- */
- protected function _sendCmdChunk($pipeline, $chunk)
- {
- if (empty($chunk)) {
- return;
- }
-
- $cmd_count = count($chunk);
- $exception = null;
-
- foreach ($chunk as $val) {
- try {
- $old_debug = $this->_debug->debug;
- if (!is_null($val->debug)) {
- $this->_debug->raw($val->tag . ' ' . $val->debug . "\n");
- $this->_debug->debug = false;
</del><ins>+ case 'Horde_Imap_Client_Interaction_Server_Tagged':
+ if (empty($opts['keep_fetch'])) {
+ $this->_fetch->clear();
</ins><span class="cx"> }
</span><del>- if ($this->_processCmd($pipeline, $val, $val)) {
- $this->_connection->write('', true);
- } else {
- $cmd_count = 0;
- }
- $this->_debug->debug = $old_debug;
- } catch (Horde_Imap_Client_Exception $e) {
- $this->_debug->debug = $old_debug;
-
- switch ($e->getCode()) {
- case Horde_Imap_Client_Exception::SERVER_WRITEERROR:
- $this->_temp['logout'] = true;
- $this->logout();
- break;
- }
-
- throw $e;
</del><ins>+ break 2;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- while ($cmd_count) {
- try {
- if ($this->_getLine($pipeline) instanceof Horde_Imap_Client_Interaction_Server_Tagged) {
- --$cmd_count;
- }
- } catch (Horde_Imap_Client_Exception $e) {
- switch ($e->getCode()) {
- case $e::DISCONNECT:
- $this->_temp['logout'] = true;
- // Fall-through
-
- case $e::SERVER_READERROR:
- $this->logout();
- throw $e;
- }
-
- // Catch and store exception; don't throw until all input
- // is read. (For now, only store first exception.)
- if (is_null($exception)) {
- $exception = $e;
- }
-
- if (($e instanceof Horde_Imap_Client_Exception_ServerResponse) &&
- $e->command) {
- --$cmd_count;
- }
- }
- }
-
- if (!is_null($exception)) {
- throw $exception;
- }
</del><ins>+ return $ob;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Process/send a command to the remote server.
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline The pipeline
- * object.
- * @param Horde_Imap_Client_Interaction_Command $cmd The master command.
- * @param Horde_Imap_Client_Data_Format_List $data Commands to send.
</del><ins>+ * @param Horde_Imap_Client_Data_Format_List $data Commands to send.
+ * @param array $opts Options:
+ * - debug: (boolean) Whether debug info should be output.
+ * - noliteralplus: (boolean) If true, don't use LITERAL+ extension.
</ins><span class="cx"> *
</span><del>- * @return boolean True if EOL needed to finish command.
</del><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> * @throws Horde_Imap_Client_Exception_NoSupport
</span><span class="cx"> */
</span><del>- protected function _processCmd($pipeline, $cmd, $data)
</del><ins>+ protected function _processSendList($data, $opts)
</ins><span class="cx"> {
</span><ins>+ $s_opts = array('nodebug' => !empty($opts['debug']));
+
</ins><span class="cx"> foreach ($data as $key => $val) {
</span><del>- if ($val instanceof Horde_Imap_Client_Interaction_Command_Continuation) {
- $this->_connection->write('', true);
-
- /* Check for optional continuation responses when the command
- * has already finished. */
- if (!$cmd_continuation = $this->_processCmdContinuation($pipeline, $val->optional)) {
- return false;
- }
-
- $this->_processCmd(
- $pipeline,
- $cmd,
- $val->getCommands($cmd_continuation)
- );
- continue;
- }
-
</del><span class="cx"> if ($key) {
</span><del>- $this->_connection->write(' ');
</del><ins>+ $this->_writeStream(' ', $s_opts);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if ($val instanceof Horde_Imap_Client_Data_Format_List) {
</span><del>- $this->_connection->write('(');
- $this->_processCmd($pipeline, $cmd, $val);
- $this->_connection->write(')');
- } elseif (($val instanceof Horde_Imap_Client_Data_Format_String) &&
- $val->literal()) {
- /* RFC 3516/4466: Send literal8 if we have binary data. */
- if ($cmd->literal8 &&
- $val->binary() &&
- $this->queryCapability('BINARY')) {
- $binary = true;
- $this->_connection->write('~');
- } else {
- $binary = false;
- }
</del><ins>+ $this->_writeStream('(', $s_opts);
+ $this->_processSendList($val, $opts);
+ $this->_writeStream(')', $s_opts);
+ } elseif ($val instanceof Horde_Imap_Client_Data_Format_String) {
+ if ($val->literal()) {
+ /* RFC 3516/4466: Send literal8 if we have binary data. */
+ if ($val->binary() && $this->queryCapability('BINARY')) {
+ $binary = true;
+ $literal = '~';
+ } else {
+ $binary = false;
+ $literal = '';
+ }
</ins><span class="cx">
</span><del>- $literal_len = $val->length();
- $this->_connection->write('{' . $literal_len);
</del><ins>+ $literal_len = $val->length();
+ $literal .= '{' . $literal_len;
</ins><span class="cx">
</span><del>- /* RFC 2088 - If LITERAL+ is available, saves a roundtrip from
- * the server. */
- if ($cmd->literalplus && $this->queryCapability('LITERAL+')) {
- $this->_connection->write('+}', true);
</del><ins>+ /* RFC 2088 - If LITERAL+ is available, saves a roundtrip
+ * from the server. */
+ if (empty($opts['noliteralplus']) &&
+ $this->queryCapability('LITERAL+')) {
+ $this->_writeStream($literal . "+}", array_merge($s_opts, array(
+ 'eol' => true
+ )));
+ } else {
+ $this->_writeStream($literal . "}", array_merge($s_opts, array(
+ 'eol' => true
+ )));
+
+ $ob = $this->_getLine();
+ if (!($ob instanceof Horde_Imap_Client_Interaction_Server_Continuation)) {
+ $this->_debug->info("ERROR: Unexpected response from server while waiting for a continuation request.");
+ $e = new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Error when communicating with the mail server."),
+ Horde_Imap_Client_Exception::SERVER_READERROR
+ );
+ $e->details = strval($ob);
+ throw $e;
+ }
+ }
+
+ $this->_writeStream($val->getStream()->stream, array_merge($s_opts, array(
+ 'binary' => $binary,
+ 'literal' => $literal_len
+ )));
</ins><span class="cx"> } else {
</span><del>- $this->_connection->write('}', true);
- $this->_processCmdContinuation($pipeline);
</del><ins>+ $this->_writeStream($val->escapeStream(), $s_opts);
</ins><span class="cx"> }
</span><del>-
- $this->_connection->writeLiteral($val->getStream(), $literal_len, $binary);
</del><span class="cx"> } else {
</span><del>- $this->_connection->write($val->escape());
</del><ins>+ $this->_writeStream($val->escape(), $s_opts);
</ins><span class="cx"> }
</span><span class="cx"> }
</span><del>-
- return true;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Process a command continuation response.
</del><ins>+ * Shortcut to creating a new IMAP client command object.
</ins><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline The pipeline
- * object.
- * @param boolean $noexception Don't throw
- * exception if
- * continuation
- * does not occur.
- *
- * @return mixed A Horde_Imap_Client_Interaction_Server_Continuation
- * object or false.
- *
- * @throws Horde_Imap_Client_Exception
</del><ins>+ * @param mixed $cmd The IMAP command(s) to add.
</ins><span class="cx"> */
</span><del>- protected function _processCmdContinuation($pipeline, $noexception = false)
</del><ins>+ protected function _clientCommand($cmd = null)
</ins><span class="cx"> {
</span><del>- do {
- $ob = $this->_getLine($pipeline);
- } while ($ob instanceof Horde_Imap_Client_Interaction_Server_Untagged);
-
- if ($ob instanceof Horde_Imap_Client_Interaction_Server_Continuation) {
- return $ob;
- } elseif ($noexception) {
- return false;
</del><ins>+ $ob = new Horde_Imap_Client_Interaction_Client(++$this->_tag);
+ if (!is_null($cmd)) {
+ $ob->add($cmd);
</ins><span class="cx"> }
</span><del>-
- $this->_debug->info("ERROR: Unexpected response from server while waiting for a continuation request.");
- $e = new Horde_Imap_Client_Exception(
- Horde_Imap_Client_Translation::t("Error when communicating with the mail server."),
- Horde_Imap_Client_Exception::SERVER_READERROR
- );
- $e->details = strval($ob);
-
- throw $e;
</del><ins>+ return $ob;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * Shortcut to creating a new IMAP client command object.
</del><ins>+ * Writes data to the IMAP output stream and handles debug output.
</ins><span class="cx"> *
</span><del>- * @param string $cmd The IMAP command.
</del><ins>+ * @param mixed $data Either a string or stream resource.
+ * @param array $opts Additional options:
+ * - binary: (boolean) If true, the literal data is binary.
+ * - eol: (boolean) If true, output EOL.
+ * - literal: (integer) If set, the length of the literal data.
+ * - nodebug: (boolean) If true, don't output debug data.
</ins><span class="cx"> *
</span><del>- * @return Horde_Imap_Client_Interaction_Command A command object.
</del><ins>+ * @throws Horde_Imap_Client_Exception
</ins><span class="cx"> */
</span><del>- protected function _command($cmd)
</del><ins>+ protected function _writeStream($data, array $opts = array())
</ins><span class="cx"> {
</span><del>- return new Horde_Imap_Client_Interaction_Command($cmd, ++$this->_tag);
- }
</del><ins>+ $write_error = false;
</ins><span class="cx">
</span><del>- /**
- * Shortcut to creating a new pipeline object.
- *
- * @param Horde_Imap_Client_Interaction_Command $cmd An IMAP command to
- * add.
- *
- * @return Horde_Imap_Client_Interaction_Pipeline A pipeline object.
- */
- protected function _pipeline($cmd = null)
- {
- if (!isset($this->_temp['fetchob'])) {
- $this->_temp['fetchob'] = new Horde_Imap_Client_Fetch_Results(
- $this->_fetchDataClass,
- Horde_Imap_Client_Fetch_Results::SEQUENCE
</del><ins>+ if (is_resource($data)) {
+ rewind($data);
+ while (!feof($data)) {
+ if (fwrite($this->_stream, fread($data, 8192)) === false) {
+ $write_error = true;
+ break;
+ }
+ }
+ } elseif (fwrite($this->_stream, $data . (empty($opts['eol']) ? '' : "\r\n")) === false) {
+ $write_error = true;
+ }
+
+ if ($write_error) {
+ throw new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Server write error."),
+ Horde_Imap_Client_Exception::SERVER_WRITEERROR
</ins><span class="cx"> );
</span><span class="cx"> }
</span><span class="cx">
</span><del>- $ob = new Horde_Imap_Client_Interaction_Pipeline(
- clone $this->_temp['fetchob']
- );
</del><ins>+ if (!empty($opts['nodebug']) || !$this->_debug->debug) {
+ return;
+ }
</ins><span class="cx">
</span><del>- if (!is_null($cmd)) {
- $ob->add($cmd);
</del><ins>+ if (isset($opts['literal']) &&
+ empty($this->_params['debug_literal'])) {
+ $this->_debug->client('[' . (empty($opts['binary']) ? 'LITERAL' : 'BINARY') . ' DATA: ' . $opts['literal'] . ' bytes]');
+ } elseif (is_resource($data)) {
+ rewind($data);
+ while (!feof($data)) {
+ $this->_debug->raw(fread($data, 8192));
+ }
+ } else {
+ $this->_debug->raw($data . (empty($opts['eol']) ? '' : "\n"));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return $ob;
</del><ins>+ if (isset($opts['literal'])) {
+ $this->_debug->client('', false);
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Gets data from the IMAP server stream and parses it.
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
- *
</del><span class="cx"> * @return Horde_Imap_Client_Interaction_Server Server object.
</span><span class="cx"> *
</span><span class="cx"> * @throws Horde_Imap_Client_Exception
</span><span class="cx"> */
</span><del>- protected function _getLine(
- Horde_Imap_Client_Interaction_Pipeline $pipeline
- )
</del><ins>+ protected function _getLine()
</ins><span class="cx"> {
</span><del>- $server = Horde_Imap_Client_Interaction_Server::create(
- $this->_connection->read()
- );
</del><ins>+ $server = Horde_Imap_Client_Interaction_Server::create($this->_readStream());
</ins><span class="cx">
</span><span class="cx"> switch (get_class($server)) {
</span><span class="cx"> case 'Horde_Imap_Client_Interaction_Server_Continuation':
</span><del>- $this->_responseCode($pipeline, $server);
</del><ins>+ $this->_responseCode($server);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'Horde_Imap_Client_Interaction_Server_Tagged':
</span><del>- $pipeline->complete($server);
- $this->_responseCode($pipeline, $server);
</del><ins>+ $this->_responseCode($server);
+
+ /* If any FLAGS responses contain MODSEQs but not UIDs, don't
+ * cache any data and immediately close the mailbox. */
+ foreach ($this->_temp['modseqs_nouid'] as $val) {
+ if (!$this->_fetch[$val]->getUid()) {
+ $this->_debug->info('Server provided FLAGS MODSEQ without providing UID.');
+ $data = clone $this->_fetch;
+ $this->close();
+ $this->_fetch = $data;
+ break 2;
+ }
+ }
+
+ /* Update HIGHESTMODSEQ value. */
+ if (!empty($this->_temp['modseqs'])) {
+ $modseq = max($this->_temp['modseqs']);
+ $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ, $modseq);
+ $this->_updateModSeq($modseq);
+ }
+
+ /* Update cache items. */
+ $this->_updateCache($this->_fetch);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'Horde_Imap_Client_Interaction_Server_Untagged':
</span><span class="cx"> if (is_null($server->status)) {
</span><del>- $this->_serverResponse($pipeline, $server);
</del><ins>+ $this->_serverResponse($server);
</ins><span class="cx"> } else {
</span><del>- $this->_responseCode($pipeline, $server);
</del><ins>+ $this->_responseCode($server);
</ins><span class="cx"> }
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -4113,13 +3900,18 @@
</span><span class="cx"> switch ($server->status) {
</span><span class="cx"> case $server::BAD:
</span><span class="cx"> /* A tagged BAD response indicates that the tagged command caused
</span><del>- * the error. This information is unknown if untagged (RFC 3501
- * [7.1.3]). */
</del><ins>+ * the error. This information is unknown if untagged. (RFC 3501
+ * [7.1.3]) */
+ $cmd = ($server instanceof Horde_Imap_Client_Interaction_Server_Tagged)
+ ? $this->_temp['lastcmd']->getCommand()
+ : null;
+
</ins><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("IMAP error reported by server."),
</span><span class="cx"> 0,
</span><del>- $server,
- $pipeline
</del><ins>+ $server->status,
+ strval($server->token),
+ $cmd
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case $server::BYE:
</span><span class="lines">@@ -4127,6 +3919,8 @@
</span><span class="cx"> * be treated like a regular command: a client MUST process the
</span><span class="cx"> * entire command until logging out (RFC 3501 [3.4; 7.1.5]). */
</span><span class="cx"> if (empty($this->_temp['logout'])) {
</span><ins>+ $this->_temp['logout'] = true;
+ $this->logout();
</ins><span class="cx"> $e = new Horde_Imap_Client_Exception(
</span><span class="cx"> Horde_Imap_Client_Translation::t("IMAP Server closed the connection."),
</span><span class="cx"> Horde_Imap_Client_Exception::DISCONNECT
</span><span class="lines">@@ -4140,14 +3934,15 @@
</span><span class="cx"> /* An untagged NO response indicates a warning; ignore and assume
</span><span class="cx"> * that it also included response text code that is handled
</span><span class="cx"> * elsewhere. Throw exception if tagged; command handlers can
</span><del>- * catch this if able to workaround this issue (RFC 3501
- * [7.1.2]). */
</del><ins>+ * catch this if able to workaround this issue. (RFC 3501
+ * [7.1.2]) */
</ins><span class="cx"> if ($server instanceof Horde_Imap_Client_Interaction_Server_Tagged) {
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("IMAP error reported by server."),
</span><span class="cx"> 0,
</span><del>- $server,
- $pipeline
</del><ins>+ $server->status,
+ strval($server->token),
+ $this->_temp['lastcmd']->getCommand()
</ins><span class="cx"> );
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -4161,17 +3956,107 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><ins>+ * Read data from incoming IMAP stream.
+ *
+ * @return Horde_Imap_Client_Tokenize The tokenized data.
+ *
+ * @throws Horde_Imap_Client_Exception
+ */
+ protected function _readStream()
+ {
+ $got_data = false;
+ $literal_len = null;
+ $token = new Horde_Imap_Client_Tokenize();
+
+ do {
+ if (feof($this->_stream)) {
+ $this->_temp['logout'] = true;
+ $this->logout();
+ $this->_debug->info("ERROR: Server closed the connection.");
+ throw new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Mail server closed the connection unexpectedly."),
+ Horde_Imap_Client_Exception::DISCONNECT
+ );
+ }
+
+ if (is_null($literal_len)) {
+ $this->_debug->server('', false);
+
+ while (($in = fgets($this->_stream)) !== false) {
+ $got_data = true;
+
+ if (substr($in, -1) == "\n") {
+ $in = rtrim($in);
+ $this->_debug->raw($in . "\n");
+ $token->add($in);
+ break;
+ }
+
+ $this->_debug->raw($in);
+ $token->add($in);
+ }
+
+ /* Check for literal data. */
+ if (!is_null($len = $token->getLiteralLength())) {
+ if ($len['length']) {
+ $binary = $len['binary'];
+ $literal_len = $len['length'];
+ } else {
+ // Skip 0-length literal data.
+ $literal_len = null;
+ }
+ continue;
+ }
+ break;
+ }
+
+ $debug_literal = ($this->_debug->debug &&
+ !empty($this->_params['debug_literal']));
+ $old_len = $literal_len;
+
+ $this->_debug->server('', false);
+
+ while ($literal_len && !feof($this->_stream)) {
+ $in = fread($this->_stream, min($literal_len, 8192));
+ $token->add($in);
+ if ($debug_literal) {
+ $this->_debug->raw($in);
+ }
+
+ $got_data = true;
+
+ $in_len = strlen($in);
+ if ($in_len > $literal_len) {
+ break;
+ }
+ $literal_len -= $in_len;
+ }
+
+ $literal_len = null;
+
+ if (!$debug_literal) {
+ $this->_debug->raw('[' . ($binary ? 'BINARY' : 'LITERAL') . ' DATA: ' . $old_len . ' bytes]' . "\n");
+ }
+ } while (true);
+
+ if (!$got_data) {
+ $this->_debug->info("ERROR: IMAP read/timeout error.");
+ $this->logout();
+ throw new Horde_Imap_Client_Exception(
+ Horde_Imap_Client_Translation::t("Error when communicating with the mail server."),
+ Horde_Imap_Client_Exception::SERVER_READERROR
+ );
+ }
+
+ return $token;
+ }
+
+ /**
</ins><span class="cx"> * Handle untagged server responses (see RFC 3501 [2.2.2]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
- * @param Horde_Imap_Client_Interaction_Server $ob Server
- * response.
</del><ins>+ * @param Horde_Imap_Client_Interaction_Server $ob Server response.
</ins><span class="cx"> */
</span><del>- protected function _serverResponse(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Interaction_Server $ob
- )
</del><ins>+ protected function _serverResponse(Horde_Imap_Client_Interaction_Server $ob)
</ins><span class="cx"> {
</span><span class="cx"> $token = $ob->token;
</span><span class="cx">
</span><span class="lines">@@ -4179,12 +4064,12 @@
</span><span class="cx"> * line. */
</span><span class="cx"> switch ($first = strtoupper($token->current())) {
</span><span class="cx"> case 'CAPABILITY':
</span><del>- $this->_parseCapability($pipeline, $token->flushIterator());
</del><ins>+ $this->_parseCapability($token->flushIterator());
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'LIST':
</span><span class="cx"> case 'LSUB':
</span><del>- $this->_parseList($pipeline, $token);
</del><ins>+ $this->_parseList($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'STATUS':
</span><span class="lines">@@ -4195,12 +4080,12 @@
</span><span class="cx"> case 'SEARCH':
</span><span class="cx"> case 'SORT':
</span><span class="cx"> // Parse a SEARCH/SORT response (RFC 3501 [7.2.5] & RFC 5256 [4]).
</span><del>- $this->_parseSearch($pipeline, $token->flushIterator());
</del><ins>+ $this->_parseSearch($token->flushIterator());
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'ESEARCH':
</span><span class="cx"> // Parse an ESEARCH response (RFC 4466 [2.6.2]).
</span><del>- $this->_parseEsearch($pipeline, $token);
</del><ins>+ $this->_parseEsearch($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'FLAGS':
</span><span class="lines">@@ -4209,7 +4094,7 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'QUOTA':
</span><del>- $this->_parseQuota($pipeline, $token);
</del><ins>+ $this->_parseQuota($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'QUOTAROOT':
</span><span class="lines">@@ -4218,28 +4103,28 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'NAMESPACE':
</span><del>- $this->_parseNamespace($pipeline, $token);
</del><ins>+ $this->_parseNamespace($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'THREAD':
</span><del>- $this->_parseThread($pipeline, $token);
</del><ins>+ $this->_parseThread($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'ACL':
</span><del>- $this->_parseACL($pipeline, $token);
</del><ins>+ $this->_parseACL($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'LISTRIGHTS':
</span><del>- $this->_parseListRights($pipeline, $token);
</del><ins>+ $this->_parseListRights($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'MYRIGHTS':
</span><del>- $this->_parseMyRights($pipeline, $token);
</del><ins>+ $this->_parseMyRights($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'ID':
</span><span class="cx"> // ID extension (RFC 2971)
</span><del>- $this->_parseID($pipeline, $token);
</del><ins>+ $this->_parseID($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'ENABLED':
</span><span class="lines">@@ -4254,22 +4139,18 @@
</span><span class="cx">
</span><span class="cx"> case 'COMPARATOR':
</span><span class="cx"> // I18NLEVEL=2 extension (RFC 5255 [4.7])
</span><del>- $this->_parseComparator($pipeline, $token);
</del><ins>+ $this->_parseComparator($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'VANISHED':
</span><span class="cx"> // QRESYNC extension (RFC 5162 [3.6])
</span><del>- $this->_parseVanished($pipeline, $token);
</del><ins>+ $this->_parseVanished($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'ANNOTATION':
</span><del>- // Parse an ANNOTATION response.
- $this->_parseAnnotation($pipeline, $token);
- break;
-
</del><span class="cx"> case 'METADATA':
</span><del>- // Parse a METADATA response.
- $this->_parseMetadata($pipeline, $token);
</del><ins>+ // Parse a ANNOTATEMORE/METADATA response.
+ $this->_parseMetadata($token);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> default:
</span><span class="lines">@@ -4295,16 +4176,13 @@
</span><span class="cx">
</span><span class="cx"> case 'EXPUNGE':
</span><span class="cx"> // EXPUNGE response - RFC 3501 [7.4.1]
</span><del>- $this->_deleteMsgs($this->_selected, $this->getIdsOb($first, true), array(
- 'decrement' => true,
- 'pipeline' => $pipeline
- ));
- $pipeline->data['expunge_seen'] = true;
</del><ins>+ $this->_deleteMsgs($this->_selected, $this->getIdsOb($first, true), true);
+ $this->_temp['expunge_seen'] = true;
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'FETCH':
</span><span class="cx"> // FETCH response - RFC 3501 [7.4.2]
</span><del>- $this->_parseFetch($pipeline, $first, $token);
</del><ins>+ $this->_parseFetch($first, $token);
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> break;
</span><span class="lines">@@ -4314,16 +4192,11 @@
</span><span class="cx"> /**
</span><span class="cx"> * Handle status responses (see RFC 3501 [7.1]).
</span><span class="cx"> *
</span><del>- * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline
- * object.
- * @param Horde_Imap_Client_Interaction_Server $ob Server object.
</del><ins>+ * @param Horde_Imap_Client_Interaction_Server $ob Server object.
</ins><span class="cx"> *
</span><span class="cx"> * @throws Horde_Imap_Client_Exception_ServerResponse
</span><span class="cx"> */
</span><del>- protected function _responseCode(
- Horde_Imap_Client_Interaction_Pipeline $pipeline,
- Horde_Imap_Client_Interaction_Server $ob
- )
</del><ins>+ protected function _responseCode(Horde_Imap_Client_Interaction_Server $ob)
</ins><span class="cx"> {
</span><span class="cx"> if (is_null($ob->responseCode)) {
</span><span class="cx"> return;
</span><span class="lines">@@ -4358,12 +4231,12 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("Charset used in search query is not supported on the mail server."),
</span><span class="cx"> Horde_Imap_Client_Exception::BADCHARSET,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'CAPABILITY':
</span><del>- $this->_parseCapability($pipeline, $rc->data);
</del><ins>+ $this->_parseCapability($rc->data);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'PARSE':
</span><span class="lines">@@ -4374,8 +4247,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> sprintf(Horde_Imap_Client_Translation::t("The mail server was unable to parse the contents of the mail message: %s"), strval($ob->token)),
</span><span class="cx"> Horde_Imap_Client_Exception::PARSEERROR,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx"> }
</span><span class="cx"> break;
</span><span class="lines">@@ -4390,7 +4263,7 @@
</span><span class="cx">
</span><span class="cx"> case 'TRYCREATE':
</span><span class="cx"> // RFC 3501 [7.1]
</span><del>- $pipeline->data['trycreate'] = true;
</del><ins>+ $this->_temp['trycreate'] = true;
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'PERMANENTFLAGS':
</span><span class="lines">@@ -4413,7 +4286,7 @@
</span><span class="cx">
</span><span class="cx"> case 'REFERRAL':
</span><span class="cx"> // Defined by RFC 2221
</span><del>- $pipeline->data['referral'] = new Horde_Imap_Client_Url($rc->data[0]);
</del><ins>+ $this->_temp['referral'] = new Horde_Imap_Client_Url($rc->data[0]);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'UNKNOWN-CTE':
</span><span class="lines">@@ -4421,20 +4294,20 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The mail server was unable to parse the contents of the mail message."),
</span><span class="cx"> Horde_Imap_Client_Exception::UNKNOWNCTE,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'APPENDUID':
</span><span class="cx"> // Defined by RFC 4315
</span><span class="cx"> // APPENDUID: [0] = UIDVALIDITY, [1] = UID(s)
</span><del>- $pipeline->data['appenduid'] = $this->getIdsOb($rc->data[1]);
</del><ins>+ $this->_temp['appenduid'] = $this->getIdsOb($rc->data[1]);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'COPYUID':
</span><span class="cx"> // Defined by RFC 4315
</span><span class="cx"> // COPYUID: [0] = UIDVALIDITY, [1] = UIDFROM, [2] = UIDTO
</span><del>- $pipeline->data['copyuid'] = array_combine(
</del><ins>+ $this->_temp['copyuid'] = array_combine(
</ins><span class="cx"> $this->getIdsOb($rc->data[1])->ids,
</span><span class="cx"> $this->getIdsOb($rc->data[2])->ids
</span><span class="cx"> );
</span><span class="lines">@@ -4442,7 +4315,7 @@
</span><span class="cx"> /* Use UIDPLUS information to move cached data to new mailbox (see
</span><span class="cx"> * RFC 4549 [4.2.2.1]). Need to move now, because a MOVE might
</span><span class="cx"> * EXPUNGE immediately afterwards. */
</span><del>- $this->_moveCache($pipeline->data['copydest'], $pipeline->data['copyuid'], $rc->data[0]);
</del><ins>+ $this->_moveCache($this->_temp['copydest'], $this->_temp['copyuid'], $rc->data[0]);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'UIDNOTSTICKY':
</span><span class="lines">@@ -4455,8 +4328,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("Could not save message on server."),
</span><span class="cx"> Horde_Imap_Client_Exception::CATENATE_BADURL,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'TOOBIG':
</span><span class="lines">@@ -4464,44 +4337,44 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("Could not save message data because it is too large."),
</span><span class="cx"> Horde_Imap_Client_Exception::CATENATE_TOOBIG,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'HIGHESTMODSEQ':
</span><span class="cx"> // Defined by RFC 4551 [3.1.1]
</span><del>- $pipeline->data['modseqs'][] = $rc->data[0];
</del><ins>+ $this->_temp['modseqs'][] = $rc->data[0];
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'NOMODSEQ':
</span><span class="cx"> // Defined by RFC 4551 [3.1.2]
</span><del>- $pipeline->data['modseqs'][] = 0;
</del><ins>+ $this->_temp['modseqs'][] = 0;
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'MODIFIED':
</span><span class="cx"> // Defined by RFC 4551 [3.2]
</span><del>- $pipeline->data['modified']->add($rc->data[0]);
</del><ins>+ $this->_temp['modified']->add($rc->data[0]);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'CLOSED':
</span><span class="cx"> // Defined by RFC 5162 [3.7]
</span><del>- if (isset($pipeline->data['qresyncmbox'])) {
</del><ins>+ if (isset($this->_temp['qresyncmbox'])) {
</ins><span class="cx"> /* If there is any pending FETCH cache entries, flush them
</span><span class="cx"> * now before changing mailboxes. */
</span><del>- $this->_updateCache($pipeline->fetch);
- $pipeline->fetch->clear();
</del><ins>+ $this->_updateCache($this->_fetch);
+ $this->_fetch->clear();
</ins><span class="cx">
</span><span class="cx"> $this->_changeSelected(
</span><del>- $pipeline->data['qresyncmbox'][0],
- $pipeline->data['qresyncmbox'][1]
</del><ins>+ $this->_temp['qresyncmbox'][0],
+ $this->_temp['qresyncmbox'][1]
</ins><span class="cx"> );
</span><del>- unset($pipeline->data['qresyncmbox']);
</del><ins>+ unset($this->_temp['qresyncmbox']);
</ins><span class="cx"> }
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'NOTSAVED':
</span><span class="cx"> // Defined by RFC 5182 [2.5]
</span><del>- $pipeline->data['searchnotsaved'] = true;
</del><ins>+ $this->_temp['searchnotsaved'] = true;
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'BADCOMPARATOR':
</span><span class="lines">@@ -4509,8 +4382,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The comparison algorithm was not recognized by the server."),
</span><span class="cx"> Horde_Imap_Client_Exception::BADCOMPARATOR,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'METADATA':
</span><span class="lines">@@ -4519,7 +4392,7 @@
</span><span class="cx"> switch ($md[0]) {
</span><span class="cx"> case 'LONGENTRIES':
</span><span class="cx"> // Defined by RFC 5464 [4.2.1]
</span><del>- $pipeline->data['metadata']['*longentries'] = intval($md[1]);
</del><ins>+ $this->_temp['metadata']['*longentries'] = intval($md[1]);
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'MAXSIZE':
</span><span class="lines">@@ -4527,8 +4400,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The metadata item could not be saved because it is too large."),
</span><span class="cx"> Horde_Imap_Client_Exception::METADATA_MAXSIZE,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ intval($md[1])
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'NOPRIVATE':
</span><span class="lines">@@ -4536,8 +4409,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The metadata item could not be saved because the server does not support private annotations."),
</span><span class="cx"> Horde_Imap_Client_Exception::METADATA_NOPRIVATE,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'TOOMANY':
</span><span class="lines">@@ -4545,15 +4418,15 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The metadata item could not be saved because the maximum number of annotations has been exceeded."),
</span><span class="cx"> Horde_Imap_Client_Exception::METADATA_TOOMANY,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx"> }
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'UNAVAILABLE':
</span><span class="cx"> // Defined by RFC 5530 [3]
</span><del>- $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception(
</del><ins>+ $this->_temp['loginerr'] = new Horde_Imap_Client_Exception(
</ins><span class="cx"> Horde_Imap_Client_Translation::t("Remote server is temporarily unavailable."),
</span><span class="cx"> Horde_Imap_Client_Exception::LOGIN_UNAVAILABLE
</span><span class="cx"> );
</span><span class="lines">@@ -4561,7 +4434,7 @@
</span><span class="cx">
</span><span class="cx"> case 'AUTHENTICATIONFAILED':
</span><span class="cx"> // Defined by RFC 5530 [3]
</span><del>- $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception(
</del><ins>+ $this->_temp['loginerr'] = new Horde_Imap_Client_Exception(
</ins><span class="cx"> Horde_Imap_Client_Translation::t("Authentication failed."),
</span><span class="cx"> Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED
</span><span class="cx"> );
</span><span class="lines">@@ -4569,7 +4442,7 @@
</span><span class="cx">
</span><span class="cx"> case 'AUTHORIZATIONFAILED':
</span><span class="cx"> // Defined by RFC 5530 [3]
</span><del>- $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception(
</del><ins>+ $this->_temp['loginerr'] = new Horde_Imap_Client_Exception(
</ins><span class="cx"> Horde_Imap_Client_Translation::t("Authentication was successful, but authorization failed."),
</span><span class="cx"> Horde_Imap_Client_Exception::LOGIN_AUTHORIZATIONFAILED
</span><span class="cx"> );
</span><span class="lines">@@ -4577,7 +4450,7 @@
</span><span class="cx">
</span><span class="cx"> case 'EXPIRED':
</span><span class="cx"> // Defined by RFC 5530 [3]
</span><del>- $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception(
</del><ins>+ $this->_temp['loginerr'] = new Horde_Imap_Client_Exception(
</ins><span class="cx"> Horde_Imap_Client_Translation::t("Authentication credentials have expired."),
</span><span class="cx"> Horde_Imap_Client_Exception::LOGIN_EXPIRED
</span><span class="cx"> );
</span><span class="lines">@@ -4585,7 +4458,7 @@
</span><span class="cx">
</span><span class="cx"> case 'PRIVACYREQUIRED':
</span><span class="cx"> // Defined by RFC 5530 [3]
</span><del>- $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception(
</del><ins>+ $this->_temp['loginerr'] = new Horde_Imap_Client_Exception(
</ins><span class="cx"> Horde_Imap_Client_Translation::t("Operation failed due to a lack of a secure connection."),
</span><span class="cx"> Horde_Imap_Client_Exception::LOGIN_PRIVACYREQUIRED
</span><span class="cx"> );
</span><span class="lines">@@ -4596,8 +4469,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("You do not have adequate permissions to carry out this operation."),
</span><span class="cx"> Horde_Imap_Client_Exception::NOPERM,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'INUSE':
</span><span class="lines">@@ -4605,13 +4478,13 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("There was a temporary issue when attempting this operation. Please try again later."),
</span><span class="cx"> Horde_Imap_Client_Exception::INUSE,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'EXPUNGEISSUED':
</span><span class="cx"> // Defined by RFC 5530 [3]
</span><del>- $pipeline->data['expungeissued'] = true;
</del><ins>+ $this->_temp['expungeissued'] = true;
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case 'CORRUPTION':
</span><span class="lines">@@ -4619,8 +4492,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The mail server is reporting corrupt data in your mailbox."),
</span><span class="cx"> Horde_Imap_Client_Exception::CORRUPTION,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'SERVERBUG':
</span><span class="lines">@@ -4635,8 +4508,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The mail server has denied the request."),
</span><span class="cx"> Horde_Imap_Client_Exception::LIMIT,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'OVERQUOTA':
</span><span class="lines">@@ -4644,8 +4517,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The operation failed because the quota has been exceeded on the mail server."),
</span><span class="cx"> Horde_Imap_Client_Exception::OVERQUOTA,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'ALREADYEXISTS':
</span><span class="lines">@@ -4653,8 +4526,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The object could not be created because it already exists."),
</span><span class="cx"> Horde_Imap_Client_Exception::ALREADYEXISTS,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'NONEXISTENT':
</span><span class="lines">@@ -4662,8 +4535,8 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The object could not be deleted because it does not exist."),
</span><span class="cx"> Horde_Imap_Client_Exception::NONEXISTENT,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> case 'USEATTR':
</span><span class="lines">@@ -4671,23 +4544,13 @@
</span><span class="cx"> throw new Horde_Imap_Client_Exception_ServerResponse(
</span><span class="cx"> Horde_Imap_Client_Translation::t("The special-use attribute requested for the mailbox is not supported."),
</span><span class="cx"> Horde_Imap_Client_Exception::USEATTR,
</span><del>- $ob,
- $pipeline
</del><ins>+ $ob->status,
+ strval($ob->token)
</ins><span class="cx"> );
</span><span class="cx">
</span><del>- case 'DOWNGRADED':
- // Defined by RFC 6858 [3]
- $downgraded = $this->getIdsOb($rc->data[0]);
- foreach ($pipeline->fetch as $val) {
- if (in_array($val->getUid(), $downgraded)) {
- $val->setDowngraded(true);
- }
- }
- break;
-
</del><span class="cx"> case 'XPROXYREUSE':
</span><span class="cx"> // The proxy connection was reused, so no need to do login tasks.
</span><del>- $pipeline->data['proxyreuse'] = true;
</del><ins>+ $this->_temp['proxyreuse'] = true;
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> default:
</span></span></pre>
</div>
</div>
</body>
</html>