diff --git a/CHANGELOG b/CHANGELOG index 21eedff5bb5..56d81303b4e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,8 @@ CHANGELOG Roundcube Webmail - Fix PHP Warning: Use of undefined constant IDNA_DEFAULT on systems without php-intl (#6244) - Fix bug where some parts of quota information could have been ignored (#6280) - Fix bug where some escape sequences in html styles could bypass security checks +- Fix bug where some forbidden characters on Cyrus-IMAP were not prevented from use in folder names +- Fix bug where only attachments with the same name would be ignored on zip download (#6301) RELEASE 1.3.6 ------------- diff --git a/plugins/zipdownload/zipdownload.php b/plugins/zipdownload/zipdownload.php index 4759549f995..ada89ca1418 100644 --- a/plugins/zipdownload/zipdownload.php +++ b/plugins/zipdownload/zipdownload.php @@ -18,7 +18,7 @@ class zipdownload extends rcube_plugin private $charset = 'ASCII'; - private $names = []; + private $names = array(); // RFC4155: mbox date format const MBOX_DATE_FORMAT = 'D M d H:i:s Y'; @@ -210,7 +210,7 @@ private function _create_displayname($part) * Adding a number before dot of extension on a name of file with same name on zip * Ext: attach(1).txt on attach filename that has a attach.txt filename on same zip */ - if (isset($this->name[$displayname])) { + if (isset($this->names[$displayname])) { list($filename, $ext) = preg_split("/\.(?=[^\.]*$)/", $displayname); $displayname = $filename . '(' . ($this->names[$displayname]++) . ').' . $ext; $this->names[$displayname] = 1; diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index faf38652667..2faa70b5fbd 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -3727,6 +3727,35 @@ public function folder_sync($folder) } } + /** + * Check if the folder name is valid + * + * @param string $folder Folder name (UTF-8) + * @param string &$char First forbidden character found + * + * @return bool True if the name is valid, False otherwise + */ + public function folder_validate($folder, &$char = null) + { + if (parent::folder_validate($folder, $char)) { + $vendor = $this->get_vendor(); + $regexp = '\\x00-\\x1F\\x7F%*'; + + if ($vendor == 'cyrus') { + // List based on testing Kolab's Cyrus-IMAP 2.5 + $regexp .= '!`@(){}|\\?<;"'; + } + + if (!preg_match("/[$regexp]/", $folder, $m)) { + return true; + } + + $char = $m[0]; + } + + return false; + } + /** * Get message header names for rcube_imap_generic::fetchHeader(s) * diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php index 56703177ca6..faacd4f658e 100644 --- a/program/lib/Roundcube/rcube_storage.php +++ b/program/lib/Roundcube/rcube_storage.php @@ -796,6 +796,26 @@ abstract function folder_sync($folder); */ abstract function mod_folder($folder, $mode = 'out'); + /** + * Check if the folder name is valid + * + * @param string $folder Folder name (UTF-8) + * @param string &$char First forbidden character found + * + * @return bool True if the name is valid, False otherwise + */ + public function folder_validate($folder, &$char = null) + { + $delim = $this->get_hierarchy_delimiter(); + + if (strpos($folder, $delim) !== false) { + $char = $delim; + return false; + } + + return true; + } + /** * Create all folders specified as default */ diff --git a/program/steps/settings/save_folder.inc b/program/steps/settings/save_folder.inc index ed1b09fc122..0b777798ba9 100644 --- a/program/steps/settings/save_folder.inc +++ b/program/steps/settings/save_folder.inc @@ -45,14 +45,8 @@ else if (mb_strlen($name) > 128) { else if ($name[0] == '.' && $RCMAIL->config->get('imap_skip_hidden_folders')) { $error = $RCMAIL->gettext('namedotforbidden'); } -else { - // these characters are problematic e.g. when used in LIST/LSUB - foreach (array($delimiter, '%', '*') as $char) { - if (strpos($name, $char) !== false) { - $error = $RCMAIL->gettext('forbiddencharacter') . " ($char)"; - break; - } - } +else if (!$STORAGE->folder_validate($name, $char)) { + $error = $RCMAIL->gettext('forbiddencharacter') . " ($char)"; } if ($error) {