From 59478e06c25303a790a0840ab2ac30662c4ef781 Mon Sep 17 00:00:00 2001 From: Hugues Hiegel Date: Tue, 5 Aug 2014 16:46:22 +0200 Subject: c'est la merde.. --- plugins/managesieve/Changelog | 37 +- plugins/managesieve/config.inc.php.dist | 30 +- plugins/managesieve/lib/Roundcube/rcube_sieve.php | 16 +- .../lib/Roundcube/rcube_sieve_engine.php | 151 +- .../lib/Roundcube/rcube_sieve_script.php | 493 +++-- plugins/managesieve/localization/ar_SA.inc | 33 + plugins/managesieve/localization/az_AZ.inc | 14 +- plugins/managesieve/localization/be_BE.inc | 2 +- plugins/managesieve/localization/bg_BG.inc | 8 +- plugins/managesieve/localization/bs_BA.inc | 2 +- plugins/managesieve/localization/ca_ES.inc | 8 +- plugins/managesieve/localization/cs_CZ.inc | 22 +- plugins/managesieve/localization/cy_GB.inc | 8 +- plugins/managesieve/localization/da_DK.inc | 8 +- plugins/managesieve/localization/de_CH.inc | 2 +- plugins/managesieve/localization/de_DE.inc | 8 +- plugins/managesieve/localization/el_GR.inc | 216 +-- plugins/managesieve/localization/en_GB.inc | 2 +- plugins/managesieve/localization/en_US.inc | 51 +- plugins/managesieve/localization/eo.inc | 2 +- plugins/managesieve/localization/es_AR.inc | 2 +- plugins/managesieve/localization/es_ES.inc | 25 +- plugins/managesieve/localization/et_EE.inc | 29 +- plugins/managesieve/localization/eu_ES.inc | 181 ++ plugins/managesieve/localization/fa_IR.inc | 7 +- plugins/managesieve/localization/fi_FI.inc | 24 +- plugins/managesieve/localization/fr_FR.inc | 26 +- plugins/managesieve/localization/gl_ES.inc | 148 +- plugins/managesieve/localization/he_IL.inc | 7 +- plugins/managesieve/localization/hr_HR.inc | 26 +- plugins/managesieve/localization/hu_HU.inc | 2 +- plugins/managesieve/localization/hy_AM.inc | 2 +- plugins/managesieve/localization/ia.inc | 2 +- plugins/managesieve/localization/id_ID.inc | 2 +- plugins/managesieve/localization/it_IT.inc | 26 +- plugins/managesieve/localization/ja_JP.inc | 2 +- plugins/managesieve/localization/ko_KR.inc | 2 +- plugins/managesieve/localization/lb_LU.inc | 147 -- plugins/managesieve/localization/lt_LT.inc | 10 +- plugins/managesieve/localization/lv_LV.inc | 163 +- plugins/managesieve/localization/ml_IN.inc | 1 + plugins/managesieve/localization/mr_IN.inc | 2 +- plugins/managesieve/localization/nb_NO.inc | 2 +- plugins/managesieve/localization/nl_NL.inc | 2 +- plugins/managesieve/localization/nn_NO.inc | 13 +- plugins/managesieve/localization/pl_PL.inc | 25 +- plugins/managesieve/localization/pt_BR.inc | 21 +- plugins/managesieve/localization/pt_PT.inc | 2 +- plugins/managesieve/localization/ro_RO.inc | 8 +- plugins/managesieve/localization/ru_RU.inc | 21 +- plugins/managesieve/localization/si_LK.inc | 1 + plugins/managesieve/localization/sk_SK.inc | 2 +- plugins/managesieve/localization/sl_SI.inc | 25 +- plugins/managesieve/localization/sv_SE.inc | 2 +- plugins/managesieve/localization/th_TH.inc | 45 + plugins/managesieve/localization/tr_TR.inc | 8 +- plugins/managesieve/localization/uk_UA.inc | 2 +- plugins/managesieve/localization/vi_VN.inc | 17 +- plugins/managesieve/localization/zh_CN.inc | 2 +- plugins/managesieve/localization/zh_TW.inc | 2 +- plugins/managesieve/managesieve.js | 185 +- plugins/managesieve/managesieve.php | 1919 +++++++++++++++++++- plugins/managesieve/package.xml | 18 +- plugins/managesieve/skins/classic/managesieve.css | 103 +- .../managesieve/skins/classic/managesieve_mail.css | 2 +- .../skins/classic/templates/managesieve.html | 6 +- plugins/managesieve/skins/larry/managesieve.css | 116 +- plugins/managesieve/tests/src/parser.out | 4 +- plugins/managesieve/tests/src/parser_enotify_b | 6 +- plugins/managesieve/tests/src/parser_notify_b | 6 +- plugins/managesieve/tests/src/parser_relational | 2 +- plugins/managesieve/tests/src/parser_subaddress | 2 +- 72 files changed, 2968 insertions(+), 1550 deletions(-) create mode 100644 plugins/managesieve/localization/ar_SA.inc create mode 100644 plugins/managesieve/localization/eu_ES.inc create mode 100644 plugins/managesieve/localization/th_TH.inc (limited to 'plugins/managesieve') diff --git a/plugins/managesieve/Changelog b/plugins/managesieve/Changelog index e660ee1ee..159cc3ef9 100644 --- a/plugins/managesieve/Changelog +++ b/plugins/managesieve/Changelog @@ -1,13 +1,4 @@ -* version 7.0 [2013-09-09] ------------------------------------------------------------ -- Add vacation-seconds extension support (RFC 6131) -- Several script parser code improvements -- Support string list arguments in filter form (#1489018) -- Support date, currendate and index tests - RFC5260 (#1488120) -- Split plugin file into two files - Fix handling of &, <, > characters in scripts/filter names (#1489208) -- Support 'keep' action (#1489226) -- Add common headers to header selector (#1489271) * version 6.2 [2013-02-17] ----------------------------------------------------------- @@ -214,18 +205,18 @@ - Added it_IT localization * version 1.1 [2009-05-27] ------------------------------------------------------------ +----------------------------------------------------------- - Added new icons - Added support for headers lists (coma-separated) in rules - Added de_CH localization * version 1.0 [2009-05-21] ------------------------------------------------------------ +----------------------------------------------------------- - Rewritten using plugin API - Added hu_HU localization (Tamas Tevesz) * version beta7 (svn-r2300) [2009-03-01] ------------------------------------------------------------ +----------------------------------------------------------- - Added SquirrelMail script auto-import (Jonathan Ernst) - Added 'vacation' support (Jonathan Ernst & alec) - Added 'stop' support (Jonathan Ernst) @@ -234,47 +225,47 @@ - Small style fixes * version 0.2-stable1 (svn-r2205) [2009-01-03] ------------------------------------------------------------ +----------------------------------------------------------- - Fix moving down filter row - Fixes for compressed js files in stable release package - Created patch for svn version r2205 * version 0.2-stable [2008-12-31] ------------------------------------------------------------ +----------------------------------------------------------- - Added ru_RU, fr_FR, zh_CN translation - Fixes for Roundcube 0.2-stable -* version 0.2-beta [2008-09-21] ------------------------------------------------------------ +* version rc0.2beta [2008-09-21] +----------------------------------------------------------- - Small css fixes for IE - Fixes for Roundcube 0.2-beta * version beta6 [2008-08-08] ------------------------------------------------------------ +----------------------------------------------------------- - Added de_DE translation - Fix for Roundcube r1634 * version beta5 [2008-06-10] ------------------------------------------------------------ +----------------------------------------------------------- - Fixed 'exists' operators - Fixed 'not*' operators for custom headers - Fixed filters deleting * version beta4 [2008-06-09] ------------------------------------------------------------ +----------------------------------------------------------- - Fix for Roundcube r1490 * version beta3 [2008-05-22] ------------------------------------------------------------ +----------------------------------------------------------- - Fixed textarea error class setting - Added pagetitle setting - Added option 'managesieve_replace_delimiter' - Fixed errors on IE (still need some css fixes) - + * version beta2 [2008-05-20] ------------------------------------------------------------ +----------------------------------------------------------- - Use 'if' only for first filter and 'elsif' for the rest * version beta1 [2008-05-15] ------------------------------------------------------------ +----------------------------------------------------------- - Initial version for Roundcube r1388. diff --git a/plugins/managesieve/config.inc.php.dist b/plugins/managesieve/config.inc.php.dist index cb56a0efd..65dbcfc4e 100644 --- a/plugins/managesieve/config.inc.php.dist +++ b/plugins/managesieve/config.inc.php.dist @@ -2,7 +2,7 @@ // managesieve server port. When empty the port will be determined automatically // using getservbyname() function, with 4190 as a fallback. -$config['managesieve_port'] = null; +$rcmail_config['managesieve_port'] = null; // managesieve server address, default is localhost. // Replacement variables supported in host name: @@ -10,58 +10,58 @@ $config['managesieve_port'] = null; // %n - http hostname ($_SERVER['SERVER_NAME']) // %d - domain (http hostname without the first part) // For example %n = mail.domain.tld, %d = domain.tld -$config['managesieve_host'] = 'localhost'; +$rcmail_config['managesieve_host'] = 'localhost'; // authentication method. Can be CRAM-MD5, DIGEST-MD5, PLAIN, LOGIN, EXTERNAL // or none. Optional, defaults to best method supported by server. -$config['managesieve_auth_type'] = null; +$rcmail_config['managesieve_auth_type'] = null; // Optional managesieve authentication identifier to be used as authorization proxy. // Authenticate as a different user but act on behalf of the logged in user. // Works with PLAIN and DIGEST-MD5 auth. -$config['managesieve_auth_cid'] = null; +$rcmail_config['managesieve_auth_cid'] = null; // Optional managesieve authentication password to be used for imap_auth_cid -$config['managesieve_auth_pw'] = null; +$rcmail_config['managesieve_auth_pw'] = null; // use or not TLS for managesieve server connection // Note: tls:// prefix in managesieve_host is also supported -$config['managesieve_usetls'] = false; +$rcmail_config['managesieve_usetls'] = false; // default contents of filters script (eg. default spam filter) -$config['managesieve_default'] = '/etc/dovecot/sieve/global'; +$rcmail_config['managesieve_default'] = '/etc/dovecot/sieve/global'; // The name of the script which will be used when there's no user script -$config['managesieve_script_name'] = 'managesieve'; +$rcmail_config['managesieve_script_name'] = 'managesieve'; // Sieve RFC says that we should use UTF-8 endcoding for mailbox names, // but some implementations does not covert UTF-8 to modified UTF-7. // Defaults to UTF7-IMAP -$config['managesieve_mbox_encoding'] = 'UTF-8'; +$rcmail_config['managesieve_mbox_encoding'] = 'UTF-8'; // I need this because my dovecot (with listescape plugin) uses // ':' delimiter, but creates folders with dot delimiter -$config['managesieve_replace_delimiter'] = ''; +$rcmail_config['managesieve_replace_delimiter'] = ''; // disabled sieve extensions (body, copy, date, editheader, encoded-character, // envelope, environment, ereject, fileinto, ihave, imap4flags, index, // mailbox, mboxmetadata, regex, reject, relational, servermetadata, // spamtest, spamtestplus, subaddress, vacation, variables, virustest, etc. // Note: not all extensions are implemented -$config['managesieve_disabled_extensions'] = array(); +$rcmail_config['managesieve_disabled_extensions'] = array(); // Enables debugging of conversation with sieve server. Logs it into /sieve -$config['managesieve_debug'] = false; +$rcmail_config['managesieve_debug'] = false; // Enables features described in http://wiki.kolab.org/KEP:14 -$config['managesieve_kolab_master'] = false; +$rcmail_config['managesieve_kolab_master'] = false; // Script name extension used for scripts including. Dovecot uses '.sieve', // Cyrus uses '.siv'. Doesn't matter if you have managesieve_kolab_master disabled. -$config['managesieve_filename_extension'] = '.sieve'; +$rcmail_config['managesieve_filename_extension'] = '.sieve'; // List of reserved script names (without extension). // Scripts listed here will be not presented to the user. -$config['managesieve_filename_exceptions'] = array(); +$rcmail_config['managesieve_filename_exceptions'] = array(); ?> diff --git a/plugins/managesieve/lib/Roundcube/rcube_sieve.php b/plugins/managesieve/lib/Roundcube/rcube_sieve.php index 3bd2978da..4f66bf029 100644 --- a/plugins/managesieve/lib/Roundcube/rcube_sieve.php +++ b/plugins/managesieve/lib/Roundcube/rcube_sieve.php @@ -6,18 +6,18 @@ * Copyright (C) 2008-2011, The Roundcube Dev Team * Copyright (C) 2011, Kolab Systems AG * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // Managesieve Protocol: RFC5804 @@ -84,7 +84,7 @@ class rcube_sieve return $this->_set_error(SIEVE_ERROR_LOGIN); } - $this->exts = $this->get_extensions(); + $this->exts = $this->get_extensions(); // disable features by config if (!empty($disabled)) { @@ -379,6 +379,6 @@ class rcube_sieve */ public function debug_handler(&$sieve, $message) { - rcube::write_log('sieve', preg_replace('/\r\n$/', '', $message)); + write_log('sieve', preg_replace('/\r\n$/', '', $message)); } } diff --git a/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php b/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php index e4efef5b3..6c9f8048a 100644 --- a/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php +++ b/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php @@ -535,6 +535,7 @@ class rcube_sieve_engine $act_types = rcube_utils::get_input_value('_action_type', rcube_utils::INPUT_POST, true); $mailboxes = rcube_utils::get_input_value('_action_mailbox', rcube_utils::INPUT_POST, true); $act_targets = rcube_utils::get_input_value('_action_target', rcube_utils::INPUT_POST, true); + $domain_targets = rcube_utils::get_input_value('_action_target_domain', rcube_utils::INPUT_POST); $area_targets = rcube_utils::get_input_value('_action_target_area', rcube_utils::INPUT_POST, true); $reasons = rcube_utils::get_input_value('_action_reason', rcube_utils::INPUT_POST, true); $addresses = rcube_utils::get_input_value('_action_addresses', rcube_utils::INPUT_POST, true); @@ -622,7 +623,21 @@ class rcube_sieve_engine if (!count($target)) { $this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty'); } - else if ($type != 'regex' && $type != 'matches') { + else if (strpos($type, 'count-') === 0) { + foreach ($target as $arg) { + if (preg_match('/[^0-9]/', $arg)) { + $this->errors['tests'][$i]['target'] = $this->plugin->gettext('forbiddenchars'); + } + } + } + else if (strpos($type, 'value-') === 0) { + // Some date/time formats do not support i;ascii-numeric comparator + if ($comparator == 'i;ascii-numeric' && in_array($datepart, array('date', 'time', 'iso8601', 'std11'))) { + $comparator = ''; + } + } + + if (!preg_match('/^(regex|matches|count-)/', $type) && count($target)) { foreach ($target as $arg) { if (!$this->validate_date_part($datepart, $arg)) { $this->errors['tests'][$i]['target'] = $this->plugin->gettext('invaliddateformat'); @@ -668,7 +683,21 @@ class rcube_sieve_engine if (!count($target)) { $this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty'); } - else if ($type != 'regex' && $type != 'matches') { + else if (strpos($type, 'count-') === 0) { + foreach ($target as $arg) { + if (preg_match('/[^0-9]/', $arg)) { + $this->errors['tests'][$i]['target'] = $this->plugin->gettext('forbiddenchars'); + } + } + } + else if (strpos($type, 'value-') === 0) { + // Some date/time formats do not support i;ascii-numeric comparator + if ($comparator == 'i;ascii-numeric' && in_array($datepart, array('date', 'time', 'iso8601', 'std11'))) { + $comparator = ''; + } + } + + if (count($target) && !preg_match('/^(regex|matches|count-)/', $type)) { foreach ($target as $arg) { if (!$this->validate_date_part($datepart, $arg)) { $this->errors['tests'][$i]['target'] = $this->plugin->gettext('invaliddateformat'); @@ -699,7 +728,7 @@ class rcube_sieve_engine } else if (preg_match('/^(value|count)-/', $type)) { foreach ($target as $target_value) { - if (!preg_match('/[0-9]+/', $target_value)) { + if (preg_match('/[^0-9]/', $target_value)) { $this->errors['tests'][$i]['target'] = $this->plugin->gettext('forbiddenchars'); } } @@ -781,7 +810,7 @@ class rcube_sieve_engine } else if (preg_match('/^(value|count)-/', $type)) { foreach ($target as $target_value) { - if (!preg_match('/[0-9]+/', $target_value)) { + if (preg_match('/[^0-9]/', $target_value)) { $this->errors['tests'][$i]['target'] = $this->plugin->gettext('forbiddenchars'); } } @@ -794,9 +823,6 @@ class rcube_sieve_engine } if ($header != 'size' && $comparator) { - if (preg_match('/^(value|count)/', $this->form['tests'][$i]['type'])) - $comparator = 'i;ascii-numeric'; - $this->form['tests'][$i]['comparator'] = $comparator; } @@ -806,16 +832,15 @@ class rcube_sieve_engine $i = 0; // actions - foreach($act_types as $idx => $type) { - $type = $this->strip_value($type); - $target = $this->strip_value($act_targets[$idx]); + foreach ($act_types as $idx => $type) { + $type = $this->strip_value($type); switch ($type) { - case 'fileinto': case 'fileinto_copy': $mailbox = $this->strip_value($mailboxes[$idx], false, false); $this->form['actions'][$i]['target'] = $this->mod_mailbox($mailbox, 'in'); + if ($type == 'fileinto_copy') { $type = 'fileinto'; $this->form['actions'][$i]['copy'] = true; @@ -833,17 +858,31 @@ class rcube_sieve_engine case 'redirect': case 'redirect_copy': + $target = $this->strip_value($act_targets[$idx]); + $domain = $this->strip_value($domain_targets[$idx]); + + // force one of the configured domains + $domains = (array) $this->rc->config->get('managesieve_domains'); + if (!empty($domains) && !empty($target)) { + if (!$domain || !in_array($domain, $domains)) { + $domain = $domains[0]; + } + + $target .= '@' . $domain; + } + $this->form['actions'][$i]['target'] = $target; - if ($this->form['actions'][$i]['target'] == '') + if ($target == '') $this->errors['actions'][$i]['target'] = $this->plugin->gettext('cannotbeempty'); - else if (!rcube_utils::check_email($this->form['actions'][$i]['target'])) - $this->errors['actions'][$i]['target'] = $this->plugin->gettext('noemailwarning'); + else if (!rcube_utils::check_email($target)) + $this->errors['actions'][$i]['target'] = $this->plugin->gettext(!empty($domains) ? 'forbiddenchars' : 'noemailwarning'); if ($type == 'redirect_copy') { $type = 'redirect'; $this->form['actions'][$i]['copy'] = true; } + break; case 'addflag': @@ -864,6 +903,7 @@ class rcube_sieve_engine case 'vacation': $reason = $this->strip_value($reasons[$idx]); $interval_type = $interval_types[$idx] == 'seconds' ? 'seconds' : 'days'; + $this->form['actions'][$i]['reason'] = str_replace("\r\n", "\n", $reason); $this->form['actions'][$i]['subject'] = $subject[$idx]; $this->form['actions'][$i]['addresses'] = array_shift($addresses); @@ -871,7 +911,12 @@ class rcube_sieve_engine // @TODO: vacation :mime, :from, :handle foreach ((array)$this->form['actions'][$i]['addresses'] as $aidx => $address) { - if (!rcube_utils::check_email($address)) { + $this->form['actions'][$i]['addresses'][$aidx] = $address = trim($address); + + if (empty($address)) { + unset($this->form['actions'][$i]['addresses'][$aidx]); + } + else if (!rcube_utils::check_email($address)) { $this->errors['actions'][$i]['addresses'] = $this->plugin->gettext('noemailwarning'); break; } @@ -1354,22 +1399,6 @@ class rcube_sieve_engine $select_op->add(rcube::Q($this->plugin->gettext('valuenotequals')), 'value-ne'); } - // (current)date part select - if (in_array('date', $this->exts) || in_array('currentdate', $this->exts)) { - $date_parts = array('date', 'iso8601', 'std11', 'julian', 'time', - 'year', 'month', 'day', 'hour', 'minute', 'second', 'weekday', 'zone'); - $select_dp = new html_select(array('name' => "_rule_date_part[]", 'id' => 'rule_date_part'.$id, - 'style' => $rule['test'] == 'currentdate' || $rule['test'] == 'date' ? '' : 'display:none', - 'class' => 'datepart_selector', - )); - - foreach ($date_parts as $part) { - $select_dp->add(rcube::Q($this->plugin->gettext($part)), $part); - } - - $tout .= $select_dp->show($rule['test'] == 'currentdate' || $rule['test'] == 'date' ? $rule['part'] : ''); - } - // target(s) input if (in_array($rule['test'], array('header', 'address', 'envelope'))) { $test = ($rule['not'] ? 'not' : '').($rule['type'] ? $rule['type'] : 'is'); @@ -1396,6 +1425,22 @@ class rcube_sieve_engine $target = ''; } + // (current)date part select + if (in_array('date', $this->exts) || in_array('currentdate', $this->exts)) { + $date_parts = array('date', 'iso8601', 'std11', 'julian', 'time', + 'year', 'month', 'day', 'hour', 'minute', 'second', 'weekday', 'zone'); + $select_dp = new html_select(array('name' => "_rule_date_part[]", 'id' => 'rule_date_part'.$id, + 'style' => in_array($rule['test'], array('currentdate', 'date')) && !preg_match('/^(notcount|count)-/', $test) ? '' : 'display:none', + 'class' => 'datepart_selector', + )); + + foreach ($date_parts as $part) { + $select_dp->add(rcube::Q($this->plugin->gettext($part)), $part); + } + + $tout .= $select_dp->show($rule['test'] == 'currentdate' || $rule['test'] == 'date' ? $rule['part'] : ''); + } + $tout .= $select_op->show($test); $tout .= $this->list_input($id, 'rule_target', $target, $rule['test'] != 'size' && $rule['test'] != 'exists', @@ -1436,7 +1481,7 @@ class rcube_sieve_engine $select_type->add(rcube::Q($this->plugin->gettext('detail')), 'detail'); } - $need_mod = $rule['test'] != 'size' && $rule['test'] != 'body'; + $need_mod = !in_array($rule['test'], array('size', 'body', 'date', 'currentdate')); $mout = '\n" : ''; + + return $out; + } + + private function genid() + { + return preg_replace('/[^0-9]/', '', microtime(true)); + } + + private function strip_value($str, $allow_html = false, $trim = true) + { + if (!$allow_html) { + $str = strip_tags($str); + } + + return $trim ? trim($str) : $str; + } + + private function error_class($id, $type, $target, $elem_prefix='') + { + // TODO: tooltips + if (($type == 'test' && ($str = $this->errors['tests'][$id][$target])) || + ($type == 'action' && ($str = $this->errors['actions'][$id][$target])) + ) { + $this->add_tip($elem_prefix.$id, $str, true); + return ' class="error"'; + } + + return ''; + } + + private function add_tip($id, $str, $error=false) + { + if ($error) + $str = html::span('sieve error', $str); + + $this->tips[] = array($id, $str); + } + + private function print_tips() + { + if (empty($this->tips)) + return; + + $script = JS_OBJECT_NAME.'.managesieve_tip_register('.json_encode($this->tips).');'; + $this->rc->output->add_script($script, 'foot'); } /** - * Initializes engine object + * Converts mailbox name from/to UTF7-IMAP from/to internal Sieve encoding + * with delimiter replacement. + * + * @param string $mailbox Mailbox name + * @param string $mode Conversion direction ('in'|'out') + * + * @return string Mailbox name */ - private function get_engine() + private function mod_mailbox($mailbox, $mode = 'out') { - if (!$this->engine) { - $this->load_config(); + $delimiter = $_SESSION['imap_delimiter']; + $replace_delimiter = $this->rc->config->get('managesieve_replace_delimiter'); + $mbox_encoding = $this->rc->config->get('managesieve_mbox_encoding', 'UTF7-IMAP'); + + if ($mode == 'out') { + $mailbox = rcube_charset_convert($mailbox, $mbox_encoding, 'UTF7-IMAP'); + if ($replace_delimiter && $replace_delimiter != $delimiter) + $mailbox = str_replace($replace_delimiter, $delimiter, $mailbox); + } + else { + $mailbox = rcube_charset_convert($mailbox, 'UTF7-IMAP', $mbox_encoding); + if ($replace_delimiter && $replace_delimiter != $delimiter) + $mailbox = str_replace($delimiter, $replace_delimiter, $mailbox); + } + + return $mailbox; + } + + /** + * List sieve scripts + * + * @return array Scripts list + */ + public function list_scripts() + { + if ($this->list !== null) { + return $this->list; + } + + $this->list = $this->sieve->get_scripts(); + + // Handle active script(s) and list of scripts according to Kolab's KEP:14 + if ($this->rc->config->get('managesieve_kolab_master')) { - // Add include path for internal classes - $include_path = $this->home . '/lib' . PATH_SEPARATOR; - $include_path .= ini_get('include_path'); - set_include_path($include_path); + // Skip protected names + foreach ((array)$this->list as $idx => $name) { + $_name = strtoupper($name); + if ($_name == 'MASTER') + $master_script = $name; + else if ($_name == 'MANAGEMENT') + $management_script = $name; + else if($_name == 'USER') + $user_script = $name; + else + continue; - $this->engine = new rcube_sieve_engine($this); + unset($this->list[$idx]); + } + + // get active script(s), read USER script + if ($user_script) { + $extension = $this->rc->config->get('managesieve_filename_extension', '.sieve'); + $filename_regex = '/'.preg_quote($extension, '/').'$/'; + $_SESSION['managesieve_user_script'] = $user_script; + + $this->sieve->load($user_script); + + foreach ($this->sieve->script->as_array() as $rules) { + foreach ($rules['actions'] as $action) { + if ($action['type'] == 'include' && empty($action['global'])) { + $name = preg_replace($filename_regex, '', $action['target']); + $this->active[] = $name; + } + } + } + } + // create USER script if it doesn't exist + else { + $content = "# USER Management Script\n" + ."#\n" + ."# This script includes the various active sieve scripts\n" + ."# it is AUTOMATICALLY GENERATED. DO NOT EDIT MANUALLY!\n" + ."#\n" + ."# For more information, see http://wiki.kolab.org/KEP:14#USER\n" + ."#\n"; + if ($this->sieve->save_script('USER', $content)) { + $_SESSION['managesieve_user_script'] = 'USER'; + if (empty($this->master_file)) + $this->sieve->activate('USER'); + } + } + } + else if (!empty($this->list)) { + // Get active script name + if ($active = $this->sieve->get_active()) { + $this->active = array($active); + } + + // Hide scripts from config + $exceptions = $this->rc->config->get('managesieve_filename_exceptions'); + if (!empty($exceptions)) { + $this->list = array_diff($this->list, (array)$exceptions); + } + } + + return $this->list; + } + + /** + * Removes sieve script + * + * @param string $name Script name + * + * @return bool True on success, False on failure + */ + public function remove_script($name) + { + $result = $this->sieve->remove($name); + + // Kolab's KEP:14 + if ($result && $this->rc->config->get('managesieve_kolab_master')) { + $this->deactivate_script($name); + } + + return $result; + } + + /** + * Activates sieve script + * + * @param string $name Script name + * + * @return bool True on success, False on failure + */ + public function activate_script($name) + { + // Kolab's KEP:14 + if ($this->rc->config->get('managesieve_kolab_master')) { + $extension = $this->rc->config->get('managesieve_filename_extension', '.sieve'); + $user_script = $_SESSION['managesieve_user_script']; + + // if the script is not active... + if ($user_script && ($key = array_search($name, $this->active)) === false) { + // ...rewrite USER file adding appropriate include command + if ($this->sieve->load($user_script)) { + $script = $this->sieve->script->as_array(); + $list = array(); + $regexp = '/' . preg_quote($extension, '/') . '$/'; + + // Create new include entry + $rule = array( + 'actions' => array( + 0 => array( + 'target' => $name.$extension, + 'type' => 'include', + 'personal' => true, + ))); + + // get all active scripts for sorting + foreach ($script as $rid => $rules) { + foreach ($rules['actions'] as $aid => $action) { + if ($action['type'] == 'include' && empty($action['global'])) { + $target = $extension ? preg_replace($regexp, '', $action['target']) : $action['target']; + $list[] = $target; + } + } + } + $list[] = $name; + + // Sort and find current script position + asort($list, SORT_LOCALE_STRING); + $list = array_values($list); + $index = array_search($name, $list); + + // add rule at the end of the script + if ($index === false || $index == count($list)-1) { + $this->sieve->script->add_rule($rule); + } + // add rule at index position + else { + $script2 = array(); + foreach ($script as $rid => $rules) { + if ($rid == $index) { + $script2[] = $rule; + } + $script2[] = $rules; + } + $this->sieve->script->content = $script2; + } + + $result = $this->sieve->save(); + if ($result) { + $this->active[] = $name; + } + } + } + } + else { + $result = $this->sieve->activate($name); + if ($result) + $this->active = array($name); + } + + return $result; + } + + /** + * Deactivates sieve script + * + * @param string $name Script name + * + * @return bool True on success, False on failure + */ + public function deactivate_script($name) + { + // Kolab's KEP:14 + if ($this->rc->config->get('managesieve_kolab_master')) { + $extension = $this->rc->config->get('managesieve_filename_extension', '.sieve'); + $user_script = $_SESSION['managesieve_user_script']; + + // if the script is active... + if ($user_script && ($key = array_search($name, $this->active)) !== false) { + // ...rewrite USER file removing appropriate include command + if ($this->sieve->load($user_script)) { + $script = $this->sieve->script->as_array(); + $name = $name.$extension; + + foreach ($script as $rid => $rules) { + foreach ($rules['actions'] as $aid => $action) { + if ($action['type'] == 'include' && empty($action['global']) + && $action['target'] == $name + ) { + break 2; + } + } + } + + // Entry found + if ($rid < count($script)) { + $this->sieve->script->delete_rule($rid); + $result = $this->sieve->save(); + if ($result) { + unset($this->active[$key]); + } + } + } + } + } + else { + $result = $this->sieve->deactivate(); + if ($result) + $this->active = array(); + } + + return $result; + } + + /** + * Saves current script (adding some variables) + */ + public function save_script($name = null) + { + // Kolab's KEP:14 + if ($this->rc->config->get('managesieve_kolab_master')) { + $this->sieve->script->set_var('EDITOR', self::PROGNAME); + $this->sieve->script->set_var('EDITOR_VERSION', self::VERSION); + } + + return $this->sieve->save($name); + } + + /** + * Returns list of rules from the current script + * + * @return array List of rules + */ + public function list_rules() + { + $result = array(); + $i = 1; + + foreach ($this->script as $idx => $filter) { + if ($filter['type'] != 'if') { + continue; + } + $fname = $filter['name'] ? $filter['name'] : "#$i"; + $result[] = array( + 'id' => $idx, + 'name' => $fname, + 'class' => $filter['disabled'] ? 'disabled' : '', + ); + $i++; } - return $this->engine; + return $result; } } diff --git a/plugins/managesieve/package.xml b/plugins/managesieve/package.xml index 6ae53c250..a0c38b82d 100644 --- a/plugins/managesieve/package.xml +++ b/plugins/managesieve/package.xml @@ -17,16 +17,16 @@ alec@alec.pl yes - 2013-09-09 + 2013-02-17 - 7.0 - 7.0 + 6.2 + 6.0 stable stable - GNU GPLv3+ + GNU GPLv2 - @@ -38,10 +38,6 @@ - - - - @@ -97,7 +93,6 @@ - @@ -108,8 +103,11 @@ - + + + + diff --git a/plugins/managesieve/skins/classic/managesieve.css b/plugins/managesieve/skins/classic/managesieve.css index 59d88cb46..b7c6f5d06 100644 --- a/plugins/managesieve/skins/classic/managesieve.css +++ b/plugins/managesieve/skins/classic/managesieve.css @@ -171,12 +171,12 @@ td.advbutton a td.advbutton a.show { - background: url(images/down_small.gif) center no-repeat; + background: url(images/down_small.gif?v=8629.106) center no-repeat; } td.advbutton a.hide { - background: url(images/up_small.gif) center no-repeat; + background: url(images/up_small.gif?v=c56c.106) center no-repeat; } td.rowbuttons @@ -201,30 +201,11 @@ td.rowtargets padding-top: 2px; } -td.rowtargets > div -{ - vertical-align: top; - margin-top: 2px; -} - td.rowtargets div.adv { padding-top: 3px; } -td.rowtargets div.adv span.label -{ - display: inline-block; - padding-right: 10px; - min-width: 65px; -} - -html.mozilla #filter-form select -{ - padding-top: 3px; - padding-bottom: 3px; -} - input.disabled, input.disabled:hover { color: #999999; @@ -245,7 +226,6 @@ input.radio select.operator_selector { width: 200px; - vertical-align: top; } td.rowtargets span, @@ -256,11 +236,6 @@ span.label white-space: nowrap; } -td.rowtargets label -{ - color: black; -} - #footer { padding-top: 5px; @@ -299,7 +274,7 @@ span.sieve.error a.button.add { - background: url(images/add.png) no-repeat; + background: url(images/add.png?v=a165.280) no-repeat; width: 30px; height: 20px; margin-right: 4px; @@ -308,7 +283,7 @@ a.button.add a.button.del { - background: url(images/del.png) no-repeat; + background: url(images/del.png?v=3c27.247) no-repeat; width: 30px; height: 20px; display: inline-block; @@ -326,78 +301,8 @@ a.button.disabled #filter-form textarea { font-size: 11px; - vertical-align: middle; } -/* smart multi-row input field */ -.listarea -{ - border: 1px solid #666; - margin: 0; - padding: 1px; - display: inline-block; - max-height: 67px; - overflow-y: auto; -} - -td.rowtargets > span.listarea -{ - vertical-align: top; - margin-top: 2px; -} - -.listelement -{ - display: block; - white-space: nowrap; - background-color: #fff; - border-top: 1px solid #e2e2e2; - height: 16px; - padding: 0; - margin: 0; - overflow: hidden; - line-height: 16px; -} - -.listarea.error .listelement -{ - background-color: #FFFFC4; -} - -.listelement:first-child -{ - border-top: none; -} - -#filter-form .listelement input -{ - border: none; - border-radius: 0; - box-shadow: none; - outline: none; - vertical-align: top; - height: 16px; - padding-top: 0; - padding-bottom: 0; - line-height: 16px; - background-color: transparent; -} - -.listelement input:focus -{ - box-shadow: none; -} - -.listelement .reset -{ - display: inline-block; - width: 16px; - height: 16px; - background: url(images/erase.png) -1px 0 no-repeat #eee; - cursor: pointer; -} - - /* fixes for popup window */ body.iframe.mail diff --git a/plugins/managesieve/skins/classic/managesieve_mail.css b/plugins/managesieve/skins/classic/managesieve_mail.css index 87a11cc92..73cc47ba2 100644 --- a/plugins/managesieve/skins/classic/managesieve_mail.css +++ b/plugins/managesieve/skins/classic/managesieve_mail.css @@ -1,5 +1,5 @@ #messagemenu li a.filterlink { - background-image: url(images/filter.png); + background-image: url(images/filter.png?v=b0fe.547); background-position: 7px 0; } diff --git a/plugins/managesieve/skins/classic/templates/managesieve.html b/plugins/managesieve/skins/classic/templates/managesieve.html index 869e3ac36..71eebe105 100644 --- a/plugins/managesieve/skins/classic/templates/managesieve.html +++ b/plugins/managesieve/skins/classic/templates/managesieve.html @@ -19,7 +19,7 @@ - + @@ -83,9 +83,5 @@ - - diff --git a/plugins/managesieve/skins/larry/managesieve.css b/plugins/managesieve/skins/larry/managesieve.css index 2144fe13f..bf5910edc 100644 --- a/plugins/managesieve/skins/larry/managesieve.css +++ b/plugins/managesieve/skins/larry/managesieve.css @@ -43,7 +43,7 @@ #filtersetslist { width: 100%; - table-layout: fixed; + table-layout: fixed; } #filterslist tbody td, @@ -145,12 +145,12 @@ td.advbutton a td.advbutton a.show { - background: url(images/down_small.gif) center no-repeat; + background: url(images/down_small.gif?v=8629.106) center no-repeat; } td.advbutton a.hide { - background: url(images/up_small.gif) center no-repeat; + background: url(images/up_small.gif?v=c56c.106) center no-repeat; } td.rowbuttons @@ -175,23 +175,9 @@ td.rowtargets padding-top: 2px; } -td.rowtargets > div -{ - vertical-align: top; - margin-top: 2px; -} - td.rowtargets div.adv { padding-top: 3px; - font-size: 10px; -} - -td.rowtargets div.adv span.label -{ - display: inline-block; - padding-right: 5px; - min-width: 70px; } input.disabled, input.disabled:hover @@ -211,15 +197,9 @@ input.radio margin-top: 0; } -input.radio -{ - vertical-align: middle; -} - select.operator_selector { width: 200px; - vertical-align: top; } td.rowtargets span, @@ -230,11 +210,6 @@ span.label white-space: nowrap; } -td.rowtargets label -{ - color: black; -} - #footer { padding-top: 5px; @@ -277,7 +252,7 @@ a.button a.button.add { - background: url(images/add.png) no-repeat; + background: url(images/add.png?v=a165.280) no-repeat; width: 30px; height: 20px; margin-right: 4px; @@ -286,7 +261,7 @@ a.button.add a.button.del { - background: url(images/del.png) no-repeat; + background: url(images/del.png?v=3c27.247) no-repeat; width: 30px; height: 20px; display: inline-block; @@ -305,13 +280,6 @@ a.button.disabled { font-size: 11px; padding: 1px; - vertical-align: middle; -} - -html.mozilla #filter-form select -{ - padding-top: 3px; - padding-bottom: 3px; } /* revert larry style button */ @@ -328,80 +296,6 @@ fieldset border-radius: 4px; } -/* smart multi-row input field */ -.listarea -{ - border: 1px solid #B2B2B2; - border-radius: 4px; - box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); - -moz-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); - -webkit-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); - -o-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1); - margin: 0; - padding: 2px; - display: inline-block; - max-height: 59px; - overflow-y: auto; -} - -td.rowtargets > span.listarea -{ - vertical-align: top; - margin-top: 2px; -} - -.listelement -{ - display: block; - white-space: nowrap; - background-color: #fff; - border-top: 1px solid #e2e2e2; - height: 14px; - padding: 0; - margin: 0; - overflow: hidden; - line-height: 14px; -} - -.listarea.error .listelement -{ - background-color: #FFFFC4; -} - -.listelement:first-child -{ - border-top: none; -} - -#filter-form .listelement input -{ - border: none; - border-radius: 0; - box-shadow: none; - outline: none; - vertical-align: top; - height: 14px; - padding-top: 0; - padding-bottom: 0; - line-height: 14px; - background-color: transparent; -} - -.listelement input:focus -{ - box-shadow: none; -} - -.listelement .reset -{ - display: inline-block; - width: 16px; - height: 16px; - background: url(images/erase.png) -1px -1px no-repeat #eee; - cursor: pointer; -} - - /* fixes for popup window */ body.iframe.mail diff --git a/plugins/managesieve/tests/src/parser.out b/plugins/managesieve/tests/src/parser.out index cb0bad5e7..385c8890d 100644 --- a/plugins/managesieve/tests/src/parser.out +++ b/plugins/managesieve/tests/src/parser.out @@ -1,4 +1,4 @@ -require ["envelope","fileinto","reject"]; +require ["fileinto","reject","envelope"]; # rule:[spam] if header :contains "X-DSPAM-Result" "Spam" { @@ -39,7 +39,7 @@ if true } fileinto "Test"; # rule:[address test] -if address :is "From" "nagios@domain.tld" +if address :all :is "From" "nagios@domain.tld" { fileinto "domain.tld"; stop; diff --git a/plugins/managesieve/tests/src/parser_enotify_b b/plugins/managesieve/tests/src/parser_enotify_b index a3011bac2..8854658f4 100644 --- a/plugins/managesieve/tests/src/parser_enotify_b +++ b/plugins/managesieve/tests/src/parser_enotify_b @@ -1,6 +1,6 @@ -require ["enotify","envelope","variables"]; +require ["envelope","variables","enotify"]; # rule:[from] -if envelope :matches "from" "*" +if envelope :all :matches "from" "*" { set "env_from" " [really: ${1}]"; } @@ -10,7 +10,7 @@ if header :matches "Subject" "*" set "subject" "${1}"; } # rule:[from notify] -if address :matches "from" "*" +if address :all :matches "from" "*" { set "from_addr" "${1}"; notify :message "${from_addr}${env_from}: ${subject}" "mailto:alm@example.com"; diff --git a/plugins/managesieve/tests/src/parser_notify_b b/plugins/managesieve/tests/src/parser_notify_b index ab90ed48c..cf80a9701 100644 --- a/plugins/managesieve/tests/src/parser_notify_b +++ b/plugins/managesieve/tests/src/parser_notify_b @@ -1,6 +1,6 @@ -require ["envelope","notify","variables"]; +require ["envelope","variables","notify"]; # rule:[from] -if envelope :matches "from" "*" +if envelope :all :matches "from" "*" { set "env_from" " [really: ${1}]"; } @@ -10,7 +10,7 @@ if header :matches "Subject" "*" set "subject" "${1}"; } # rule:[from notify] -if address :matches "from" "*" +if address :all :matches "from" "*" { set "from_addr" "${1}"; notify :message "${from_addr}${env_from}: ${subject}" :method "sms:1234567890"; diff --git a/plugins/managesieve/tests/src/parser_relational b/plugins/managesieve/tests/src/parser_relational index 92c5e1a8e..0a92fde54 100644 --- a/plugins/managesieve/tests/src/parser_relational +++ b/plugins/managesieve/tests/src/parser_relational @@ -1,4 +1,4 @@ -require ["comparator-i;ascii-numeric","relational"]; +require ["relational","comparator-i;ascii-numeric"]; # rule:[redirect] if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-score" "14" { diff --git a/plugins/managesieve/tests/src/parser_subaddress b/plugins/managesieve/tests/src/parser_subaddress index e44555096..f106b796e 100644 --- a/plugins/managesieve/tests/src/parser_subaddress +++ b/plugins/managesieve/tests/src/parser_subaddress @@ -1,4 +1,4 @@ -require ["envelope","fileinto","subaddress"]; +require ["envelope","subaddress","fileinto"]; if envelope :user "To" "postmaster" { fileinto "postmaster"; -- cgit v1.2.3