From 837078cd23d46f7f908f58d3c330cbb67bcf31cc Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 10 Jan 2021 10:30:43 +0100 Subject: [PATCH] Fix mail search error on invalid search_mods definition (#7789) --- CHANGELOG | 1 + config/defaults.inc.php | 3 ++- program/actions/mail/search.php | 47 ++++++++++++++++++++++----------- tests/Actions/Mail/Search.php | 37 ++++++++++++++++++-------- 4 files changed, 61 insertions(+), 27 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee83070a2..d8fd48f3d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -71,6 +71,7 @@ CHANGELOG Roundcube Webmail - Password: Added 'pwned' password strength driver (#7274) - Password: Removed old 'cpanel' driver, 'cpanel_webmail' driver renamed to 'cpanel' (#7780) - Fix bug where it wasn't possible to save Spanish (Latin America) locale preference (#7784) +- Fix mail search error on invalid search_mods definition (#7789) - Fix error when dealing with message/rfc822 attachments using Gmail IMAP (#6854) - Fix ISO-2022-JP-MS encoding issues (#7091) - Fix so messages in threads with no root aren't displayed separately (#4999) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index 48475b2b3..6a76dc1c6 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -1352,9 +1352,10 @@ $config['sig_separator'] = true; // Use MIME encoding (quoted-printable) for 8bit characters in message body $config['force_7bit'] = false; -// Defaults of the search field configuration. +// Default fields configuration for mail search. // The array can contain a per-folder list of header fields which should be considered when searching // The entry with key '*' stands for all folders which do not have a specific list set. +// Supported fields: subject, from, to, cc, bcc, body, text. // Please note that folder names should to be in sync with $config['*_mbox'] options $config['search_mods'] = null; // Example: ['*' => ['subject'=>1, 'from'=>1], 'Sent' => ['subject'=>1, 'to'=>1]]; diff --git a/program/actions/mail/search.php b/program/actions/mail/search.php index 008f6368a..0287d5bd1 100644 --- a/program/actions/mail/search.php +++ b/program/actions/mail/search.php @@ -51,9 +51,7 @@ class rcmail_action_mail_search extends rcmail_action_mail_index $search_request = md5($mbox . $scope . $interval . $filter . $str); // Parse input - list($subject, $srch) = self::search_input($str, $headers, $scope, $mbox); - - $search = isset($srch) ? trim($srch) : trim($str); + list($subject, $search) = self::search_input($str, $headers, $scope, $mbox); // add list filter string $search_str = $filter && $filter != 'ALL' ? $filter : ''; @@ -213,11 +211,22 @@ class rcmail_action_mail_search extends rcmail_action_mail_index return $search . ' ' . $date->format('j-M-Y'); } + /** + * Parse search input. + * + * @param string $str Search string + * @param string $headers Comma-separated list of headers/fields to search in + * @param string $scope Search scope (all | base | sub) + * @param string $mbox Folder name + * + * @return array Search criteria (1st element) and search value (2nd element) + */ public static function search_input($str, $headers, $scope, $mbox) { - $rcmail = rcmail::get_instance(); - $subject = []; - $srch = null; + $rcmail = rcmail::get_instance(); + $subject = []; + $srch = null; + $supported = ['subject', 'from', 'to', 'cc', 'bcc']; // Check the search string for type of search if (preg_match("/^from:.*/i", $str)) { @@ -247,22 +256,30 @@ class rcmail_action_mail_search extends rcmail_action_mail_index else if (strlen(trim($str))) { if ($headers) { foreach (explode(',', $headers) as $header) { - if ($header == 'text') { + switch ($header) { + case 'text': // #1488208: get rid of other headers when searching by "TEXT" $subject = ['text' => 'TEXT']; + break 2; + case 'body': + $subject['body'] = 'BODY'; break; - } - else { - $subject[$header] = ($header != 'body' ? 'HEADER ' : '') . strtoupper($header); + default: + if (in_array_nocase($header, $supported)) { + $subject[$header] = 'HEADER ' . strtoupper($header); + } } } // save search modifiers for the current folder to user prefs - $mkey = $scope == 'all' ? '*' : $mbox; - $search_mods = self::search_mods(); - $search_mods[$mkey] = array_fill_keys(array_keys($subject), 1); + $mkey = $scope == 'all' ? '*' : $mbox; + $search_mods = self::search_mods(); + $search_mods_value = array_fill_keys(array_keys($subject), 1); - $rcmail->user->save_prefs(['search_mods' => $search_mods]); + if (!isset($search_mods[$mkey]) || $search_mods[$mkey] != $search_mods_value) { + $search_mods[$mkey] = $search_mods_value; + $rcmail->user->save_prefs(['search_mods' => $search_mods]); + } } else { // search in subject by default @@ -270,6 +287,6 @@ class rcmail_action_mail_search extends rcmail_action_mail_index } } - return [$subject, $srch]; + return [$subject, isset($srch) ? trim($srch) : trim($str)]; } } diff --git a/tests/Actions/Mail/Search.php b/tests/Actions/Mail/Search.php index 9db62d22f..3f0f7914a 100644 --- a/tests/Actions/Mail/Search.php +++ b/tests/Actions/Mail/Search.php @@ -7,16 +7,6 @@ */ class Actions_Mail_Search extends ActionTestCase { - /** - * Class constructor - */ - function test_class() - { - $object = new rcmail_action_mail_search; - - $this->assertInstanceOf('rcmail_action', $object); - } - /** * Test searching mail (empty result) */ @@ -76,7 +66,32 @@ class Actions_Mail_Search extends ActionTestCase */ function test_search_input() { - $this->markTestIncomplete(); + $output = $this->initOutput(rcmail_action::MODE_AJAX, 'mail', 'search'); + + $result = rcmail_action_mail_search::search_input('', 'subject,from', 'base', 'INBOX'); + + $this->assertSame([], $result[0]); + $this->assertSame('', $result[1]); + + $result = rcmail_action_mail_search::search_input('test', 'subject,from', 'base', 'INBOX'); + + $this->assertSame(['subject' => 'HEADER SUBJECT', 'from' => 'HEADER FROM'], $result[0]); + $this->assertSame('test', $result[1]); + + $result = rcmail_action_mail_search::search_input('test', null, 'base', 'INBOX'); + + $this->assertSame(['subject' => 'HEADER SUBJECT'], $result[0]); + $this->assertSame('test', $result[1]); + + $result = rcmail_action_mail_search::search_input('body:test', 'subject,from', 'base', 'INBOX'); + + $this->assertSame(['body' => 'BODY'], $result[0]); + $this->assertSame('test', $result[1]); + + $result = rcmail_action_mail_search::search_input('test', 'from,invalid entry', 'base', 'INBOX'); + + $this->assertSame(['from' => 'HEADER FROM'], $result[0]); + $this->assertSame('test', $result[1]); } /**