From a04a74fec4b5e13e8464f1f3c9071fa0b56a13eb Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Wed, 12 Sep 2012 03:59:10 -0400
Subject: [PATCH] Improvements in building criteria string for IMAP SEARCH

---
 program/include/rcube_shared.inc |   15 +++++++++++++++
 program/steps/mail/search.inc    |    2 +-
 program/include/rcube_imap.php   |    8 +++++++-
 tests/Framework/Shared.php       |   28 ++++++++++++++++++++++++++++
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 66b5c4b..0b2f84d 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -1434,6 +1434,12 @@
             $criteria = 'UNDELETED '.$criteria;
         }
 
+        // unset CHARSET if criteria string is ASCII, this way
+        // SEARCH won't be re-sent after "unsupported charset" response
+        if ($charset && $charset != 'US-ASCII' && is_ascii($criteria)) {
+            $charset = 'US-ASCII';
+        }
+
         if ($this->threading) {
             $threads = $this->conn->thread($folder, $this->threading, $criteria, true, $charset);
 
@@ -1465,7 +1471,7 @@
         }
 
         $messages = $this->conn->search($folder,
-            ($charset ? "CHARSET $charset " : '') . $criteria, true);
+            ($charset && $charset != 'US-ASCII' ? "CHARSET $charset " : '') . $criteria, true);
 
         // Error, try with US-ASCII (some servers may support only US-ASCII)
         if ($messages->is_error() && $charset && $charset != 'US-ASCII') {
diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc
index c15305c..4577c6d 100644
--- a/program/include/rcube_shared.inc
+++ b/program/include/rcube_shared.inc
@@ -255,6 +255,21 @@
 
 
 /**
+ * Check if a string contains only ascii characters
+ *
+ * @param string $str           String to check
+ * @param bool   $control_chars Includes control characters
+ *
+ * @return bool
+ */
+function is_ascii($str, $control_chars = true)
+{
+    $regexp = $control_chars ? '/[^\x00-\x7F]/' : '/[^\x20-\x7E]/';
+    return preg_match($regexp, $str) ? false : true;
+}
+
+
+/**
  * Remove single and double quotes from a given string
  *
  * @param string Input value
diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc
index 6706809..db5424b 100644
--- a/program/steps/mail/search.inc
+++ b/program/steps/mail/search.inc
@@ -100,7 +100,7 @@
 if (!empty($subject)) {
   $search_str .= str_repeat(' OR', count($subject)-1);
   foreach ($subject as $sub)
-    $search_str .= sprintf(" %s {%d}\r\n%s", $sub, strlen($search), $search);
+    $search_str .= ' ' . $sub . ' ' . rcube_imap_generic::escape($search);
 }
 
 $search_str  = trim($search_str);
diff --git a/tests/Framework/Shared.php b/tests/Framework/Shared.php
index 99ef829..0394cd0 100644
--- a/tests/Framework/Shared.php
+++ b/tests/Framework/Shared.php
@@ -201,4 +201,32 @@
 
     }
 
+    /**
+     * rcube_shared.inc: is_ascii()
+     */
+    function test_is_ascii()
+    {
+        $result = is_ascii("0123456789");
+        $this->assertTrue($result, "Valid ASCII (numbers)");
+
+        $result = is_ascii("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
+        $this->assertTrue($result, "Valid ASCII (letters)");
+
+        $result = is_ascii(" !\"#\$%&'()*+,-./:;<=>?@[\\^_`{|}~");
+        $this->assertTrue($result, "Valid ASCII (special characters)");
+
+        $result = is_ascii("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+            ."\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F");
+        $this->assertTrue($result, "Valid ASCII (control characters)");
+
+        $result = is_ascii("\n", false);
+        $this->assertFalse($result, "Valid ASCII (control characters)");
+
+        $result = is_ascii("ż");
+        $this->assertFalse($result, "Invalid ASCII (UTF-8 character)");
+
+        $result = is_ascii("ż", false);
+        $this->assertFalse($result, "Invalid ASCII (UTF-8 character [2])");
+    }
+
 }

--
Gitblit v1.9.1