Add run-time configurable caching for headers fetch requests
authorMichael M Slusarz <slusarz@curecanti.org>
Tue, 1 Dec 2009 05:29:08 +0000 (22:29 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Tue, 1 Dec 2009 06:29:25 +0000 (23:29 -0700)
Fix some borken behavior when caching base headertext also.

framework/Imap_Client/lib/Horde/Imap/Client/Base.php
framework/Imap_Client/package.xml

index b0fd58d..850987c 100644 (file)
@@ -1719,6 +1719,9 @@ abstract class Horde_Imap_Client_Base
      *         Each entry should have a unique 'label' value.
      *   Value: (array) One array for each request. Each array may contain
      *          the following options:
+     *     'cache' - (boolean) If true, and 'peek' is also true, will cache
+     *               the result of this call.
+     *               DEFAULT: false
      *     'headers' - (array) The headers to search for (case-insensitive).
      *                 DEFAULT: NONE (MANDATORY)
      *     'id' - (string) The MIME ID to search.
@@ -1897,8 +1900,9 @@ abstract class Horde_Imap_Client_Base
      */
     public function fetch($mailbox, $criteria, $options = array())
     {
-        $cache_array = $get_fields = $new_criteria = $ret = array();
-        $header_cache = null;
+        $cache_array = $get_fields = $header_cache = $new_criteria = $ret = array();
+        $headerpeek = false;
+        $headertext = null;
         $qresync = isset($this->_init['enabled']['QRESYNC']);
         $seq = !empty($options['sequence']);
 
@@ -1918,7 +1922,8 @@ abstract class Horde_Imap_Client_Base
 
         $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_AUTO);
 
-        $cf = $this->_initCache(true)
+        $cache_avail = $this->_initCache(true);
+        $cf = $cache_avail
             ? $this->_params['cache']['fields']
             : array();
 
@@ -2014,15 +2019,38 @@ abstract class Horde_Imap_Client_Base
             case Horde_Imap_Client::FETCH_HEADERTEXT:
                 // Caching for this access only - and only base header is
                 // cached.
-                if (!empty($v['peek'])) {
-                    foreach ($v as $k2 => $v2) {
+                foreach ($v as $k2 => $v2) {
+                    if (!empty($v['peek'])) {
+                        $headerpeek = true;
                         if (!isset($v2['id']) || ($v2['id'] === 0)) {
-                            $headertext_cache = $k2;
+                            $headertext = $k2;
                             break;
                         }
                     }
                 }
                 break;
+
+            case Horde_Imap_Client::FETCH_HEADERS:
+                $this->_temp['headers_caching'] = array();
+
+                /* Only cache if directly requested. */
+                if ($cache_avail) {
+                    $fetch_field = 'headers';
+
+                    foreach ($v as $key => $val) {
+                        if (!empty($val['cache']) &&
+                            !empty($val['peek'])) {
+                            $cache_field = 'HIChdrs';
+                            ksort($val);
+                            $header_cache[] = array(
+                                'f' => hash('md5', serialize($val)),
+                                'k' => $key,
+                                'l' => $val['label']
+                            );
+                        }
+                    }
+                }
+                break;
             }
 
             if (!is_null($cache_field)) {
@@ -2035,7 +2063,7 @@ abstract class Horde_Imap_Client_Base
         }
 
         /* If nothing is cacheable, we can do a straight search. */
-        if (empty($cache_array) && is_null($header_cache)) {
+        if (empty($cache_array) && $headerpeek) {
             return $this->_fetch($criteria, $options);
         }
 
@@ -2061,23 +2089,44 @@ abstract class Horde_Imap_Client_Base
             $ret[$id] = array('uid' => $id);
 
             foreach ($cache_array as $key => $cval) {
-                // Retrieved from cache so store in return array
-                if (isset($data[$val][$cval['c']])) {
-                    $ret[$id][$cval['f']] = $data[$val][$cval['c']];
-                    unset($crit[$key]);
+                switch ($key) {
+                case Horde_Imap_Client::FETCH_HEADERS:
+                    /* HEADERS caching. */
+                    foreach ($header_cache as $hval) {
+                        if (isset($data[$val][$cval['c']][$hval['f']])) {
+                            $ret[$id][$cval['f']][$hval['l']] = $data[$val][$cval['c']][$hval['f']];
+                            unset($crit[$key][$hval['k']]);
+                            if (empty($crit[$key])) {
+                                unset($crit[$key]);
+                            }
+                        } else {
+                            $this->_temp['headers_caching'][$hval['l']] = $hval['f'];
+                        }
+                    }
+                    break;
+
+                default:
+                    /* Retrieved from cache so store in return array. */
+                    if (isset($data[$val][$cval['c']])) {
+                        $ret[$id][$cval['f']] = $data[$val][$cval['c']];
+                        unset($crit[$key]);
+                    }
+                    break;
                 }
             }
 
-            if (!is_null($header_cache) &&
+
+            /* HEADERTEXT caching for this access only. */
+            if (!is_null($headertext) &&
                 isset($this->_temp['headertext'][$val])) {
-                $ret[$id]['headertext'][0] = empty($crit[Horde_Imap_Client::FETCH_HEADERTEXT][$header_cache]['parse'])
+                $ret[$id]['headertext'][0] = empty($crit[Horde_Imap_Client::FETCH_HEADERTEXT][$headertext]['parse'])
                     ? $this->_temp['headertext'][$val]
                     : Horde_Mime_Headers::parseHeaders($this->_temp['headertext'][$val]);
 
                 if (count($crit[Horde_Imap_Client::FETCH_HEADERTEXT]) == 1) {
                     unset($crit[Horde_Imap_Client::FETCH_HEADERTEXT]);
                 } else {
-                    unset($crit[Horde_Imap_Client::FETCH_HEADERTEXT][$header_cache]);
+                    unset($crit[Horde_Imap_Client::FETCH_HEADERTEXT][$headertext]);
                 }
             }
 
@@ -2105,14 +2154,21 @@ abstract class Horde_Imap_Client_Base
                 while (list($k, $v) = each($fetch_res)) {
                     reset($v);
                     while (list($k2, $v2) = each($v)) {
-                        if (!is_null($header_cache) &&
-                            ($k2 == 'headertext') &&
-                            isset($v2[0])) {
-                            /* Store headertext internally as the raw text -
-                             * can convert to parsed format if needed. */
-                            $this->_temp['headertext'][$k] = $v2[0];
-                            if (!empty($val['c'][Horde_Imap_Client::FETCH_HEADERTEXT][$header_cache]['parse'])) {
-                                $v2[0] = Horde_Mime_Headers::parseHeaders($v2[0]);
+                        switch ($k2) {
+                        case 'headertext':
+                            foreach ($val['c'][Horde_Imap_Client::FETCH_HEADERTEXT] as $hkey => $hval) {
+                                if (!is_null($headertext) &&
+                                    ($headertext == $hkey)) {
+                                    /* Store headertext internally as the raw
+                                     * text; can convert to parsed format later
+                                     * if needed. */
+                                    $this->_temp['headertext'][$k] = $v2[$hkey];
+                                }
+
+                                if (!empty($hval['parse'])) {
+                                    $id = isset($hval['id']) ? $hval['id'] : 0;
+                                    $v2[$id] = Horde_Mime_Headers::parseHeaders($v2[$id]);
+                                }
                             }
                         }
 
@@ -2723,6 +2779,15 @@ abstract class Horde_Imap_Client_Base
                         $tmp['HICsize'] = $val;
                     }
                     break;
+
+                case 'headers':
+                    reset($val);
+                    if (isset($this->_temp['headers_caching'][key($val)])) {
+                        $tmp['HIChdrs'][$this->_temp['headers_caching'][key($val)]] = is_array($val)
+                            ? current($val)
+                            : clone current($val);
+                    }
+                    break;
                 }
             }
 
index bef55da..633f08e 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>* Add support for THREAD=REFS (draft-ietf-morg-inthread-00).
+ <notes>* Add run-time configurable caching for headers fetch requests.
+ * Add support for THREAD=REFS (draft-ietf-morg-inthread-00).
  * Add support for RFC 5258 (LIST-EXTENDED).
  * Add Horde_Imap_Client_Utils::createUrl().
  * Support SORT=DISPLAY extension.