From 8f66aa06f58ba2c9f99541a191ee4bcaa98500b3 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 9 Sep 2012 16:50:14 +0200 Subject: Fix encoding vCard file when contains PHOTO;ENCODING=b (#1488683) --- tests/Framework/VCard.php | 14 ++++++++++++++ tests/src/photo.vcf | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tests/src/photo.vcf (limited to 'tests') diff --git a/tests/Framework/VCard.php b/tests/Framework/VCard.php index a830c2cbc..56ca9d721 100644 --- a/tests/Framework/VCard.php +++ b/tests/Framework/VCard.php @@ -49,6 +49,20 @@ class Framework_VCard extends PHPUnit_Framework_TestCase $this->assertEquals("Iksiñski", $vcards2[0]->surname, "Detect charset in encoded values"); } + function test_import_photo_encoding() + { + $input = file_get_contents($this->_srcpath('photo.vcf')); + + $vcards = rcube_vcard::import($input); + $vcard = $vcards[0]->get_assoc(); + + $this->assertCount(1, $vcards, "Detected 1 vcard"); + + // ENCODING=b case (#1488683) + $this->assertEquals("/9j/4AAQSkZJRgABAQA", substr(base64_encode($vcard['photo']), 0, 19), "Photo decoding"); + $this->assertEquals("Müller", $vcard['surname'], "Unicode characters"); + } + function test_encodings() { $input = file_get_contents($this->_srcpath('utf-16_sample.vcf')); diff --git a/tests/src/photo.vcf b/tests/src/photo.vcf new file mode 100644 index 000000000..c3a805009 --- /dev/null +++ b/tests/src/photo.vcf @@ -0,0 +1,45 @@ +BEGIN:VCARD +VERSION:3.0 +N:Müller;Jörg;;; +FN:Apple Computer AG +ORG:Apple Computer AG; +PHOTO;ENCODING=b: + /9j/4AAQSkZJRgABAQAAAQABAAD/7QAcUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAAD/2wBDAAEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQH/wAARCAAwADADAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAA + AAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEI + I0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlq + c3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW + 19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL + /8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLR + ChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOE + hYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn + 6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/igAoAKAPmH43ftT+CfgzqNt4bNjeeLvGV2IHXw7 + pVxDbLZx3LBbdtU1GVLhbN7jIMFvHa3VzIpWRoY4mWQ9dDCTrrmuoQ/mavfvZXV7dW2jkr4ynQfL + Zzn1inZL1lZ6+ST87H0lp1zLe6fY3k9s1nNd2dtczWjv5j2ss8KSyWzybU3tA7mJn2JuKk7Vzgcr + Vm1e9m1fvrv8zqi+aKbVm0nbtdXt8i5SGFAHHeOfH3hH4b6DP4k8Z61a6JpUBCCW4LPNdTsCUtbK + 1iD3F5dSYO2C3jd8AuwVFZhdOnOrLlhFyf4Lzb6IzqVYUo81SSiundvslu3/AEz5i0n9u74Fanqo + 064m8UaNbvII49X1TRUGnnORvmFje3t5BGTjDtatwcyCPBrreArpX9xvqlJ3/FJP7zlWYUHKzVRL + +ZxVvnaTa+4+QLvVPgJ4U+LutfFXx78QJfi3q954iuvEOieHvBmkyzaVbO1x5ulPruq6pLawTvp1 + uLdIrK08xFmgXzl2oI67LV50o0qdP2K5VGUptKXnyxi29XfVtb6HDehGtKpUm6zcnNKCfK9brnlK + 3pZJ37pH3/8ACj9qb4T/ABd1FdD0TUr3SPETozwaJ4ht47C5vQgLONOnjnuLS8dVBYwJOt1tDMIN + oLV51XCVqK5pJSj1cW3b1uk1vvqvM9Kji6VZ8qbjJ7KVlf0abTf4n0dXMdQUAfhf+2J8UNW8ffFz + W9Cnlki0XwDqOp+GdNsFdhB9qsr6a31DUDHu2tcXbwojSEbhFCka4Uc+9hKUadGMl8VRKcn11V0v + RJng4urKpWkntTlKCXTRtN+re58n11HKFAH6PfsGfBvQfEl3rHxR8Q2y38vhrUrfT/DNpIT5FvqY + iF1carIgI8ye2R4Y7RXykbySTbS6xlfOx9aUVGlF2503N+W1vnrc9HAUYzlKrJX5GuVf3t7+dvu3 + vc/WKvIPXCgD8FP2s/BF/wCC/jd4wlu0It/Fmp6h4usJf4JINZ1G7ndVbu0UpZZBztY446V9BhZq + dCnZ/DFQfrFJHz+Kg4V6l/tSc15qTb/rzPmqug5woA++v2J/j74d+HN9rHgLxndrpmjeJr62vtJ1 + mbP2Sw1dY/s0ltfOM+Rb30Yh8u5ZTHFPEFlZEk3Dgx2HlVUZw1lBNOPVp9vNa6X22137sFiI0ZSh + N2jNpqXSLSe/k+/R+p+w1eMe0FAHxz+2P8DLr4r+CIPEPhy2Nx4y8FJdXVnaxrmfWdGlAk1DSosK + WkuozEt5p8fHmTLNADuuQR24KuqU3GTtCpbXtLo32T2b9GcWNw7qwU4q84X06yi9Wl531XfXyPxK + ME4nNsYZRciUwG3MbicTh/LMJix5glD/ACGPbv3/AC4zxXtniFvUNJ1XSmjXVNM1DTWmUvCuoWVz + ZtKgxloxcRxmRRkZZcgZGTzSTT2afo7hqtz6w/ZB+BV78UPHtl4n1eykHgfwdewajfXE0bCDVtVt + mE+n6PAzAJOBOkdxqAUssdsnlSDNwoPLi66pU3FP95NNJdk95P06d35XOvCUHWqJtfu4NOT7vdR8 + 7vfsvVH7gV4R7oUAFAHKReA/A8Gsy+IofBnhSHxBO7ST67F4d0iPWZnb7zy6mlmL2R2/iZ5yT3NX + 7Spbl9pPl/l55W+69iPZUubm9nDmvfm5I81+97XuX9a8MeGvEtsLLxF4e0PX7MMGFprWk2Gq2wZe + jCC+t54tw7HZkdqUZzg7wlKL7xk4v700OUIT0lCMl2lFS/NMuaXpOlaHZQ6Zoumafo+nW4It9P0u + yttPsoATkiG1tI4oIgTyQkagnmk5Sk7ybk+7bb+96jjGMVaMVFdopJfcjQpDP//Z +X-ABShowAs:COMPANY +X-ABUID:2E4CB084-4767-4C85-BBCA-805B1DCB1C8E\:ABPerson +END:VCARD -- cgit v1.2.3 From a04a74fec4b5e13e8464f1f3c9071fa0b56a13eb Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 12 Sep 2012 09:59:10 +0200 Subject: Improvements in building criteria string for IMAP SEARCH --- program/include/rcube_imap.php | 8 +++++++- program/include/rcube_shared.inc | 15 +++++++++++++++ program/steps/mail/search.inc | 2 +- tests/Framework/Shared.php | 28 ++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index 66b5c4bd6..0b2f84d4f 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -1434,6 +1434,12 @@ class rcube_imap extends rcube_storage $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 @@ class rcube_imap extends rcube_storage } $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 c15305c08..4577c6df5 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -254,6 +254,21 @@ function asciiwords($str, $css_id = false, $replace_with = '') } +/** + * 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 * diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc index 670680959..db5424b3b 100644 --- a/program/steps/mail/search.inc +++ b/program/steps/mail/search.inc @@ -100,7 +100,7 @@ $search = isset($srch) ? trim($srch) : trim($str); 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 99ef829da..0394cd025 100644 --- a/tests/Framework/Shared.php +++ b/tests/Framework/Shared.php @@ -201,4 +201,32 @@ class Framework_Shared extends PHPUnit_Framework_TestCase } + /** + * 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])"); + } + } -- cgit v1.2.3 From b2e5178b105cfc224715329716bdbdce94976cd3 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 13 Sep 2012 11:34:22 +0200 Subject: Added tests for rcube_charset class --- tests/Framework/Charset.php | 140 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/Framework/Charset.php b/tests/Framework/Charset.php index 9e3fad4d3..1fd1654dc 100644 --- a/tests/Framework/Charset.php +++ b/tests/Framework/Charset.php @@ -14,15 +14,149 @@ class Framework_Charset extends PHPUnit_Framework_TestCase function data_clean() { return array( - array('', '', 'Empty string'), + array('', ''), + array("\xC1", ''), ); } /** * @dataProvider data_clean */ - function test_clean($input, $output, $title) + function test_clean($input, $output) { - $this->assertEquals(rcube_charset::clean($input), $output, $title); + $this->assertEquals($output, rcube_charset::clean($input)); } + + /** + * Data for test_parse_charset() + */ + function data_parse_charset() + { + return array( + array('UTF8', 'UTF-8'), + array('WIN1250', 'WINDOWS-1250'), + ); + } + + /** + * @dataProvider data_parse_charset + */ + function test_parse_charset($input, $output) + { + $this->assertEquals($output, rcube_charset::parse_charset($input)); + } + + /** + * Data for test_convert() + */ + function data_convert() + { + return array( + array('ö', 'ö', 'UTF-8', 'UTF-8'), + array('ö', '', 'UTF-8', 'US-ASCII'), + array('aż', 'a', 'UTF-8', 'US-ASCII'), + array('&BCAEMARBBEEESwQ7BDoEOA-', 'Рассылки', 'UTF7-IMAP', 'UTF-8'), + array('Рассылки', '&BCAEMARBBEEESwQ7BDoEOA-', 'UTF-8', 'UTF7-IMAP'), + ); + } + + /** + * @dataProvider data_convert + */ + function test_convert($input, $output, $from, $to) + { + $this->assertEquals($output, rcube_charset::convert($input, $from, $to)); + } + + /** + * Data for test_utf7_to_utf8() + */ + function data_utf7_to_utf8() + { + return array( + array('+BCAEMARBBEEESwQ7BDoEOA-', 'Рассылки'), + ); + } + + /** + * @dataProvider data_utf7_to_utf8 + */ + function test_utf7_to_utf8($input, $output) + { + $this->assertEquals($output, rcube_charset::utf7_to_utf8($input)); + } + + /** + * Data for test_utf7imap_to_utf8() + */ + function data_utf7imap_to_utf8() + { + return array( + array('&BCAEMARBBEEESwQ7BDoEOA-', 'Рассылки'), + ); + } + + /** + * @dataProvider data_utf7imap_to_utf8 + */ + function test_utf7imap_to_utf8($input, $output) + { + $this->assertEquals($output, rcube_charset::utf7imap_to_utf8($input)); + } + + /** + * Data for test_utf8_to_utf7imap() + */ + function data_utf8_to_utf7imap() + { + return array( + array('Рассылки', '&BCAEMARBBEEESwQ7BDoEOA-'), + ); + } + + /** + * @dataProvider data_utf8_to_utf7imap + */ + function test_utf8_to_utf7imap($input, $output) + { + $this->assertEquals($output, rcube_charset::utf8_to_utf7imap($input)); + } + + /** + * Data for test_utf16_to_utf8() + */ + function data_utf16_to_utf8() + { + return array( + array(base64_decode('BCAEMARBBEEESwQ7BDoEOA=='), 'Рассылки'), + ); + } + + /** + * @dataProvider data_utf16_to_utf8 + */ + function test_utf16_to_utf8($input, $output) + { + $this->assertEquals($output, rcube_charset::utf16_to_utf8($input)); + } + + /** + * Data for test_detect() + */ + function data_detect() + { + return array( + array('', '', 'UTF-8'), + array('a', 'UTF-8', 'UTF-8'), + ); + } + + /** + * @dataProvider data_detect + */ + function test_detect($input, $fallback, $output) + { + $this->assertEquals($output, rcube_charset::detect($input, $fallback)); + } + } -- cgit v1.2.3