Add Horde_Imap_Client_Base::parseCacheId().
authorMichael M Slusarz <slusarz@curecanti.org>
Mon, 1 Feb 2010 04:15:02 +0000 (21:15 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Mon, 1 Feb 2010 04:15:02 +0000 (21:15 -0700)
This makes all cache ID generation internal to Horde_Imap_Client, which
is desirable.

Additionally, for CONDSTORE hosts, we should use the last modseq seen
with respect to the *browser*, not the server.  This ensures that all
changes are caught when the browser does a request - if a browser misses
a request, for example, it may not catch the changes.

framework/Imap_Client/lib/Horde/Imap/Client/Base.php
framework/Imap_Client/package.xml
imp/lib/Mailbox.php
imp/lib/Views/ListMessages.php

index e3fb759..5e566f0 100644 (file)
@@ -2701,6 +2701,8 @@ abstract class Horde_Imap_Client_Base
      * Returns a unique identifier for the current mailbox status.
      *
      * @param string $mailbox  A mailbox. Either in UTF7-IMAP or UTF-8.
+     * @param array $addl      Additional cache info to add to the cache ID
+     *                         string.
      *
      * @return string  The cache ID string, which will change when the
      *                 composition of the mailbox changes. The uidvalidity
@@ -2708,35 +2710,74 @@ abstract class Horde_Imap_Client_Base
      *                 by the '|' character.
      * @throws Horde_Imap_Client_Exception
      */
-    public function getCacheId($mailbox)
+    public function getCacheId($mailbox, $addl = array())
     {
         $query = Horde_Imap_Client::STATUS_UIDVALIDITY;
 
         /* Use MODSEQ as cache ID if CONDSTORE extension is available. */
         if (isset($this->_init['enabled']['CONDSTORE'])) {
-            $condstore = true;
             $query |= Horde_Imap_Client::STATUS_HIGHESTMODSEQ;
         } else {
-            $condstore = false;
             $query |= Horde_Imap_Client::STATUS_MESSAGES | Horde_Imap_Client::STATUS_UIDNEXT;
         }
 
         $status = $this->status($mailbox, $query);
 
-        if ($condstore) {
-            return implode('|', array($status['uidvalidity'], $status['highestmodseq']));
+        if ($query & Horde_Imap_Client::STATUS_HIGHESTMODSEQ) {
+            $parts = array(
+                'V' . $status['uidvalidity'],
+                'H' . $status['highestmodseq']
+            );
+        } else {
+            if (empty($status['uidnext'])) {
+                /* UIDNEXT is not strictly required on mailbox open. If it is
+                 * not available, use the last UID in the mailbox instead. */
+                $this->_temp['nocache'] = true;
+                $search_res = $this->_getSeqUIDLookup(array($status['messages']), true);
+                unset($this->_temp['nocache']);
+                $status['uidnext'] = reset($search_res['uids']);
+            }
+
+            $parts = array(
+                'V' . $status['uidvalidity'],
+                'U' . $status['uidnext'],
+                'M' . $status['messages']
+            );
         }
 
-        if (empty($status['uidnext'])) {
-            /* UIDNEXT is not strictly required on mailbox open. If it is
-             * not available, use the last UID in the mailbox instead. */
-            $this->_temp['nocache'] = true;
-            $search_res = $this->_getSeqUIDLookup(array($status['messages']), true);
-            unset($this->_temp['nocache']);
-            $status['uidnext'] = reset($search_res['uids']);
+        return implode('|', array_merge($parts, $addl));
+    }
+
+    /**
+     * Parses a cacheID created by getCacheId().
+     *
+     * @param string $id  The cache ID.
+     *
+     * @return array  An array with the following information:
+     * <pre>
+     * 'highestmodseq' - (integer)
+     * 'messages' - (integer)
+     * 'uidnext' - (integer)
+     * 'uidvalidity' - (integer) Always present
+     * </pre>
+     */
+    public function parseCacheId($id)
+    {
+        $data = array(
+            'H' => 'highestmodseq',
+            'M' => 'messages',
+            'U' => 'uidnext',
+            'V' => 'uidvalidity'
+        );
+        $info = array();
+
+        foreach (explode('|', $id) as $part) {
+            if (isset($data[$part[0]])) {
+                $info[$data[$part[0]]] = intval(substr($part, 1));
+            }
         }
 
-        return implode('|', array($status['uidvalidity'], $status['uidnext'], $status['messages']));
+        return $info;
     }
 
     /**
index 0bd4ef2..e45d3ec 100644 (file)
@@ -31,7 +31,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
   <api>alpha</api>
  </stability>
  <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
- <notes>* Added STATUS_LASTMODSEQ and STATUS_LASTMODSEQUIDS status() entries.
+ <notes>* Add Horde_Imap_Client_Base::parseCacheId().
+ * Added STATUS_LASTMODSEQ and STATUS_LASTMODSEQUIDS status() entries.
  * Add support for LIST-STATUS (draft-ietf-morg-status-in-list-01).
  * Add support for THREAD=REFS (draft-ietf-morg-inthread-00).
  * Add support for RFC 5258 (LIST-EXTENDED).
index 032cf49..9ad758b 100644 (file)
@@ -833,8 +833,7 @@ class IMP_Mailbox
         if (!$this->_searchmbox) {
             $sortpref = IMP::getSort($this->_mailbox);
             try {
-                $id = $GLOBALS['imp_imap']->ob()->getCacheId($this->_mailbox);
-                return $id . '|' . $sortpref['by'] . '|' . $sortpref['dir'];
+                return $GLOBALS['imp_imap']->ob()->getCacheId($this->_mailbox, array($sortpref['by'], $sortpref['dir']));
             } catch (Horde_Imap_Client_Exception $e) {}
         }
 
index 2783d63..58a92f0 100644 (file)
@@ -150,8 +150,8 @@ class IMP_Views_ListMessages
             $uid_expire = false;
             try {
                 $status = $GLOBALS['imp_imap']->ob()->status($mbox, Horde_Imap_Client::STATUS_UIDVALIDITY);
-                list($old_uidvalid,) = explode('|', $args['cacheid']);
-                $uid_expire = ($old_uidvalid != $status['uidvalidity']);
+                $parsed = $GLOBALS['imp_imap']->ob()->parseCacheId($args['cacheid']);
+                $uid_expire = ($parsed['uidvalidity'] != $status['uidvalidity']);
             } catch (Horde_Imap_Cache_Exception $e) {
                 $uid_expire = true;
             }
@@ -181,10 +181,17 @@ class IMP_Views_ListMessages
                 /* Check for cached entries marked as changed via CONDSTORE
                  * IMAP extension. If changed, resend the entire entry to
                  * update the browser cache (done below). */
-                if ($args['change']) {
-                    $status = $GLOBALS['imp_imap']->ob()->status($mbox, Horde_Imap_Client::STATUS_LASTMODSEQUIDS);
-                    if (!empty($status['lastmodsequids'])) {
-                        $changed = array_flip($status['lastmodsequids']);
+                if ($args['change'] && $args['cacheid']) {
+                    if (!isset($parsed)) {
+                        $parsed = $GLOBALS['imp_imap']->ob()->parseCacheId($args['cacheid']);
+                    }
+                    if (!empty($parsed['highestmodseq'])) {
+                        try {
+                            $res = $GLOBALS['imp_imap']->ob()->fetch($mbox, array(Horde_Imap_Client::FETCH_UID => 1), array('changedsince' => $parsed['highestmodseq']));
+                            if (!empty($res)) {
+                                $changed = array_flip(array_keys($res));
+                            }
+                        } catch (Horde_Imap_Client_Exception $e) {}
                     }
                 }
             }