From: Michael M Slusarz Date: Wed, 16 Sep 2009 17:31:51 +0000 (-0600) Subject: Add workaround for WITHIN search extension for servers which don't support it X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=2643fc7d368224142a0001de173154c0536c09f6;p=horde.git Add workaround for WITHIN search extension for servers which don't support it --- diff --git a/framework/Imap_Client/lib/Horde/Imap/Client/Base.php b/framework/Imap_Client/lib/Horde/Imap/Client/Base.php index 94858970b..5c4bbcf0b 100644 --- a/framework/Imap_Client/lib/Horde/Imap/Client/Base.php +++ b/framework/Imap_Client/lib/Horde/Imap/Client/Base.php @@ -1310,7 +1310,7 @@ abstract class Horde_Imap_Client_Base $query = new Horde_Imap_Client_Search_Query(); } - $options['_query'] = $query->build(); + $options['_query'] = $query->build($this->capability()); /* Optimization - if query is just for a count of either RECENT or * ALL messages, we can send status information instead. Can't diff --git a/framework/Imap_Client/lib/Horde/Imap/Client/Search/Query.php b/framework/Imap_Client/lib/Horde/Imap/Client/Search/Query.php index 39fff05d5..b87fcf347 100644 --- a/framework/Imap_Client/lib/Horde/Imap/Client/Search/Query.php +++ b/framework/Imap_Client/lib/Horde/Imap/Client/Search/Query.php @@ -59,13 +59,6 @@ class Horde_Imap_Client_Search_Query protected $_search = array(); /** - * List of extensions needed for advanced queries. - * - * @var array - */ - protected $_exts = array(); - - /** * The Horde_Imap_Client_Utils object * * @var Horde_Imap_Client_Utils @@ -109,17 +102,25 @@ class Horde_Imap_Client_Search_Query /** * Builds an IMAP4rev1 compliant search string. * + * @param array $exts The list of extensions supported by the server. + * This determines whether certain criteria can be + * used, and determines whether workarounds are used + * for other criteria. In the format returned by + * Horde_Imap_Client_Base::capability(). + * * @return array An array with 3 elements: *
      * 'charset' - (string) The charset of the search string.
+     * 'exts' - (array) The list of IMAP extensions used to create the string.
      * 'imap4' - (boolean) True if the search uses IMAP4 criteria (as opposed
      *           to IMAP2 search criteria)
      * 'query' - (string) The IMAP search string
      * 
+ * @throws Horde_Imap_Client_Exception */ - public function build() + public function build($exts = array()) { - $cmds = array(); + $cmds = $exts_used = array(); $imap4 = false; $ptr = &$this->_search; @@ -221,17 +222,39 @@ class Horde_Imap_Client_Search_Query } if (!empty($ptr['within'])) { - $imap4 = true; - $this->_exts['WITHIN'] = true; + if (isset($exts['WITHIN'])) { + foreach ($ptr['within'] as $key => $val) { + $cmds[] = ($val['not'] ? 'NOT ' : '') . $key . ' ' . $val['interval']; + } + $exts_used[] = 'WITHIN'; + $imap4 = true; + } else { + // This workaround is only accurate to within 1 day, due to + // limitations with the IMAP4rev1 search commands. + foreach ($ptr['within'] as $key => $val) { + $tmp = ''; + if ($val['not']) { + $tmp = 'NOT '; + // NOT searches were not in IMAP2 + $imap4 = true; + } - foreach ($ptr['within'] as $key => $val) { - $cmds[] = ($val['not'] ? 'NOT ' : '') . $key . ' ' . $val['interval']; + $date = new DateTime('now -' . $val['interval'] . ' seconds'); + $cmds[] = $tmp . + (($key == self::INTERVAL_OLDER) ? self::DATE_BEFORE : self::DATE_SINCE) . + ' ' . $date->format('d-M-Y'); + } } } if (!empty($ptr['modseq'])) { + if (!isset($exts['CONDSTORE'])) { + throw new Horde_Imap_Client_Exception('IMAP Server does not support CONDSTORE.', Horde_Imap_Client_Exception::NOSUPPORTIMAPEXT); + } + + $exts_used[] = 'CONDSTORE'; $imap4 = true; - $this->_exts['CONDSTORE'] = true; + $cmds[] = ($ptr['modseq']['not'] ? 'NOT ' : '') . 'MODSEQ ' . (is_null($ptr['modseq']['name']) @@ -241,8 +264,13 @@ class Horde_Imap_Client_Search_Query } if (isset($ptr['prevsearch'])) { + if (!isset($exts['SEARCHRES'])) { + throw new Horde_Imap_Client_Exception('IMAP Server does not support SEARCHRES.', Horde_Imap_Client_Exception::NOSUPPORTIMAPEXT); + } + + $exts_used[] = 'SEARCHRES'; $imap4 = true; - $this->_exts['SEARCHRES'] = true; + $cmds[] = ($ptr['prevsearch'] ? '' : 'NOT ') . '$'; } @@ -280,23 +308,13 @@ class Horde_Imap_Client_Search_Query return array( 'charset' => $this->_charset, + 'exts' => $exts_used, 'imap4' => $imap4, 'query' => trim($query) ); } /** - * Return the list of any IMAP extensions needed to perform the query. - * - * @return array The list of extensions (CAPABILITY responses) needed to - * perform the query. - */ - public function extensionsNeeded() - { - return $this->_exts; - } - - /** * Search for a flag/keywords. * * @param string $name The flag or keyword name. @@ -426,8 +444,8 @@ class Horde_Imap_Client_Search_Query * Search for messages within a date range. Only one internal date and * one RFC 2822 date can be specified per query. * - * @param DateTime $date DateTime or Horde_Date object. - * @param string $range Either: + * @param mixed $date DateTime or Horde_Date object. + * @param string $range Either: *
      * Horde_Imap_Client_Search_Query::DATE_BEFORE,
      * Horde_Imap_Client_Search_Query::DATE_ON, or
@@ -453,8 +471,10 @@ class Horde_Imap_Client_Search_Query
 
     /**
      * Search for messages within a given interval. Only one interval of each
-     * type can be specified per search query. The IMAP server must support
-     * the WITHIN extension (RFC 5032) for this query to be used.
+     * type can be specified per search query. If the IMAP server supports
+     * the WITHIN extension (RFC 5032), it will be used.  Otherwise, the
+     * search query will be dynamically created using IMAP4rev1 search
+     * terms.
      *
      * @param integer $interval  Seconds from the present.
      * @param string $range      Either:
@@ -540,7 +560,7 @@ class Horde_Imap_Client_Search_Query
 
     /**
      * Use the results from the previous SEARCH command. The IMAP server must
-     * support the SEARCHRES extension (RFC 5032) for this query to be used.
+     * support the SEARCHRES extension (RFC 5182) for this query to be used.
      *
      * @param boolean $not  If true, don't match the previous query.
      */
diff --git a/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php b/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php
index 6a66b0298..4508e6eb4 100644
--- a/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php
+++ b/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php
@@ -1484,20 +1484,13 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
      */
     protected function _search($query, $options)
     {
-        // Check for IMAP extensions needed
-        foreach ($query->extensionsNeeded() as $val) {
-            if (!$this->queryCapability($val)) {
-                throw new Horde_Imap_Client_Exception('IMAP Server does not support sorting extension ' . $val . '.', Horde_Imap_Client_Exception::NOSUPPORTIMAPEXT);
-            }
-
-            /* RFC 4551 [3.1] - trying to do a MODSEQ SEARCH on a mailbox that
-             * doesn't support it will return BAD. Catch that here and thrown
-             * an exception. */
-            if (($val == 'CONDSTORE') &&
-                empty($this->_temp['mailbox']['highestmodseq']) &&
-                (strpos($options['_query']['query'], 'MODSEQ ') !== false)) {
-                throw new Horde_Imap_Client_Exception('Mailbox does not support mod-sequences.', Horde_Imap_Client_Exception::MBOXNOMODSEQ);
-            }
+        /* RFC 4551 [3.1] - trying to do a MODSEQ SEARCH on a mailbox that
+         * doesn't support it will return BAD. Catch that here and thrown
+         * an exception. */
+        if (in_array('CONDSTORE', $options['_query']['exts']) &&
+            empty($this->_temp['mailbox']['highestmodseq']) &&
+            (strpos($options['_query']['query'], 'MODSEQ ') !== false)) {
+            throw new Horde_Imap_Client_Exception('Mailbox does not support mod-sequences.', Horde_Imap_Client_Exception::MBOXNOMODSEQ);
         }
 
         $cmd = '';