Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2571594
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
160 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/plugins/managesieve/Changelog b/plugins/managesieve/Changelog
index 8538f107f..f74e4f350 100644
--- a/plugins/managesieve/Changelog
+++ b/plugins/managesieve/Changelog
@@ -1,397 +1,399 @@
+* version 9.3 [2019-04-21]
+-----------------------------------------------------------
- Use RFC-compliant line endings, CRLF instead of LF (#6686)
- Fix bug where global includes were requested for vacation (#6716)
- Fix so "Create filter" option does not show up when Filters menu is disabled (#6723)
* version 9.2 [2018-11-08]
-----------------------------------------------------------
- Added support for 'editheader' extension - RFC5293 (#5954)
- Fix bug where show_real_foldernames setting wasn't respected (#6422)
- Fix bug where custom header or variable could be lost on form submission (#6594)
* version 9.1 [2018-05-19]
-----------------------------------------------------------
- Added GSSAPI support (#5779)
- Added option managesieve_default_headers
- Added option managesieve_forward to enable settings dialog for simple forwarding (#6021)
- Support filter action with custom IMAP flags (#6011)
- Support 'mime' extension tests - RFC5703 (#5832)
- Support enabling the plugin for specified hosts only (#6292)
- Support Elastic skin
- Fix bug where text: syntax was forced for strings longer than 1024 characters (#6143)
- Fix missing Save button in Edit Filter Set page of Classic skin (#6154)
- Rename "Vacation" to "Out of Office"
* version 9.0 [2017-10-02]
-----------------------------------------------------------
- Fix parsing dot-staffed lines in multiline text (#5838)
- Fix AM/PM suffix in vacation time selectors
- Fix bug where 'exists' operator was reset to 'contains' (#5899)
- Add ability to disable filter sets and other actions (#5496, #5898)
* version 8.9 [2017-05-22]
-----------------------------------------------------------
- Fix handling of scripts with nested rules (#5540)
- Fix possible defect in handling \r\n in scripts (#5685)
- Performance: Skip redundant LISTSCRIPTS command
* version 8.8 [2016-11-27]
-----------------------------------------------------------
- Fix parsing of vacation date-time with non-default date_format (#5372)
- Fix regression where js error is thrown if server does not support 'duplicate' extension
- Add option to automatically set vacation :from address (#5428)
- Support per-host managesieve_conn_options (#5136)
- Added (optional) RAW script editor (#5414)
* version 8.7 [2016-07-19]
-----------------------------------------------------------
- Support 'string' test from variables extension [RFC 5229] (#5248)
- Support 'duplicate' extension [RFC 7352]
- Unhide advanced rule controls if there are inputs with errors
- Display warning message when filter form contains errors
* version 8.6 [2016-04-06]
-----------------------------------------------------------
- Refactored script parser to be 100x faster (on big scripts)
* version 8.5 [2015-11-15]
-----------------------------------------------------------
- Add support for :from parameter in vacation action (patch from Michele Locati)
* version 8.4 [2015-04-20]
-----------------------------------------------------------
- Add option to prepopulate vacation addresses on form init (#1490030)
- Add option to define default vacation interval
- Fix missing position indicator in Larry skin when dragging a filter
- Fix incorrect filter data after filter delete (#1490356)
* version 8.3 [2015-03-12]
-----------------------------------------------------------
- Fix PHP fatal error when visiting Vacation interface and there's no sieve script yet
- Fix handling of header test with one-element array as header name
- Fix missing host:port in connection error message
* version 8.2 [2015-01-14]
-----------------------------------------------------------
- Fix bug where actions without if/elseif/else in sieve scripts were skipped
- Support "not allof" test as a negation of all sub-tests
- Fix bug where vacation rule was saved to wrong script if managesieve_kolab_master=true
- Improve procedure of script selection to write a vacation rule
* version 8.1 [2014-12-09]
-----------------------------------------------------------
- Added simple API to manage vacation rule
- Fix missing css/js scripts in filter form in mail task
- Fix default vacation status (#1490019)
- Make possible to set vacation start/end date and time
- Fix compatibility with contextmenu plugin
* version 8.0 [2014-07-16]
-----------------------------------------------------------
- Fix bug where non-existing (or unsubscribed) folder wasn't listed in folder selector (#1489956)
- Added optional separate interface for out-of-office management (#1488266)
- Fix disabled "create filter" action
- Fix enotify/notify extension handling
- Improved UI accessibility
- Added option to specify connection socket parameters - managesieve_conn_options
- Support vacation date rules without date extension (#1489978)
* version 7.2 [2014-02-14]
-----------------------------------------------------------
- Nicely handle server-side modification of script names (#1489412)
- Add Filters tab/section using plugin API hook
- Fix issue where folder selector wasn't visible on new filter form
- Fix issue where multi-select fields were not visible in new filter action rows (#1489600)
- Fix issue in displaying filter form when managesieve_kolab_master=true
and sieve variables extension is supported by the server (#1489599)
- Fix wrong action folder selection if managesieve_domains is not empty (#1489617)
- Fix filter creation from an email when preview frame is disabled (#1489647)
* version 7.1 [2013-11-22]
-----------------------------------------------------------
- lib/Net_Sieve.php moved to Roundcube /lib directory
- Added managesieve_domains option to limit redirect destinations
- Fix bug where at least one additional address of vacation message was required (#1489345)
- Fix so i;ascii-numeric comparator is not forced as default for :count and :value operators
- Fix date/currentdate related form issues and comparators handling (#1489346)
- Fix a bug where deleted filter was not removed from the list
* 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]
-----------------------------------------------------------
- Support tls:// prefix in managesieve_host option
- Removed depracated functions usage
- Don't trim whitespace in folder names (#1488955)
* version 6.1 [2012-12-21]
-----------------------------------------------------------
- Fixed filter activation/deactivation confirmation message (#1488765)
- Moved rcube_* classes to <plugin>/lib/Roundcube for compat. with Roundcube Framework autoloader
- Fixed filter selection after filter deletion (#1488832)
- Fixed compatibility with jQueryUI-1.9
- Don't force 'stop' action on last rule in a script
* version 6.0 [2012-10-03]
-----------------------------------------------------------
- Fixed issue with DBMail bug [http://pear.php.net/bugs/bug.php?id=19077] (#1488594)
- Added support for enotify/notify (RFC5435, RFC5436, draft-ietf-sieve-notify-00)
- Change default port to 4190 (IANA-allocated), add port auto-detection (#1488713)
- Added request size limits detection and script corruption prevention (#1488648)
- Fix so scripts listed in managesieve_filename_exceptions aren't displayed on the list (#1488724)
* version 5.2 [2012-07-24]
-----------------------------------------------------------
- Added GUI for variables setting - RFC5229 (patch from Paweł Słowik)
- Fixed scrollbars in Larry's iframes
- Fix performance issue in message_headers_output hook handling
* version 5.1 [2012-06-21]
-----------------------------------------------------------
- Fixed filter popup width (for non-english localizations)
- Fixed tokenizer infinite loop on invalid script content
- Larry skin support
- Fixed custom header name validity check, made RFC2822-compliant
* version 5.0 [2012-01-05]
-----------------------------------------------------------
- Fixed setting test type to :is when none is specified
- Fixed javascript error in IE8
- Fixed possible ID duplication when adding filter rules very fast (#1488288)
- Fixed bug where drag layer wasn't removed when dragging was ended over sets list
* version 5.0-rc1 [2011-11-17]
-----------------------------------------------------------
- Fixed sorting of scripts, scripts including aware of the sort order
- Fixed import of rules with unsupported tests
- Added 'address' and 'envelope' tests support
- Added 'body' extension support (RFC5173)
- Added 'subaddress' extension support (RFC5233)
- Added comparators support
- Changed Sender/Recipient labels to From/To
- Fixed importing rule names from Ingo
- Fixed handling of extensions disabled in config
* version 5.0-beta [2011-10-17]
-----------------------------------------------------------
- Added possibility to create a filter based on selected message "in-place"
- Fixed import from Horde-INGO (#1488064)
- Add managesieve_script_name option for default name of the script (#1487956)
- Fixed handling of enabled magic_quotes_gpc setting
- Fixed PHP warning on connection error when submitting filter form
- Fixed bug where new action row with flags wasn't handled properly
- Added managesieve_connect hook for plugins
- Fixed doubled Filter tab on page refresh
- Added filters set selector in filter form when invoked in mail task
- Improved script parser, added support for include and variables extensions
- Added Kolab's KEP:14 support (http://wiki.kolab.org/User:Greve/Drafts/KEP:14)
- Use smaller action/rule buttons
- UI redesign: added possibility to move filter to any place using drag&drop
(instead of up/down buttons), added filter sets list object, added more
'loading' messages
- Added option to hide some scripts (managesieve_filename_exceptions)
* version 4.3 [2011-07-28]
-----------------------------------------------------------
- Fixed handling of error in Net_Sieve::listScripts()
- Fixed handling of REFERRAL responses (http://pear.php.net/bugs/bug.php?id=17107)
- Fixed bug where wrong folders hierarchy was displayed on folders listing
* version 4.2 [2011-05-24]
-----------------------------------------------------------
- Moved elsif replacement code to handle only imports from other formats
- Fixed mod_mailbox() usage for newer Roundcube versions
- Fixed regex extension (error: regex require missing)
* version 4.1 [2011-03-07]
-----------------------------------------------------------
- Fix fileinto target is always INBOX (#1487776)
- Fix escaping of backslash character in quoted strings (#1487780)
- Fix handling of non-safe characters (double-quote, backslash)
or UTF-8 characters (dovecot's implementation bug workaround)
in script names
- Fix saving of a script using flags extension on servers with imap4flags support (#1487825)
* version 4.0 [2011-02-10]
-----------------------------------------------------------
- Fix STARTTLS for timsieved < 2.3.10
- Added :regex and :matches support (#1487746)
- Added setflag/addflag/removeflag support (#1487449)
- Added support for vacation :subject field (#1487120)
- rcube_sieve_script class moved to separate file
- Moved javascript code from skin templates into managesieve.js file
* version 3.0 [2011-02-01]
-----------------------------------------------------------
- Added support for SASL proxy authentication (#1486691)
- Fixed parsing of scripts with \r\n line separator
- Apply forgotten changes for form errors handling
- Fix multi-line strings parsing (#1487685)
- Added tests for script parser
- Rewritten script parser
- Fix double request when clicking on Filters tab using Firefox
* version 2.10 [2010-10-10]
-----------------------------------------------------------
- Fixed import from Avelsieve
- Use localized size units (#1486976)
- Added support for relational operators and i;ascii-numeric comparator
- Added popups with form errors
* version 2.9 [2010-08-02]
-----------------------------------------------------------
- Fixed vacation parameters parsing (#1486883)
* version 2.8 [2010-07-08]
-----------------------------------------------------------
- Added managesieve_auth_type option (#1486731)
* version 2.7 [2010-07-06]
-----------------------------------------------------------
- Update Net_Sieve to version 1.3.0 (fixes LOGIN athentication)
- Added support for copying and copy sending of messages (COPY extension)
* version 2.6 [2010-06-03]
-----------------------------------------------------------
- Support %n and %d variables in managesieve_host option
* version 2.5 [2010-05-04]
-----------------------------------------------------------
- Fix filters set label after activation
- Fix filters set activation, add possibility to deactivate sets (#1486699)
- Fix download button state when sets list is empty
- Fix errors when sets list is empty
* version 2.4 [2010-04-01]
-----------------------------------------------------------
- Fixed bug in DIGEST-MD5 authentication (http://pear.php.net/bugs/bug.php?id=17285)
- Fixed disabling rules with many tests
- Small css unification with core
- Scripts import/export
* version 2.3 [2010-03-18]
-----------------------------------------------------------
- Added import from Horde-INGO
- Support for more than one match using if+stop instead of if+elsif structures (#1486078)
- Support for selectively disabling rules within a single sieve script (#1485882)
- Added vertical splitter
* version 2.2 [2010-02-06]
-----------------------------------------------------------
- Fix handling of "<>" characters in filter names (#1486477)
* version 2.1 [2010-01-12]
-----------------------------------------------------------
- Fix "require" structure generation when many modules are used
- Fix problem with '<' and '>' characters in header tests
* version 2.0 [2009-11-02]
-----------------------------------------------------------
- Added 'managesieve_debug' option
- Added multi-script support
- Small css improvements + sprite image buttons
- PEAR::NetSieve 1.2.0b1
* version 1.7 [2009-09-20]
-----------------------------------------------------------
- Support multiple managesieve hosts using %h variable
in managesieve_host option
- Fix first rule deleting (#1486140)
* version 1.6 [2009-09-08]
-----------------------------------------------------------
- Fix warning when importing squirrelmail rules
- Fix handling of "true" as "anyof (true)" test
* version 1.5 [2009-09-04]
-----------------------------------------------------------
- Added es_ES, ua_UA localizations
- Added 'managesieve_mbox_encoding' option
* version 1.4 [2009-07-29]
-----------------------------------------------------------
- Updated PEAR::Net_Sieve to 1.1.7
* version 1.3 [2009-07-24]
-----------------------------------------------------------
- support more languages
- support config.inc.php file
* version 1.2 [2009-06-28]
-----------------------------------------------------------
- Support IMAP namespaces in fileinto (#1485943)
- 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)
- Added option for extensions disabling (Jonathan Ernst & alec)
- Added fi_FI, nl_NL, bg_BG localization
- 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]
-----------------------------------------------------------
- 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/lib/Roundcube/rcube_sieve_engine.php b/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php
index 074d3be85..1dcec48ba 100644
--- a/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php
+++ b/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php
@@ -1,3085 +1,3085 @@
<?php
/**
* Managesieve (Sieve Filters) Engine
*
* Engine part of Managesieve plugin implementing UI and backend access.
*
* Copyright (C) The Roundcube Dev Team
* Copyright (C) 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 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/.
*/
class rcube_sieve_engine
{
protected $rc;
protected $sieve;
protected $errors;
protected $form;
protected $list;
protected $tips = array();
protected $script = array();
protected $exts = array();
protected $active = array();
protected $headers = array();
protected $disabled_actions = array();
protected $addr_headers = array(
// Required
"from", "to", "cc", "bcc", "sender", "resent-from", "resent-to",
// Additional (RFC 822 / RFC 2822)
"reply-to", "resent-reply-to", "resent-sender", "resent-cc", "resent-bcc",
// Non-standard (RFC 2076, draft-palme-mailext-headers-08.txt)
"for-approval", "for-handling", "for-comment", "apparently-to", "errors-to",
"delivered-to", "return-receipt-to", "x-admin", "read-receipt-to",
"x-confirm-reading-to", "return-receipt-requested",
"registered-mail-reply-requested-by", "mail-followup-to", "mail-reply-to",
"abuse-reports-to", "x-complaints-to", "x-report-abuse-to",
// Undocumented
"x-beenthere",
);
protected $notify_methods = array(
'mailto',
// 'sms',
// 'tel',
);
protected $notify_importance_options = array(
3 => 'notifyimportancelow',
2 => 'notifyimportancenormal',
1 => 'notifyimportancehigh'
);
- const VERSION = '9.2';
+ const VERSION = '9.3';
const PROGNAME = 'Roundcube (Managesieve)';
const PORT = 4190;
/**
* Class constructor
*/
function __construct($plugin)
{
$this->rc = rcube::get_instance();
$this->plugin = $plugin;
$this->headers = $this->get_default_headers();
}
/**
* Loads configuration, initializes plugin (including sieve connection)
*/
function start($mode = null)
{
// register UI objects
$this->rc->output->add_handlers(array(
'filterslist' => array($this, 'filters_list'),
'filtersetslist' => array($this, 'filtersets_list'),
'filterform' => array($this, 'filter_form'),
'filtersetform' => array($this, 'filterset_form'),
'filterseteditraw' => array($this, 'filterset_editraw'),
));
$this->disabled_actions = (array) $this->rc->config->get('managesieve_disabled_actions');
// connect to managesieve server
$error = $this->connect($_SESSION['username'], $this->rc->decrypt($_SESSION['password']));
// load current/active script
if (!$error) {
// Get list of scripts
$list = $this->list_scripts();
// reset current script when entering filters UI (#1489412)
if ($this->rc->action == 'plugin.managesieve') {
$this->rc->session->remove('managesieve_current');
}
if ($mode != 'vacation' && $mode != 'forward') {
if (!empty($_GET['_set']) || !empty($_POST['_set'])) {
$script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true);
}
else if (!empty($_SESSION['managesieve_current'])) {
$script_name = $_SESSION['managesieve_current'];
}
}
$error = $this->load_script($script_name);
}
// finally set script objects
if ($error) {
switch ($error) {
case rcube_sieve::ERROR_CONNECTION:
case rcube_sieve::ERROR_LOGIN:
$this->rc->output->show_message('managesieve.filterconnerror', 'error');
break;
default:
$this->rc->output->show_message('managesieve.filterunknownerror', 'error');
break;
}
// reload interface in case of possible error when specified script wasn't found (#1489412)
if ($script_name !== null && !empty($list) && !in_array($script_name, $list)) {
$this->rc->output->command('reload', 500);
}
// to disable 'Add filter' button set env variable
$this->rc->output->set_env('filterconnerror', true);
$this->script = array();
}
else {
$this->exts = $this->sieve->get_extensions();
$this->init_script();
$this->rc->output->set_env('currentset', $this->sieve->current);
$_SESSION['managesieve_current'] = $this->sieve->current;
}
$this->rc->output->set_env('raw_sieve_editor', $this->rc->config->get('managesieve_raw_editor', true));
$this->rc->output->set_env('managesieve_disabled_actions', $this->disabled_actions);
if (in_array('list_sets', $this->disabled_actions))
$this->rc->output->set_env('managesieve_no_set_list', true);
return $error;
}
/**
* Connect to configured managesieve server
*
* @param string $username User login
* @param string $password User password
*
* @return int Connection status: 0 on success, >0 on failure
*/
public function connect($username, $password)
{
// Get connection parameters
$host = $this->rc->config->get('managesieve_host', 'localhost');
$port = $this->rc->config->get('managesieve_port');
$tls = $this->rc->config->get('managesieve_usetls', false);
$host = rcube_utils::parse_host($host);
$host = rcube_utils::idn_to_ascii($host);
// remove tls:// prefix, set TLS flag
if (($host = preg_replace('|^tls://|i', '', $host, 1, $cnt)) && $cnt) {
$tls = true;
}
if (empty($port)) {
$port = getservbyname('sieve', 'tcp') ?: self::PORT;
}
$plugin = $this->rc->plugins->exec_hook('managesieve_connect', array(
'user' => $username,
'password' => $password,
'host' => $host,
'port' => $port,
'usetls' => $tls,
'auth_type' => $this->rc->config->get('managesieve_auth_type'),
'disabled' => $this->rc->config->get('managesieve_disabled_extensions'),
'debug' => $this->rc->config->get('managesieve_debug', false),
'auth_cid' => $this->rc->config->get('managesieve_auth_cid'),
'auth_pw' => $this->rc->config->get('managesieve_auth_pw'),
'socket_options' => $this->rc->config->get('managesieve_conn_options')
));
// Handle per-host socket options
rcube_utils::parse_socket_options($plugin['socket_options'], $plugin['host']);
// try to connect to managesieve server and to fetch the script
$this->sieve = new rcube_sieve(
$plugin['user'],
$plugin['password'],
$plugin['host'],
$plugin['port'],
$plugin['auth_type'],
$plugin['usetls'],
$plugin['disabled'],
$plugin['debug'],
$plugin['auth_cid'],
$plugin['auth_pw'],
$plugin['socket_options'],
$plugin['gssapi_context'],
$plugin['gssapi_cn']
);
$error = $this->sieve->error();
if ($error) {
rcube::raise_error(array(
'code' => 403,
'file' => __FILE__,
'line' => __LINE__,
'message' => "Unable to connect to managesieve on $host:$port"
), true, false);
}
return $error;
}
/**
* Load specified (or active) script
*
* @param string $script_name Optional script name
*
* @return int Connection status: 0 on success, >0 on failure
*/
protected function load_script($script_name = null)
{
// Get list of scripts
$list = $this->list_scripts();
if ($script_name === null || $script_name === '') {
// get (first) active script
if (!empty($this->active)) {
$script_name = $this->active[0];
}
else if ($list) {
$script_name = $list[0];
}
// create a new (initial) script
else {
// if script not exists build default script contents
$script_file = $this->rc->config->get('managesieve_default');
$script_name = $this->rc->config->get('managesieve_script_name');
if (empty($script_name)) {
$script_name = 'roundcube';
}
if ($script_file && is_readable($script_file)) {
$content = file_get_contents($script_file);
}
// add script and set it active
if ($this->sieve->save_script($script_name, $content)) {
$this->activate_script($script_name);
$this->list[] = $script_name;
}
}
}
if ($script_name) {
$this->sieve->load($script_name);
}
return $this->sieve->error();
}
/**
* User interface actions handler
*/
function actions()
{
$error = $this->start();
// Handle user requests
if ($action = rcube_utils::get_input_value('_act', rcube_utils::INPUT_GPC)) {
$fid = (int) rcube_utils::get_input_value('_fid', rcube_utils::INPUT_POST);
if ($action == 'delete' && !$error) {
if (!in_array('delete_rule', $this->disabled_actions)) {
if (isset($this->script[$fid])) {
if ($this->sieve->script->delete_rule($fid))
$result = $this->save_script();
if ($result === true) {
$this->rc->output->show_message('managesieve.filterdeleted', 'confirmation');
$this->rc->output->command('managesieve_updatelist', 'del', array('id' => $fid));
}
else {
$this->rc->output->show_message('managesieve.filterdeleteerror', 'error');
}
}
}
else {
$this->rc->output->show_message('managesieve.disabledaction', 'error');
}
}
else if ($action == 'move' && !$error) {
if (isset($this->script[$fid])) {
$to = (int) rcube_utils::get_input_value('_to', rcube_utils::INPUT_POST);
$rule = $this->script[$fid];
// remove rule
unset($this->script[$fid]);
$this->script = array_values($this->script);
// add at target position
if ($to >= count($this->script)) {
$this->script[] = $rule;
}
else {
$script = array();
foreach ($this->script as $idx => $r) {
if ($idx == $to)
$script[] = $rule;
$script[] = $r;
}
$this->script = $script;
}
$this->sieve->script->content = $this->script;
$result = $this->save_script();
if ($result === true) {
$result = $this->list_rules();
$this->rc->output->show_message('managesieve.moved', 'confirmation');
$this->rc->output->command('managesieve_updatelist', 'list',
array('list' => $result, 'clear' => true, 'set' => $to));
}
else {
$this->rc->output->show_message('managesieve.moveerror', 'error');
}
}
}
else if ($action == 'act' && !$error) {
if (isset($this->script[$fid])) {
$rule = $this->script[$fid];
$disabled = !empty($rule['disabled']);
$rule['disabled'] = !$disabled;
$result = $this->sieve->script->update_rule($fid, $rule);
if ($result !== false)
$result = $this->save_script();
if ($result === true) {
if ($rule['disabled'])
$this->rc->output->show_message('managesieve.deactivated', 'confirmation');
else
$this->rc->output->show_message('managesieve.activated', 'confirmation');
$this->rc->output->command('managesieve_updatelist', 'update',
array('id' => $fid, 'disabled' => $rule['disabled']));
}
else {
if ($rule['disabled'])
$this->rc->output->show_message('managesieve.deactivateerror', 'error');
else
$this->rc->output->show_message('managesieve.activateerror', 'error');
}
}
}
else if ($action == 'setact' && !$error) {
if (!in_array('enable_disable_set', $this->disabled_actions)) {
$script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST, true);
$result = $this->activate_script($script_name);
$kep14 = $this->rc->config->get('managesieve_kolab_master');
if ($result === true) {
$this->rc->output->set_env('active_sets', $this->active);
$this->rc->output->show_message('managesieve.setactivated', 'confirmation');
$this->rc->output->command('managesieve_updatelist', 'setact',
array('name' => $script_name, 'active' => true, 'all' => !$kep14));
}
else {
$this->rc->output->show_message('managesieve.setactivateerror', 'error');
}
}
else {
$this->rc->output->show_message('managesieve.disabledaction', 'error');
}
}
else if ($action == 'deact' && !$error) {
if (!in_array('enable_disable_set', $this->disabled_actions)) {
$script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST, true);
$result = $this->deactivate_script($script_name);
if ($result === true) {
$this->rc->output->set_env('active_sets', $this->active);
$this->rc->output->show_message('managesieve.setdeactivated', 'confirmation');
$this->rc->output->command('managesieve_updatelist', 'setact',
array('name' => $script_name, 'active' => false));
}
else {
$this->rc->output->show_message('managesieve.setdeactivateerror', 'error');
}
}
else {
$this->rc->output->show_message('managesieve.disabledaction', 'error');
}
}
else if ($action == 'setdel' && !$error) {
if (!in_array('delete_set', $this->disabled_actions)) {
$script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST, true);
$result = $this->remove_script($script_name);
if ($result === true) {
$this->rc->output->show_message('managesieve.setdeleted', 'confirmation');
$this->rc->output->command('managesieve_updatelist', 'setdel',
array('name' => $script_name));
$this->rc->session->remove('managesieve_current');
}
else {
$this->rc->output->show_message('managesieve.setdeleteerror', 'error');
}
}
else {
$this->rc->output->show_message('managesieve.disabledaction', 'error');
}
}
else if ($action == 'setget') {
if (!in_array('download_set', $this->disabled_actions)) {
$this->rc->request_security_check(rcube_utils::INPUT_GET);
$script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true);
$script = $this->sieve->get_script($script_name);
if ($script !== false) {
$this->rc->output->download_headers($script_name . '.txt', array('length' => strlen($script)));
echo $script;
}
exit;
}
}
else if ($action == 'list') {
$result = $this->list_rules();
$this->rc->output->command('managesieve_updatelist', 'list', array('list' => $result));
}
else if ($action == 'ruleadd') {
$rid = rcube_utils::get_input_value('_rid', rcube_utils::INPUT_POST);
$id = $this->genid();
$content = $this->rule_div($fid, $id, false, $_SESSION['managesieve-compact-form']);
$this->rc->output->command('managesieve_rulefill', $content, $id, $rid);
}
else if ($action == 'actionadd') {
$aid = rcube_utils::get_input_value('_aid', rcube_utils::INPUT_POST);
$id = $this->genid();
$content = $this->action_div($fid, $id, false);
$this->rc->output->command('managesieve_actionfill', $content, $id, $aid);
}
else if ($action == 'addresses') {
$aid = rcube_utils::get_input_value('_aid', rcube_utils::INPUT_POST);
$this->rc->output->command('managesieve_vacation_addresses_update', $aid, $this->user_emails());
}
$this->rc->output->send();
}
else if ($this->rc->task == 'mail') {
// Initialize the form
$rules = rcube_utils::get_input_value('r', rcube_utils::INPUT_GET);
if (!empty($rules)) {
$tests = array();
foreach ($rules as $rule) {
list($header, $value) = explode(':', $rule, 2);
$tests[] = array(
'type' => 'contains',
'test' => 'header',
'arg1' => $header,
'arg2' => $value,
);
}
$this->form = array(
'join' => count($tests) > 1 ? 'allof' : 'anyof',
'name' => '',
'tests' => $tests,
'actions' => array(
0 => array('type' => 'fileinto'),
1 => array('type' => 'stop'),
),
);
}
}
$this->send();
}
function saveraw()
{
// Init plugin and handle managesieve connection
$error = $this->start();
$script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST);
$result = $this->sieve->save_script($script_name, $_POST['rawsetcontent']);
if ($result === false) {
$this->rc->output->show_message('managesieve.filtersaveerror', 'error');
$errorLines = $this->sieve->get_error_lines();
if (count($errorLines) > 0) {
$this->rc->output->set_env("sieve_errors", $errorLines);
}
}
else {
$this->rc->output->show_message('managesieve.setupdated', 'confirmation');
$this->rc->output->command('parent.managesieve_updatelist', 'refresh');
}
$this->send();
}
function save()
{
// Init plugin and handle managesieve connection
$error = $this->start();
// get request size limits (#1488648)
$max_post = max(array(
ini_get('max_input_vars'),
ini_get('suhosin.request.max_vars'),
ini_get('suhosin.post.max_vars'),
));
$max_depth = max(array(
ini_get('suhosin.request.max_array_depth'),
ini_get('suhosin.post.max_array_depth'),
));
// check request size limit
if ($max_post && count($_POST, COUNT_RECURSIVE) >= $max_post) {
rcube::raise_error(array(
'code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Request size limit exceeded (one of max_input_vars/suhosin.request.max_vars/suhosin.post.max_vars)"
), true, false);
$this->rc->output->show_message('managesieve.filtersaveerror', 'error');
}
// check request depth limits
else if ($max_depth && count($_POST['_header']) > $max_depth) {
rcube::raise_error(array(
'code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Request size limit exceeded (one of suhosin.request.max_array_depth/suhosin.post.max_array_depth)"
), true, false);
$this->rc->output->show_message('managesieve.filtersaveerror', 'error');
}
// filters set add action
else if (!empty($_POST['_newset'])) {
$name = rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true);
$copy = rcube_utils::get_input_value('_copy', rcube_utils::INPUT_POST, true);
$from = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST);
$exceptions = $this->rc->config->get('managesieve_filename_exceptions');
$kolab = $this->rc->config->get('managesieve_kolab_master');
$name_uc = mb_strtolower($name);
$list = $this->list_scripts();
if (in_array('new_set', $this->disabled_actions)) {
$error = 'managesieve.disabledaction';
}
else if (!$name) {
$this->errors['name'] = $this->plugin->gettext('cannotbeempty');
}
else if (mb_strlen($name) > 128) {
$this->errors['name'] = $this->plugin->gettext('nametoolong');
}
else if (!empty($exceptions) && in_array($name, (array)$exceptions)) {
$this->errors['name'] = $this->plugin->gettext('namereserved');
}
else if (!empty($kolab) && in_array($name_uc, array('MASTER', 'USER', 'MANAGEMENT'))) {
$this->errors['name'] = $this->plugin->gettext('namereserved');
}
else if (in_array($name, $list)) {
$this->errors['name'] = $this->plugin->gettext('setexist');
}
else if ($from == 'file') {
// from file
if (is_uploaded_file($_FILES['_file']['tmp_name'])) {
$file = file_get_contents($_FILES['_file']['tmp_name']);
$file = preg_replace('/\r/', '', $file);
// for security don't save script directly
// check syntax before, like this...
$this->sieve->load_script($file);
if (!$this->save_script($name)) {
$this->errors['file'] = $this->plugin->gettext('setcreateerror');
}
}
else { // upload failed
$err = $_FILES['_file']['error'];
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
$msg = $this->rc->gettext(array('name' => 'filesizeerror',
'vars' => array('size' =>
$this->rc->show_bytes(rcube_utils::max_upload_size()))));
}
else {
$this->errors['file'] = $this->plugin->gettext('fileuploaderror');
}
}
}
else if (!$this->sieve->copy($name, $from == 'set' ? $copy : '')) {
$error = 'managesieve.setcreateerror';
}
if (!$error && empty($this->errors)) {
// Find position of the new script on the list
$list[] = $name;
asort($list, SORT_LOCALE_STRING);
$list = array_values($list);
$index = array_search($name, $list);
$this->rc->output->show_message('managesieve.setcreated', 'confirmation');
$this->rc->output->command('parent.managesieve_updatelist', 'setadd',
array('name' => $name, 'index' => $index));
}
else if ($msg) {
$this->rc->output->command('display_message', $msg, 'error');
}
else if ($error) {
$this->rc->output->show_message($error, 'error');
}
}
// filter add/edit action
else if (isset($_POST['_name'])) {
$name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true));
$fid = trim(rcube_utils::get_input_value('_fid', rcube_utils::INPUT_POST));
$join = trim(rcube_utils::get_input_value('_join', rcube_utils::INPUT_POST));
// and arrays
$headers = rcube_utils::get_input_value('_header', rcube_utils::INPUT_POST);
$cust_headers = rcube_utils::get_input_value('_custom_header', rcube_utils::INPUT_POST);
$cust_vars = rcube_utils::get_input_value('_custom_var', rcube_utils::INPUT_POST);
$ops = rcube_utils::get_input_value('_rule_op', rcube_utils::INPUT_POST);
$sizeops = rcube_utils::get_input_value('_rule_size_op', rcube_utils::INPUT_POST);
$sizeitems = rcube_utils::get_input_value('_rule_size_item', rcube_utils::INPUT_POST);
$sizetargets = rcube_utils::get_input_value('_rule_size_target', rcube_utils::INPUT_POST);
$targets = rcube_utils::get_input_value('_rule_target', rcube_utils::INPUT_POST, true);
$mods = rcube_utils::get_input_value('_rule_mod', rcube_utils::INPUT_POST);
$mod_types = rcube_utils::get_input_value('_rule_mod_type', rcube_utils::INPUT_POST);
$body_trans = rcube_utils::get_input_value('_rule_trans', rcube_utils::INPUT_POST);
$body_types = rcube_utils::get_input_value('_rule_trans_type', rcube_utils::INPUT_POST, true);
$comparators = rcube_utils::get_input_value('_rule_comp', rcube_utils::INPUT_POST);
$indexes = rcube_utils::get_input_value('_rule_index', rcube_utils::INPUT_POST);
$lastindexes = rcube_utils::get_input_value('_rule_index_last', rcube_utils::INPUT_POST);
$dateheaders = rcube_utils::get_input_value('_rule_date_header', rcube_utils::INPUT_POST);
$dateparts = rcube_utils::get_input_value('_rule_date_part', rcube_utils::INPUT_POST);
$mime_parts = rcube_utils::get_input_value('_rule_mime_part', rcube_utils::INPUT_POST);
$mime_types = rcube_utils::get_input_value('_rule_mime_type', rcube_utils::INPUT_POST);
$mime_params = rcube_utils::get_input_value('_rule_mime_param', rcube_utils::INPUT_POST, true);
$message = rcube_utils::get_input_value('_rule_message', rcube_utils::INPUT_POST);
$dup_handles = rcube_utils::get_input_value('_rule_duplicate_handle', rcube_utils::INPUT_POST, true);
$dup_headers = rcube_utils::get_input_value('_rule_duplicate_header', rcube_utils::INPUT_POST, true);
$dup_uniqueids = rcube_utils::get_input_value('_rule_duplicate_uniqueid', rcube_utils::INPUT_POST, true);
$dup_seconds = rcube_utils::get_input_value('_rule_duplicate_seconds', rcube_utils::INPUT_POST);
$dup_lasts = rcube_utils::get_input_value('_rule_duplicate_last', rcube_utils::INPUT_POST);
$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);
$intervals = rcube_utils::get_input_value('_action_interval', rcube_utils::INPUT_POST);
$interval_types = rcube_utils::get_input_value('_action_interval_type', rcube_utils::INPUT_POST);
$from = rcube_utils::get_input_value('_action_from', rcube_utils::INPUT_POST);
$subject = rcube_utils::get_input_value('_action_subject', rcube_utils::INPUT_POST, true);
$flags = rcube_utils::get_input_value('_action_flags', rcube_utils::INPUT_POST);
$varnames = rcube_utils::get_input_value('_action_varname', rcube_utils::INPUT_POST);
$varvalues = rcube_utils::get_input_value('_action_varvalue', rcube_utils::INPUT_POST);
$varmods = rcube_utils::get_input_value('_action_varmods', rcube_utils::INPUT_POST);
$notifymethods = rcube_utils::get_input_value('_action_notifymethod', rcube_utils::INPUT_POST);
$notifytargets = rcube_utils::get_input_value('_action_notifytarget', rcube_utils::INPUT_POST, true);
$notifyoptions = rcube_utils::get_input_value('_action_notifyoption', rcube_utils::INPUT_POST, true);
$notifymessages = rcube_utils::get_input_value('_action_notifymessage', rcube_utils::INPUT_POST, true);
$notifyfrom = rcube_utils::get_input_value('_action_notifyfrom', rcube_utils::INPUT_POST);
$notifyimp = rcube_utils::get_input_value('_action_notifyimportance', rcube_utils::INPUT_POST);
$addheader_name = rcube_utils::get_input_value('_action_addheader_name', rcube_utils::INPUT_POST);
$addheader_value = rcube_utils::get_input_value('_action_addheader_value', rcube_utils::INPUT_POST, true);
$addheader_pos = rcube_utils::get_input_value('_action_addheader_pos', rcube_utils::INPUT_POST);
$delheader_name = rcube_utils::get_input_value('_action_delheader_name', rcube_utils::INPUT_POST);
$delheader_value = rcube_utils::get_input_value('_action_delheader_value', rcube_utils::INPUT_POST, true);
$delheader_pos = rcube_utils::get_input_value('_action_delheader_pos', rcube_utils::INPUT_POST);
$delheader_index = rcube_utils::get_input_value('_action_delheader_index', rcube_utils::INPUT_POST);
$delheader_op = rcube_utils::get_input_value('_action_delheader_op', rcube_utils::INPUT_POST);
$delheader_comp = rcube_utils::get_input_value('_action_delheader_comp', rcube_utils::INPUT_POST);
$this->form['disabled'] = !empty($_POST['_disabled']);
$this->form['join'] = $join == 'allof';
$this->form['name'] = $name;
$this->form['tests'] = array();
$this->form['actions'] = array();
if ($name == '')
$this->errors['name'] = $this->plugin->gettext('cannotbeempty');
else {
foreach ($this->script as $idx => $rule)
if($rule['name'] == $name && $idx != $fid) {
$this->errors['name'] = $this->plugin->gettext('ruleexist');
break;
}
}
$i = 0;
// rules
if ($join == 'any') {
$this->form['tests'][0]['test'] = 'true';
}
else {
foreach ($headers as $idx => $header) {
// targets are indexed differently (assume form order)
$target = $this->strip_value($targets[$idx], true);
$header = $this->strip_value($header);
$operator = $this->strip_value($ops[$idx]);
$comparator = $this->strip_value($comparators[$idx]);
if ($header == 'size') {
$sizeop = $this->strip_value($sizeops[$idx]);
$sizeitem = $this->strip_value($sizeitems[$idx]);
$sizetarget = $this->strip_value($sizetargets[$idx]);
$this->form['tests'][$i]['test'] = 'size';
$this->form['tests'][$i]['type'] = $sizeop;
$this->form['tests'][$i]['arg'] = $sizetarget;
if ($sizetarget == '')
$this->errors['tests'][$i]['sizetarget'] = $this->plugin->gettext('cannotbeempty');
else if (!preg_match('/^[0-9]+(K|M|G)?$/i', $sizetarget.$sizeitem, $m)) {
$this->errors['tests'][$i]['sizetarget'] = $this->plugin->gettext('forbiddenchars');
$this->form['tests'][$i]['item'] = $sizeitem;
}
else
$this->form['tests'][$i]['arg'] .= $m[1];
}
else if ($header == 'currentdate') {
$datepart = $this->strip_value($dateparts[$idx]);
if (preg_match('/^not/', $operator))
$this->form['tests'][$i]['not'] = true;
$type = preg_replace('/^not/', '', $operator);
if ($type == 'exists') {
$this->errors['tests'][$i]['op'] = true;
}
$this->form['tests'][$i]['test'] = 'currentdate';
$this->form['tests'][$i]['type'] = $type;
$this->form['tests'][$i]['part'] = $datepart;
$this->form['tests'][$i]['arg'] = $target;
if ($type != 'exists') {
if (empty($target)) {
$this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
}
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) && !empty($target)) {
foreach ($target as $arg) {
if (!$this->validate_date_part($datepart, $arg)) {
$this->errors['tests'][$i]['target'] = $this->plugin->gettext('invaliddateformat');
break;
}
}
}
}
}
else if ($header == 'date') {
$datepart = $this->strip_value($dateparts[$idx]);
$dateheader = $this->strip_value($dateheaders[$idx]);
$index = $this->strip_value($indexes[$idx]);
$indexlast = $this->strip_value($lastindexes[$idx]);
if (preg_match('/^not/', $operator)) {
$this->form['tests'][$i]['not'] = true;
}
$type = preg_replace('/^not/', '', $operator);
if ($type == 'exists') {
$this->errors['tests'][$i]['op'] = true;
}
if (!empty($index) && $mod != 'envelope') {
$this->form['tests'][$i]['index'] = intval($index);
$this->form['tests'][$i]['last'] = !empty($indexlast);
}
if (empty($dateheader)) {
$dateheader = 'Date';
}
else if (!preg_match('/^[\x21-\x39\x41-\x7E]+$/i', $dateheader)) {
$this->errors['tests'][$i]['dateheader'] = $this->plugin->gettext('forbiddenchars');
}
$this->form['tests'][$i]['test'] = 'date';
$this->form['tests'][$i]['type'] = $type;
$this->form['tests'][$i]['part'] = $datepart;
$this->form['tests'][$i]['arg'] = $target;
$this->form['tests'][$i]['header'] = $dateheader;
if ($type != 'exists') {
if (empty($target)) {
$this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
}
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 (!empty($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');
break;
}
}
}
}
}
else if ($header == 'body') {
$trans = $this->strip_value($body_trans[$idx]);
$trans_type = $this->strip_value($body_types[$idx], true);
if (preg_match('/^not/', $operator))
$this->form['tests'][$i]['not'] = true;
$type = preg_replace('/^not/', '', $operator);
if ($type == 'exists') {
$this->errors['tests'][$i]['op'] = true;
}
$this->form['tests'][$i]['test'] = 'body';
$this->form['tests'][$i]['type'] = $type;
$this->form['tests'][$i]['arg'] = $target;
if (empty($target) && $type != 'exists') {
$this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
}
else if (preg_match('/^(value|count)-/', $type)) {
foreach ($target as $target_value) {
if (preg_match('/[^0-9]/', $target_value)) {
$this->errors['tests'][$i]['target'] = $this->plugin->gettext('forbiddenchars');
}
}
}
$this->form['tests'][$i]['part'] = $trans;
if ($trans == 'content') {
$this->form['tests'][$i]['content'] = $trans_type;
}
}
else if ($header == 'message') {
$test = $this->strip_value($message[$idx]);
if (preg_match('/^not/', $test)) {
$this->form['tests'][$i]['not'] = true;
$test = substr($test, 3);
}
$this->form['tests'][$i]['test'] = $test;
if ($test == 'duplicate') {
$this->form['tests'][$i]['last'] = !empty($dup_lasts[$idx]);
$this->form['tests'][$i]['handle'] = trim($dup_handles[$idx]);
$this->form['tests'][$i]['header'] = trim($dup_headers[$idx]);
$this->form['tests'][$i]['uniqueid'] = trim($dup_uniqueids[$idx]);
$this->form['tests'][$i]['seconds'] = trim($dup_seconds[$idx]);
if ($this->form['tests'][$i]['seconds']
&& preg_match('/[^0-9]/', $this->form['tests'][$i]['seconds'])
) {
$this->errors['tests'][$i]['duplicate_seconds'] = $this->plugin->gettext('forbiddenchars');
}
if ($this->form['tests'][$i]['header'] && $this->form['tests'][$i]['uniqueid']) {
$this->errors['tests'][$i]['duplicate_uniqueid'] = $this->plugin->gettext('duplicate.conflict.err');
}
}
}
else {
$cust_header = $headers = $this->strip_value($cust_headers[$idx]);
$mod = $this->strip_value($mods[$idx]);
$mod_type = $this->strip_value($mod_types[$idx]);
$index = $this->strip_value($indexes[$idx]);
$indexlast = $this->strip_value($lastindexes[$idx]);
$mime_param = $this->strip_value($mime_params[$idx]);
$mime_type = $mime_types[$idx];
$mime_part = $mime_parts[$idx];
if ($header == 'string') {
$cust_var = $headers = $this->strip_value($cust_vars[$idx]);
}
if (preg_match('/^not/', $operator))
$this->form['tests'][$i]['not'] = true;
$type = preg_replace('/^not/', '', $operator);
if (!empty($index) && $mod != 'envelope') {
$this->form['tests'][$i]['index'] = intval($index);
$this->form['tests'][$i]['last'] = !empty($indexlast);
}
if ($header == '...' || $header == 'string') {
if (!count($headers))
$this->errors['tests'][$i]['header'] = $this->plugin->gettext('cannotbeempty');
else if ($header == '...') {
foreach ($headers as $hr) {
// RFC2822: printable ASCII except colon
if (!preg_match('/^[\x21-\x39\x41-\x7E]+$/i', $hr)) {
$this->errors['tests'][$i]['header'] = $this->plugin->gettext('forbiddenchars');
}
}
}
if (empty($this->errors['tests'][$i]['header']))
$cust_header = $cust_var = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers;
}
$test = $header == 'string' ? 'string' : 'header';
$header = $header == 'string' ? $cust_var : $header;
$header = $header == '...' ? $cust_header : $header;
if (is_array($header)) {
foreach ($header as $h_index => $val) {
if (isset($this->headers[$val])) {
$header[$h_index] = $this->headers[$val];
}
}
}
if ($type == 'exists') {
$this->form['tests'][$i]['test'] = 'exists';
$this->form['tests'][$i]['arg'] = $header;
}
else {
if ($mod == 'address' || $mod == 'envelope') {
$found = false;
if (empty($this->errors['tests'][$i]['header'])) {
foreach ((array)$header as $hdr) {
if (!in_array(strtolower(trim($hdr)), $this->addr_headers))
$found = true;
}
}
if (!$found)
$test = $mod;
}
$this->form['tests'][$i]['type'] = $type;
$this->form['tests'][$i]['test'] = $test;
$this->form['tests'][$i]['arg1'] = $header;
$this->form['tests'][$i]['arg2'] = $target;
if (empty($target)) {
$this->errors['tests'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
}
else if (preg_match('/^(value|count)-/', $type)) {
foreach ($target as $target_value) {
if (preg_match('/[^0-9]/', $target_value)) {
$this->errors['tests'][$i]['target'] = $this->plugin->gettext('forbiddenchars');
}
}
}
if ($mod) {
$this->form['tests'][$i]['part'] = $mod_type;
}
}
if ($test == 'header') {
if (in_array($mime_type, array('type', 'subtype', 'contenttype', 'param'))) {
$this->form['tests'][$i]['mime-' . $mime_type] = true;
if ($mime_type == 'param') {
if (empty($mime_param)) {
$this->errors['tests'][$i]['mime-param'] = $this->plugin->gettext('cannotbeempty');
}
$this->form['tests'][$i]['mime-param'] = $mime_param;
}
}
if ($mime_part == 'anychild') {
$this->form['tests'][$i]['mime-anychild'] = true;
}
}
}
if ($header != 'size' && $comparator) {
$this->form['tests'][$i]['comparator'] = $comparator;
}
$i++;
}
}
$i = 0;
// actions
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;
}
break;
case 'reject':
case 'ereject':
$target = $this->strip_value($area_targets[$idx]);
$this->form['actions'][$i]['target'] = str_replace("\r\n", "\n", $target);
// if ($target == '')
// $this->errors['actions'][$i]['targetarea'] = $this->plugin->gettext('cannotbeempty');
break;
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 ($target == '')
$this->errors['actions'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
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':
case 'setflag':
case 'removeflag':
$_target = array();
if (empty($flags[$idx])) {
$this->errors['actions'][$i]['target'] = $this->plugin->gettext('noflagset');
}
else {
foreach ($flags[$idx] as $flag) {
$_target[] = $this->strip_value($flag);
}
}
$this->form['actions'][$i]['target'] = $_target;
break;
case 'addheader':
case 'deleteheader':
$this->form['actions'][$i]['name'] = trim($type == 'addheader' ? $addheader_name[$idx] : $delheader_name[$idx]);
$this->form['actions'][$i]['value'] = $type == 'addheader' ? $addheader_value[$idx] : $delheader_value[$idx];
$this->form['actions'][$i]['last'] = ($type == 'addheader' ? $addheader_pos[$idx] : $delheader_pos[$idx]) == 'last';
if (empty($this->form['actions'][$i]['name'])) {
$this->errors['actions'][$i]['name'] = $this->plugin->gettext('cannotbeempty');
}
else if (!preg_match('/^[0-9a-z_-]+$/i', $this->form['actions'][$i]['name'])) {
$this->errors['actions'][$i]['name'] = $this->plugin->gettext('forbiddenchars');
}
if ($type == 'deleteheader') {
foreach ((array) $this->form['actions'][$i]['value'] as $pidx => $pattern) {
if (empty($pattern)) {
unset($this->form['actions'][$i]['value'][$pidx]);
}
}
$this->form['actions'][$i]['match-type'] = $delheader_op[$idx];
$this->form['actions'][$i]['comparator'] = $delheader_comp[$idx];
$this->form['actions'][$i]['index'] = $delheader_index[$idx];
if (empty($this->form['actions'][$i]['index'])) {
if (!empty($this->form['actions'][$i]['last'])) {
$this->errors['actions'][$i]['index'] = $this->plugin->gettext('lastindexempty');
}
}
else if (!preg_match('/^[0-9]+$/i', $this->form['actions'][$i]['index'])) {
$this->errors['actions'][$i]['index'] = $this->plugin->gettext('forbiddenchars');
}
}
else {
if (empty($this->form['actions'][$i]['value'])) {
$this->errors['actions'][$i]['value'] = $this->plugin->gettext('cannotbeempty');
}
}
break;
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]['from'] = $from[$idx];
$this->form['actions'][$i]['subject'] = $subject[$idx];
$this->form['actions'][$i]['addresses'] = $addresses[$idx];
$this->form['actions'][$i][$interval_type] = $intervals[$idx];
// @TODO: vacation :mime, :handle
foreach ((array)$this->form['actions'][$i]['addresses'] as $aidx => $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;
}
}
if (!empty($this->form['actions'][$i]['from']) && !rcube_utils::check_email($this->form['actions'][$i]['from'])) {
$this->errors['actions'][$i]['from'] = $this->plugin->gettext('noemailwarning');
}
if ($this->form['actions'][$i]['reason'] == '')
$this->errors['actions'][$i]['reason'] = $this->plugin->gettext('cannotbeempty');
if ($this->form['actions'][$i][$interval_type] && !preg_match('/^[0-9]+$/', $this->form['actions'][$i][$interval_type]))
$this->errors['actions'][$i]['interval'] = $this->plugin->gettext('forbiddenchars');
break;
case 'set':
$this->form['actions'][$i]['name'] = $varnames[$idx];
$this->form['actions'][$i]['value'] = $varvalues[$idx];
foreach ((array)$varmods[$idx] as $v_m) {
$this->form['actions'][$i][$v_m] = true;
}
if (empty($varnames[$idx])) {
$this->errors['actions'][$i]['name'] = $this->plugin->gettext('cannotbeempty');
}
else if (!preg_match('/^[0-9a-z_]+$/i', $varnames[$idx])) {
$this->errors['actions'][$i]['name'] = $this->plugin->gettext('forbiddenchars');
}
if (!isset($varvalues[$idx]) || $varvalues[$idx] === '') {
$this->errors['actions'][$i]['value'] = $this->plugin->gettext('cannotbeempty');
}
break;
case 'notify':
if (empty($notifymethods[$idx])) {
$this->errors['actions'][$i]['method'] = $this->plugin->gettext('cannotbeempty');
}
if (empty($notifytargets[$idx])) {
$this->errors['actions'][$i]['target'] = $this->plugin->gettext('cannotbeempty');
}
if (!empty($notifyfrom[$idx]) && !rcube_utils::check_email($notifyfrom[$idx])) {
$this->errors['actions'][$i]['from'] = $this->plugin->gettext('noemailwarning');
}
// skip empty options
foreach ((array)$notifyoptions[$idx] as $opt_idx => $opt) {
if (!strlen(trim($opt))) {
unset($notifyoptions[$idx][$opt_idx]);
}
}
$this->form['actions'][$i]['method'] = $notifymethods[$idx] . ':' . $notifytargets[$idx];
$this->form['actions'][$i]['options'] = $notifyoptions[$idx];
$this->form['actions'][$i]['message'] = $notifymessages[$idx];
$this->form['actions'][$i]['from'] = $notifyfrom[$idx];
$this->form['actions'][$i]['importance'] = $notifyimp[$idx];
break;
}
$this->form['actions'][$i]['type'] = $type;
$i++;
}
if (!$this->errors && !$error) {
// save the script
if (!isset($this->script[$fid])) {
$fid = $this->sieve->script->add_rule($this->form);
$new = true;
}
else {
$fid = $this->sieve->script->update_rule($fid, $this->form);
}
if ($fid !== false) {
$save = $this->save_script();
}
if ($save && $fid !== false) {
$this->rc->output->show_message('managesieve.filtersaved', 'confirmation');
if ($this->rc->task != 'mail') {
$this->rc->output->command('parent.managesieve_updatelist',
isset($new) ? 'add' : 'update',
array(
'name' => $this->form['name'],
'id' => $fid,
'disabled' => $this->form['disabled']
));
}
else {
$this->rc->output->command('managesieve_dialog_close');
$this->rc->output->send('iframe');
}
}
else {
$this->rc->output->show_message('managesieve.filtersaveerror', 'error');
}
}
else {
$this->rc->output->show_message('managesieve.filterformerror', 'warning');
}
}
$this->send();
}
protected function send()
{
// Handle form action
if (isset($_GET['_framed']) || isset($_POST['_framed'])) {
if (isset($_GET['_newset']) || isset($_POST['_newset'])) {
$this->rc->output->send('managesieve.setedit');
}
else if (isset($_GET['_seteditraw']) || isset($_POST['_seteditraw'])) {
$this->rc->output->send('managesieve.seteditraw');
}
else {
$this->rc->output->send('managesieve.filteredit');
}
}
else {
$this->rc->output->set_pagetitle($this->plugin->gettext('filters'));
$this->rc->output->send('managesieve.managesieve');
}
}
// return the filters list as HTML table
function filters_list($attrib)
{
// add id to message list table if not specified
if (!strlen($attrib['id']))
$attrib['id'] = 'rcmfilterslist';
// define list of cols to be displayed
$a_show_cols = array('name');
$result = $this->list_rules();
// create XHTML table
$out = $this->rc->table_output($attrib, $result, $a_show_cols, 'id');
// set client env
$this->rc->output->add_gui_object('filterslist', $attrib['id']);
$this->rc->output->include_script('list.js');
// add some labels to client
$this->rc->output->add_label('managesieve.filterdeleteconfirm');
return $out;
}
// return the filters list as <SELECT>
function filtersets_list($attrib, $no_env = false)
{
// add id to message list table if not specified
if (!strlen($attrib['id'])) {
$attrib['id'] = 'rcmfiltersetslist';
}
$list = $this->list_scripts();
if ($list) {
asort($list, SORT_LOCALE_STRING);
}
if (!empty($attrib['type']) && $attrib['type'] == 'list') {
// define list of cols to be displayed
$a_show_cols = array('name');
if ($list) {
foreach ($list as $idx => $set) {
$scripts['S'.$idx] = $set;
$result[] = array(
'name' => $set,
'id' => 'S'.$idx,
'class' => !in_array($set, $this->active) ? 'disabled' : '',
);
}
}
// create XHTML table
$out = $this->rc->table_output($attrib, $result, $a_show_cols, 'id');
$this->rc->output->set_env('filtersets', $scripts);
$this->rc->output->include_script('list.js');
}
else {
$select = new html_select(array('name' => '_set', 'id' => $attrib['id'],
'onchange' => $this->rc->task != 'mail' ? 'rcmail.managesieve_set()' : ''));
if ($list) {
foreach ($list as $set)
$select->add($set, $set);
}
$out = $select->show($this->sieve->current);
}
// set client env
if (!$no_env) {
$this->rc->output->add_gui_object('filtersetslist', $attrib['id']);
$this->rc->output->add_label('managesieve.setdeleteconfirm');
}
return $out;
}
function filterset_editraw($attrib)
{
$script_name = isset($_GET['_set']) ? $_GET['_set'] : $_POST['_set'];
$script = $this->sieve->get_script($script_name);
$script_post = $_POST['rawsetcontent'];
$hiddenfields = new html_hiddenfield();
$hiddenfields->add(array('name' => '_task', 'value' => $this->rc->task));
$hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-saveraw'));
$hiddenfields->add(array('name' => '_set', 'value' => $script_name));
$hiddenfields->add(array('name' => '_seteditraw', 'value' => 1));
$hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
$out = $hiddenfields->show();
$txtarea = new html_textarea(array(
'id' => 'rawfiltersettxt',
'name' => 'rawsetcontent',
'class' => 'form-control',
'rows' => '15'
));
$out .= $txtarea->show($script_post !== null ? $script_post : ($script !== false ? rtrim($script) : ''));
$this->rc->output->add_gui_object('sievesetrawform', 'filtersetrawform');
$this->plugin->include_stylesheet('codemirror/lib/codemirror.css');
$this->plugin->include_script('codemirror/lib/codemirror.js');
$this->plugin->include_script('codemirror/addon/selection/active-line.js');
$this->plugin->include_script('codemirror/mode/sieve/sieve.js');
if ($script === false) {
$this->rc->output->show_message('managesieve.filterunknownerror', 'error');
}
$out = html::tag('form', $attrib + array(
'id' => 'filtersetrawform',
'name' => 'filtersetrawform',
'action' => './',
'method' => 'post',
'enctype' => 'multipart/form-data',
), $out);
return str_replace('</form>', '', $out);
}
function filterset_form($attrib)
{
if (!$attrib['id']) {
$attrib['id'] = 'rcmfiltersetform';
}
$table = new html_table(array('cols' => 2, 'class' => 'propform'));
$hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task));
$hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save'));
$hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
$hiddenfields->add(array('name' => '_newset', 'value' => 1));
$name = rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST);
$copy = rcube_utils::get_input_value('_copy', rcube_utils::INPUT_POST);
$selected = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST);
// filter set name input
$input_name = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30,
'class' => ($this->errors['name'] ? 'error' : '')));
$table->add('title', html::label('_name', rcube::Q($this->plugin->gettext('filtersetname'))));
$table->add(null, $input_name->show($name));
$filters = '<ul class="proplist">';
$filters .= '<li>' . html::label('from_none', html::tag('input', array(
'type' => 'radio',
'id' => 'from_none',
'name' => '_from',
'value' => 'none',
'checked' => !$selected || $selected == 'none'
)) . rcube::Q($this->plugin->gettext('none'))) . '</li>';
// filters set list
$list = $this->list_scripts();
$select = new html_select(array('name' => '_copy', 'id' => '_copy'));
if (is_array($list)) {
asort($list, SORT_LOCALE_STRING);
if (!$copy)
$copy = $_SESSION['managesieve_current'];
foreach ($list as $set) {
$select->add($set, $set);
}
$filters .= '<li>' . html::label('from_set', html::tag('input', array(
'type' => 'radio',
'id' => 'from_set',
'name' => '_from',
'value' => 'set',
'checked' => $selected == 'set',
)) . rcube::Q($this->plugin->gettext('fromset')) . ' ' . $select->show($copy)) . '</li>';
}
// script upload box
$upload = new html_inputfield(array('name' => '_file', 'id' => '_file', 'size' => 30,
'type' => 'file', 'class' => ($this->errors['file'] ? 'error' : '')));
$filters .= '<li>' . html::label('from_file', html::tag('input', array(
'type' => 'radio',
'id' => 'from_file',
'name' => '_from',
'value' => 'file',
'checked' => $selected == 'file',
)) . rcube::Q($this->plugin->gettext('fromfile')) . ' ' . $upload->show()) . '</li>';
$filters .= '</ul>';
$table->add('title', html::label('from_none', rcube::Q($this->plugin->gettext('filters'))));
$table->add('', $filters);
$out = '<form name="filtersetform" action="./" method="post" enctype="multipart/form-data">'
. "\n" . $hiddenfields->show() . "\n" . $table->show();
$this->rc->output->add_gui_object('sieveform', 'filtersetform');
if ($this->errors['name'])
$this->add_tip('_name', $this->errors['name'], true);
if ($this->errors['file'])
$this->add_tip('_file', $this->errors['file'], true);
$this->print_tips();
return $out;
}
function filter_form($attrib)
{
if (!$attrib['id']) {
$attrib['id'] = 'rcmfilterform';
}
$fid = rcube_utils::get_input_value('_fid', rcube_utils::INPUT_GPC);
$scr = isset($this->form) ? $this->form : $this->script[$fid];
$compact = !empty($attrib['compact-form']);
$_SESSION['managesieve-compact-form'] = $compact;
// do not allow creation of new rules
if ($fid == null && in_array('new_rule', $this->disabled_actions)) {
$this->rc->output->show_message('managesieve.disabledaction', 'error');
return;
}
$hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task));
$hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save'));
$hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
$hiddenfields->add(array('name' => '_fid', 'value' => $fid));
$out = $hiddenfields->show();
// 'any' flag
if ((!isset($this->form) && empty($scr['tests']) && !empty($scr))
|| (is_array($scr['tests']) && count($scr['tests']) == 1 && $scr['tests'][0]['test'] == 'true' && !$scr['tests'][0]['not'])
) {
$any = true;
}
// filter name input
$input_name = new html_inputfield(array(
'name' => '_name',
'id' => '_name',
'size' => 30,
'class' => ($this->errors['name'] ? ' error' : '')
));
if ($this->errors['name']) {
$this->add_tip('_name', $this->errors['name'], true);
}
$input_name = $input_name->show(isset($scr) ? $scr['name'] : '');
$out .= sprintf("\n" . '<div class="form-group row">'
. '<label for="_name" class="col-sm-4 col-form-label">%s</label>'
. '<div class="col-sm-8">%s</div></div>',
rcube::Q($this->plugin->gettext('filtername')), $input_name);
// filter set selector
if ($this->rc->task == 'mail') {
$out .= sprintf("\n" . '<div class="form-group row">'
. '<label for="%s" class="col-sm-4 col-form-label">%s</label>'
. '<div class="col-sm-8">%s</div></div>',
'sievescriptname',
rcube::Q($this->plugin->gettext('filterset')),
$this->filtersets_list(array('id' => 'sievescriptname'), true)
);
}
else if ($compact) {
$out .= sprintf("\n" . '<div class="form-group row form-check">'
. '<label for="disabled" class="col-sm-4 col-form-label">%s</label>'
. '<div class="col-sm-8 form-check"><input type="checkbox" id="disabled" name="_disabled" value="1" /></div></div>',
rcube::Q($this->plugin->gettext('filterdisabled')));
}
if ($compact) {
$select = new html_select(array('name' => '_join', 'id' => '_join' . $id,
'onchange' => 'rule_join_radio(this.value)'));
foreach (array('allof', 'anyof', 'any') as $val) {
$select->add($this->plugin->gettext('filter' . $val), $val);
}
$join = $any ? 'any' : 'allof';
if (isset($scr) && !$any) {
$join = $scr['join'] ? 'allof' : 'anyof';
}
$out .= sprintf("\n" . '<div class="form-group row">'
. '<label for="_join" class="col-sm-4 col-form-label">%s</label>'
. '<div class="col-sm-8">%s</div></div>',
rcube::Q($this->plugin->gettext('scope')), $select->show($join));
$out .= '<div id="rules"'.($any ? ' style="display: none"' : '').'>';
$out .= "\n<fieldset><legend>" . rcube::Q($this->plugin->gettext('rules')) . "</legend>\n";
}
else {
$out .= '<br><fieldset><legend>' . rcube::Q($this->plugin->gettext('messagesrules')) . "</legend>\n";
// any, allof, anyof radio buttons
$field_id = '_allof';
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'allof',
'onclick' => 'rule_join_radio(\'allof\')', 'class' => 'radio'));
if (isset($scr) && !$any)
$input_join = $input_join->show($scr['join'] ? 'allof' : '');
else
$input_join = $input_join->show();
$out .= $input_join . html::label($field_id, rcube::Q($this->plugin->gettext('filterallof')));
$field_id = '_anyof';
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'anyof',
'onclick' => 'rule_join_radio(\'anyof\')', 'class' => 'radio'));
if (isset($scr) && !$any)
$input_join = $input_join->show($scr['join'] ? '' : 'anyof');
else
$input_join = $input_join->show('anyof'); // default
$out .= $input_join . html::label($field_id, rcube::Q($this->plugin->gettext('filteranyof')));
$field_id = '_any';
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'any',
'onclick' => 'rule_join_radio(\'any\')', 'class' => 'radio'));
$input_join = $input_join->show($any ? 'any' : '');
$out .= $input_join . html::label($field_id, rcube::Q($this->plugin->gettext('filterany')));
$out .= '<div id="rules"'.($any ? ' style="display: none"' : '').'>';
}
$rows_num = !empty($scr['tests']) ? count($scr['tests']) : 1;
for ($x=0; $x<$rows_num; $x++) {
$out .= $this->rule_div($fid, $x, true, $compact);
}
$out .= $compact ? "</fieldset>\n</div>\n" : "</div>\n</fieldset>\n";
// actions
$label = $this->plugin->gettext($compact ? 'actions' : 'messagesactions');
$out .= '<fieldset><legend>' . rcube::Q($label) . "</legend>\n";
$rows_num = isset($scr) ? count($scr['actions']) : 1;
$out .= '<div id="actions">';
for ($x=0; $x<$rows_num; $x++)
$out .= $this->action_div($fid, $x);
$out .= "</div>\n";
$out .= "</fieldset>\n";
$this->print_tips();
if ($scr['disabled']) {
$this->rc->output->set_env('rule_disabled', true);
}
$this->rc->output->add_label(
'managesieve.ruledeleteconfirm',
'managesieve.actiondeleteconfirm'
);
$this->rc->output->add_gui_object('sieveform', 'filterform');
$attrib['name'] = 'filterform';
$attrib['action'] = './';
$attrib['method'] = 'post';
$out = html::tag('form', $attrib, $out, array('name', 'action', 'method', 'class'));
if (!$compact) {
$out = str_replace('</form>', '', $out);
}
return $out;
}
function rule_div($fid, $id, $div = true, $compact = false)
{
$rule = isset($this->form) ? $this->form['tests'][$id] : $this->script[$fid]['tests'][$id];
if (isset($this->form['tests'])) {
$rows_num = count($this->form['tests']);
}
else if (isset($this->script[$fid]['tests'])) {
$rows_num = count($this->script[$fid]['tests']);
}
else {
$rows_num = 0;
}
// headers select
$select_header = new html_select(array('name' => "_header[$id]", 'id' => 'header'.$id,
'onchange' => 'rule_header_select(' .$id .')'));
foreach ($this->headers as $index => $header) {
$header = $this->rc->text_exists($index) ? $this->plugin->gettext($index) : $header;
$select_header->add($header, $index);
}
$select_header->add($this->plugin->gettext('...'), '...');
if (in_array('body', $this->exts)) {
$select_header->add($this->plugin->gettext('body'), 'body');
}
$select_header->add($this->plugin->gettext('size'), 'size');
if (in_array('date', $this->exts)) {
$select_header->add($this->plugin->gettext('datetest'), 'date');
$select_header->add($this->plugin->gettext('currdate'), 'currentdate');
}
if (in_array('variables', $this->exts)) {
$select_header->add($this->plugin->gettext('string'), 'string');
}
if (in_array('duplicate', $this->exts)) {
$select_header->add($this->plugin->gettext('message'), 'message');
}
if (isset($rule['test'])) {
if (in_array($rule['test'], array('header', 'address', 'envelope'))) {
if (is_array($rule['arg1']) && count($rule['arg1']) == 1) {
$rule['arg1'] = $rule['arg1'][0];
}
$matches = !is_array($rule['arg1']) && ($header = strtolower($rule['arg1'])) && isset($this->headers[$header]);
$test = $matches ? $header : '...';
}
else if ($rule['test'] == 'exists') {
if (is_array($rule['arg']) && count($rule['arg']) == 1) {
$rule['arg'] = $rule['arg'][0];
}
$matches = !is_array($rule['arg']) && ($header = strtolower($rule['arg'])) && isset($this->headers[$header]);
$test = $matches ? $header : '...';
}
else if (in_array($rule['test'], array('size', 'body', 'date', 'currentdate', 'string'))) {
$test = $rule['test'];
}
else if (in_array($rule['test'], array('duplicate'))) {
$test = 'message';
}
else if ($rule['test'] != 'true') {
$test = '...';
}
}
$tout = '<div class="flexbox">';
$aout = $select_header->show($test);
// custom headers input
if (isset($rule['test']) && in_array($rule['test'], array('header', 'address', 'envelope'))) {
$custom = (array) $rule['arg1'];
if (count($custom) == 1 && isset($this->headers[strtolower($custom[0])])) {
unset($custom);
}
}
else if (isset($rule['test']) && $rule['test'] == 'string') {
$customv = (array) $rule['arg1'];
if (count($customv) == 1 && isset($this->headers[strtolower($customv[0])])) {
unset($customv);
}
}
else if (isset($rule['test']) && $rule['test'] == 'exists') {
$custom = (array) $rule['arg'];
if (count($custom) == 1 && isset($this->headers[strtolower($custom[0])])) {
unset($custom);
}
}
// custom header and variable inputs
$aout .= $this->list_input($id, 'custom_header', $custom, isset($custom),
$this->error_class($id, 'test', 'header', 'custom_header'), 15) . "\n";
$aout .= $this->list_input($id, 'custom_var', $customv, isset($customv),
$this->error_class($id, 'test', 'header', 'custom_var'), 15) . "\n";
$test = self::rule_test($rule);
$target = '';
// target(s) input
if (in_array($rule['test'], array('header', 'address', 'envelope','string'))) {
$target = $rule['arg2'];
}
else if (in_array($rule['test'], array('body', 'date', 'currentdate'))) {
$target = $rule['arg'];
}
else if ($rule['test'] == 'size') {
if (preg_match('/^([0-9]+)(K|M|G)?$/', $rule['arg'], $matches)) {
$sizetarget = $matches[1];
$sizeitem = $matches[2];
}
else {
$sizetarget = $rule['arg'];
$sizeitem = $rule['item'];
}
}
// (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]", '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);
}
$aout .= $select_dp->show($rule['test'] == 'currentdate' || $rule['test'] == 'date' ? $rule['part'] : '');
}
// message test select (e.g. duplicate)
if (in_array('duplicate', $this->exts)) {
$select_msg = new html_select(array('name' => "_rule_message[$id]", 'id' => 'rule_message'.$id,
'style' => in_array($rule['test'], array('duplicate')) ? '' : 'display:none',
'class' => 'message_selector',
));
$select_msg->add(rcube::Q($this->plugin->gettext('duplicate')), 'duplicate');
$select_msg->add(rcube::Q($this->plugin->gettext('notduplicate')), 'notduplicate');
$tout .= $select_msg->show($test);
}
$tout .= $this->match_type_selector('rule_op', $id, $test, $rule['test']);
$tout .= $this->list_input($id, 'rule_target', $target,
$rule['test'] != 'size' && $rule['test'] != 'exists' && $rule['test'] != 'duplicate',
$this->error_class($id, 'test', 'target', 'rule_target')) . "\n";
$select_size_op = new html_select(array('name' => "_rule_size_op[$id]", 'id' => 'rule_size_op'.$id, 'class' => 'input-group-prepend'));
$select_size_op->add(rcube::Q($this->plugin->gettext('filterover')), 'over');
$select_size_op->add(rcube::Q($this->plugin->gettext('filterunder')), 'under');
$select_size_item = new html_select(array('name' => "_rule_size_item[$id]", 'id' => 'rule_size_item'.$id, 'class' => 'input-group-append'));
foreach (array('', 'K', 'M', 'G') as $unit) {
$select_size_item->add($this->plugin->gettext($unit . 'B'), $unit);
}
$tout .= '<div id="rule_size' .$id. '" class="input-group" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">';
$tout .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : '');
$tout .= html::tag('input', array(
'type' => 'text',
'name' => "_rule_size_target[$id]",
'id' => 'rule_size_i'.$id,
'value' => $sizetarget,
'size' => 10,
'class' => $this->error_class($id, 'test', 'sizetarget', 'rule_size_i'),
));
$tout .= "\n" . $select_size_item->show($sizeitem);
$tout .= '</div>';
$tout .= '</div>';
// Advanced modifiers (address, envelope)
$select_mod = new html_select(array('name' => "_rule_mod[$id]", 'id' => 'rule_mod_op'.$id,
'onchange' => 'rule_mod_select(' .$id .')'));
$select_mod->add(rcube::Q($this->plugin->gettext('none')), '');
$select_mod->add(rcube::Q($this->plugin->gettext('address')), 'address');
if (in_array('envelope', $this->exts)) {
$select_mod->add(rcube::Q($this->plugin->gettext('envelope')), 'envelope');
}
$select_type = new html_select(array('name' => "_rule_mod_type[$id]", 'id' => 'rule_mod_type'.$id));
$select_type->add(rcube::Q($this->plugin->gettext('allparts')), 'all');
$select_type->add(rcube::Q($this->plugin->gettext('domain')), 'domain');
$select_type->add(rcube::Q($this->plugin->gettext('localpart')), 'localpart');
if (in_array('subaddress', $this->exts)) {
$select_type->add(rcube::Q($this->plugin->gettext('user')), 'user');
$select_type->add(rcube::Q($this->plugin->gettext('detail')), 'detail');
}
$need_mod = !in_array($rule['test'], array('size', 'body', 'date', 'currentdate', 'duplicate', 'string'));
$mout = '<div id="rule_mod' .$id. '" class="adv input-group"' . (!$need_mod ? ' style="display:none"' : '') . '>';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('modifier'))));
$mout .= $select_mod->show($rule['test']);
$mout .= '</div>';
$mout .= '<div id="rule_mod_type' . $id . '" class="adv input-group"';
$mout .= (!in_array($rule['test'], array('address', 'envelope')) ? ' style="display:none"' : '') . '>';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('modtype'))));
$mout .= $select_type->show($rule['part']);
$mout .= '</div>';
// Advanced modifiers (comparators)
$need_comp = $rule['test'] != 'size' && $rule['test'] != 'duplicate';
$mout .= '<div id="rule_comp' .$id. '" class="adv input-group"' . (!$need_comp ? ' style="display:none"' : '') . '>';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('comparator'))));
$mout .= $this->comparator_selector($rule['comparator'], 'rule_comp', $id);
$mout .= '</div>';
// Advanced modifiers (mime)
if (in_array('mime', $this->exts)) {
$need_mime = !$rule || in_array($rule['test'], array('header', 'address', 'exists'));
$mime_type = '';
$select_mime = new html_select(array('name' => "_rule_mime_type[$id]", 'id' => 'rule_mime_type' . $id,
'style' => 'min-width:8em', 'onchange' => 'rule_mime_select(' . $id . ')'));
$select_mime->add('-', '');
foreach (array('contenttype', 'type', 'subtype', 'param') as $val) {
if (isset($rule['mime-' . $val])) {
$mime_type = $val;
}
$select_mime->add(rcube::Q($this->plugin->gettext('mime-' . $val)), $val);
}
$select_mime_part = new html_select(array('name' => "_rule_mime_part[$id]", 'id' => 'rule_mime_part' . $id));
$select_mime_part->add(rcube::Q($this->plugin->gettext('mime-message')), '');
$select_mime_part->add(rcube::Q($this->plugin->gettext('mime-anychild')), 'anychild');
$mout .= '<div id="rule_mime_part' .$id. '" class="adv input-group"' . (!$need_mime ? ' style="display:none"' : '') . '>';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('mimepart'))));
$mout .= $select_mime_part->show(!empty($rule['mime-anychild']) ? 'anychild' : '');
$mout .= '</div>';
$mout .= '<div id="rule_mime' .$id. '" class="adv input-group"' . (!$need_mime ? ' style="display:none"' : '') . '>';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('mime'))));
$mout .= $select_mime->show($mime_type);
$mout .= $this->list_input($id, 'rule_mime_param', $rule['mime-param'], true,
$this->error_class($id, 'test', 'mime_param', 'rule_mime_param'), 30, $mime_type != 'param');
$mout .= '</div>';
}
// Advanced modifiers (body transformations)
$select_mod = new html_select(array('name' => "_rule_trans[$id]", 'id' => 'rule_trans_op'.$id,
'onchange' => 'rule_trans_select(' .$id .')'));
$select_mod->add(rcube::Q($this->plugin->gettext('text')), 'text');
$select_mod->add(rcube::Q($this->plugin->gettext('undecoded')), 'raw');
$select_mod->add(rcube::Q($this->plugin->gettext('contenttype')), 'content');
$mout .= '<div id="rule_trans' .$id. '" class="adv input-group"' . ($rule['test'] != 'body' ? ' style="display:none"' : '') . '>';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('modifier'))));
$mout .= $select_mod->show($rule['part']);
$mout .= html::tag('input', array(
'type' => 'text',
'name' => "_rule_trans_type[$id]",
'id' => 'rule_trans_type'.$id,
'value' => is_array($rule['content']) ? implode(',', $rule['content']) : $rule['content'],
'size' => 20,
'style' => $rule['part'] != 'content' ? 'display:none' : '',
'class' => $this->error_class($id, 'test', 'part', 'rule_trans_type'),
));
$mout .= '</div>';
// Date header
if (in_array('date', $this->exts)) {
$mout .= '<div id="rule_date_header_div' .$id. '" class="adv input-group"'. ($rule['test'] != 'date' ? ' style="display:none"' : '') .'>';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('dateheader'))));
$mout .= html::tag('input', array(
'type' => 'text',
'name' => "_rule_date_header[$id]",
'id' => 'rule_date_header' . $id,
'value' => $rule['test'] == 'date' ? $rule['header'] : '',
'size' => 15,
'class' => $this->error_class($id, 'test', 'dateheader', 'rule_date_header'),
));
$mout .= '</div>';
}
// Index
if (in_array('index', $this->exts)) {
$need_index = in_array($rule['test'], array('header', ', address', 'date'));
$mout .= '<div id="rule_index_div' .$id. '" class="adv input-group"'. (!$need_index ? ' style="display:none"' : '') .'>';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('index'))));
$mout .= html::tag('input', array(
'type' => 'text',
'name' => "_rule_index[$id]",
'id' => 'rule_index' . $id,
'value' => $rule['index'] ? intval($rule['index']) : '',
'size' => 3,
'class' => $this->error_class($id, 'test', 'index', 'rule_index'),
));
$mout .= html::label('input-group-append',
html::tag('input', array(
'type' => 'checkbox',
'name' => "_rule_index_last[$id]",
'id' => 'rule_index_last' . $id,
'value' => 1,
'checked' => !empty($rule['last']),
)) . rcube::Q($this->plugin->gettext('indexlast')));
$mout .= '</div>';
}
// Duplicate
if (in_array('duplicate', $this->exts)) {
$need_duplicate = $rule['test'] == 'duplicate';
$mout .= '<div id="rule_duplicate_div' .$id. '" class="adv"'. (!$need_duplicate ? ' style="display:none"' : '') .'>';
foreach (array('handle', 'header', 'uniqueid') as $unit) {
$mout .= '<div class="input-group">';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('duplicate.' . $unit))));
$mout .= html::tag('input', array(
'type' => 'text',
'name' => '_rule_duplicate_' . $unit . "[$id]",
'id' => 'rule_duplicate_' . $unit . $id,
'value' => $rule[$unit],
'size' => 30,
'class' => $this->error_class($id, 'test', 'duplicate_' . $unit, 'rule_duplicate_' . $unit),
));
$mout .= '</div>';
}
$mout .= '<div class="input-group">';
$mout .= html::span('label input-group-prepend', html::span('input-group-text', rcube::Q($this->plugin->gettext('duplicate.seconds'))));
$mout .= html::tag('input', array(
'type' => 'text',
'name' => "_rule_duplicate_seconds[$id]",
'id' => 'rule_duplicate_seconds' . $id,
'value' => $rule['seconds'],
'size' => 6,
'class' => $this->error_class($id, 'test', 'duplicate_seconds', 'rule_duplicate_seconds'),
));
$mout .= html::label('input-group-append',
html::tag('input', array(
'type' => 'checkbox',
'name' => '_rule_duplicate_last[' . $id . ']',
'id' => 'rule_duplicate_last' . $id,
'value' => 1,
'checked' => !empty($rule['last']),
)) . rcube::Q($this->plugin->gettext('duplicate.last')));
$mout .= '</div>';
$mout .= '</div>';
}
$add_title = rcube::Q($this->plugin->gettext('add'));
$del_title = rcube::Q($this->plugin->gettext('del'));
$adv_title = rcube::Q($this->plugin->gettext('advancedopts'));
// Build output table
$out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : '';
$out .= '<table class="compact-table"><tr>';
if (!$compact) {
$out .= '<td class="advbutton">';
$out .= sprintf('<a href="#" id="ruleadv%s" title="%s" onclick="rule_adv_switch(%s, this); return false" class="show">'
. '<span class="inner">%s</span></a>', $id, $adv_title, $id, $adv_title);
$out .= '</td>';
}
$out .= '<td class="rowactions"><div class="flexbox">' . $aout . '</div></td>';
$out .= '<td class="rowtargets">' . $tout . "\n";
$out .= '<div id="rule_advanced' .$id. '" style="display:none" class="advanced">' . $mout . '</div>';
$out .= '</td>';
$out .= '<td class="rowbuttons">';
if ($compact) {
$out .= sprintf('<a href="#" id="ruleadv%s" title="%s" onclick="rule_adv_switch(%s, this); return false" class="advanced show">'
. '<span class="inner">%s</span></a>', $id, $adv_title, $id, $adv_title);
}
$out .= sprintf('<a href="#" id="ruleadd%s" title="%s" onclick="rcmail.managesieve_ruleadd(\'%s\'); return false" class="button create add">'
. '<span class="inner">%s</span></a>', $id, $add_title, $id, $add_title);
$out .= sprintf('<a href="#" id="ruledel%s" title="%s" onclick="rcmail.managesieve_ruledel(\'%s\'); return false" class="button delete del%s">'
. '<span class="inner">%s</span></a>', $id, $del_title, $id, ($rows_num < 2 ? ' disabled' : ''), $del_title);
$out .= '</td>';
$out .= '</tr></table>';
$out .= $div ? "</div>\n" : '';
return $out;
}
private static function rule_test(&$rule)
{
// first modify value/count tests with 'not' keyword
// we'll revert the meaning of operators
if ($rule['not'] && preg_match('/^(count|value)-([gteqnl]{2})/', $rule['type'], $m)) {
$rule['not'] = false;
switch ($m[2]) {
case 'gt': $rule['type'] = $m[1] . '-le'; break;
case 'ge': $rule['type'] = $m[1] . '-lt'; break;
case 'lt': $rule['type'] = $m[1] . '-ge'; break;
case 'le': $rule['type'] = $m[1] . '-gt'; break;
case 'eq': $rule['type'] = $m[1] . '-ne'; break;
case 'ne': $rule['type'] = $m[1] . '-eq'; break;
}
}
else if ($rule['not'] && $rule['test'] == 'size') {
$rule['not'] = false;
$rule['type'] = $rule['type'] == 'over' ? 'under' : 'over';
}
$set = array('header', 'address', 'envelope', 'body', 'date', 'currentdate', 'string');
// build test string supported by select element
if ($rule['size']) {
$test = $rule['type'];
}
else if (in_array($rule['test'], $set)) {
$test = ($rule['not'] ? 'not' : '') . ($rule['type'] ?: 'is');
}
else {
$test = ($rule['not'] ? 'not' : '') . $rule['test'];
}
return $test;
}
function action_div($fid, $id, $div=true)
{
$action = isset($this->form) ? $this->form['actions'][$id] : $this->script[$fid]['actions'][$id];
if (isset($this->form['actions'])) {
$rows_num = count($this->form['actions']);
}
else if (isset($this->script[$fid]['actions'])) {
$rows_num = count($this->script[$fid]['actions']);
}
else {
$rows_num = 0;
}
$out = $div ? '<div class="actionrow" id="actionrow' .$id .'">'."\n" : '';
$out .= '<table class="compact-table"><tr><td class="rowactions">';
// action select
$select_action = new html_select(array('name' => "_action_type[$id]", 'id' => 'action_type'.$id,
'onchange' => 'action_type_select(' .$id .')'));
if (in_array('fileinto', $this->exts))
$select_action->add($this->plugin->gettext('messagemoveto'), 'fileinto');
if (in_array('fileinto', $this->exts) && in_array('copy', $this->exts))
$select_action->add($this->plugin->gettext('messagecopyto'), 'fileinto_copy');
$select_action->add($this->plugin->gettext('messageredirect'), 'redirect');
if (in_array('copy', $this->exts))
$select_action->add($this->plugin->gettext('messagesendcopy'), 'redirect_copy');
if (in_array('reject', $this->exts))
$select_action->add($this->plugin->gettext('messagediscard'), 'reject');
else if (in_array('ereject', $this->exts))
$select_action->add($this->plugin->gettext('messagediscard'), 'ereject');
if (in_array('vacation', $this->exts))
$select_action->add($this->plugin->gettext('messagereply'), 'vacation');
$select_action->add($this->plugin->gettext('messagedelete'), 'discard');
if (in_array('imapflags', $this->exts) || in_array('imap4flags', $this->exts)) {
$select_action->add($this->plugin->gettext('setflags'), 'setflag');
$select_action->add($this->plugin->gettext('addflags'), 'addflag');
$select_action->add($this->plugin->gettext('removeflags'), 'removeflag');
}
if (in_array('editheader', $this->exts)) {
$select_action->add($this->plugin->gettext('addheader'), 'addheader');
$select_action->add($this->plugin->gettext('deleteheader'), 'deleteheader');
}
if (in_array('variables', $this->exts)) {
$select_action->add($this->plugin->gettext('setvariable'), 'set');
}
if (in_array('enotify', $this->exts) || in_array('notify', $this->exts)) {
$select_action->add($this->plugin->gettext('notify'), 'notify');
}
$select_action->add($this->plugin->gettext('messagekeep'), 'keep');
$select_action->add($this->plugin->gettext('rulestop'), 'stop');
$select_type = $action['type'];
if (in_array($action['type'], array('fileinto', 'redirect')) && $action['copy']) {
$select_type .= '_copy';
}
$out .= $select_action->show($select_type);
$out .= '</td>';
// actions target inputs
$out .= '<td class="rowtargets">';
// force domain selection in redirect email input
$domains = (array) $this->rc->config->get('managesieve_domains');
if (!empty($domains)) {
sort($domains);
$domain_select = new html_select(array('name' => "_action_target_domain[$id]", 'id' => 'action_target_domain'.$id));
$domain_select->add(array_combine($domains, $domains));
if ($action['type'] == 'redirect') {
$parts = explode('@', $action['target']);
if (!empty($parts)) {
$action['domain'] = array_pop($parts);
$action['target'] = implode('@', $parts);
}
}
}
// redirect target
$out .= '<span id="redirect_target' . $id . '" style="white-space:nowrap;'
. ' display:' . ($action['type'] == 'redirect' ? 'inline' : 'none') . '">'
. html::tag('input', array(
'type' => 'text',
'name' => '_action_target[' . $id . ']',
'id' => 'action_target' . $id,
'value' => $action['type'] == 'redirect' ? $action['target'] : '',
'size' => !empty($domains) ? 20 : 35,
'class' => $this->error_class($id, 'action', 'target', 'action_target'),
));
$out .= !empty($domains) ? ' @ ' . $domain_select->show($action['domain']) : '';
$out .= '</span>';
// (e)reject target
$out .= html::tag('textarea', array(
'name' => '_action_target_area[' . $id . ']',
'id' => 'action_target_area' . $id,
'rows' => 3,
'cols' => 35,
'class' => $this->error_class($id, 'action', 'targetarea', 'action_target_area'),
'style' => 'display:' . (in_array($action['type'], array('reject', 'ereject')) ? 'inline' : 'none'),
), (in_array($action['type'], array('reject', 'ereject')) ? rcube::Q($action['target'], 'strict', false) : ''));
// vacation
$vsec = in_array('vacation-seconds', $this->exts);
$auto_addr = $this->rc->config->get('managesieve_vacation_addresses_init');
$from_addr = $this->rc->config->get('managesieve_vacation_from_init');
if (empty($action)) {
if ($auto_addr) {
$action['addresses'] = $this->user_emails();
}
if ($from_addr) {
$default_identity = $this->rc->user->list_emails(true);
$action['from'] = $default_identity['email'];
}
}
$out .= '<div id="action_vacation' .$id.'" style="display:' .($action['type']=='vacation' ? 'inline' : 'none') .'" class="composite">';
$out .= '<span class="label">'. rcube::Q($this->plugin->gettext('vacationreason')) .'</span><br>';
$out .= html::tag('textarea', array(
'name' => '_action_reason[' . $id . ']',
'id' => 'action_reason' . $id,
'rows' => 3,
'cols' => 35,
'class' => $this->error_class($id, 'action', 'reason', 'action_reason'),
), rcube::Q($action['reason'], 'strict', false));
$out .= '<br><span class="label">' .rcube::Q($this->plugin->gettext('vacationsubject')) . '</span><br>';
$out .= html::tag('input', array(
'type' => 'text',
'name' => '_action_subject[' . $id . ']',
'id' => 'action_subject' . $id,
'value' => is_array($action['subject']) ? implode(', ', $action['subject']) : $action['subject'],
'size' => 35,
'class' => $this->error_class($id, 'action', 'subject', 'action_subject'),
));
$out .= '<br><span class="label">' .rcube::Q($this->plugin->gettext('vacationfrom')) . '</span><br>';
$out .= html::tag('input', array(
'type' => 'text',
'name' => '_action_from[' . $id . ']',
'id' => 'action_from' . $id,
'value' => $action['from'],
'size' => 35,
'class' => $this->error_class($id, 'action', 'from', 'action_from'),
));
$out .= '<br><span class="label">' .rcube::Q($this->plugin->gettext('vacationaddr')) . '</span><br>';
$out .= $this->list_input($id, 'action_addresses', $action['addresses'], true,
$this->error_class($id, 'action', 'addresses', 'action_addresses'), 30)
. html::a(array('href' => '#', 'onclick' => rcmail_output::JS_OBJECT_NAME . ".managesieve_vacation_addresses($id)"),
rcube::Q($this->plugin->gettext('filladdresses')));
$out .= '<br><span class="label">' . rcube::Q($this->plugin->gettext('vacationinterval')) . '</span><br>';
$out .= '<div class="input-group">' . html::tag('input', array(
'type' => 'text',
'name' => '_action_interval[' . $id . ']',
'id' => 'action_interval' . $id,
'value' => rcube_sieve_vacation::vacation_interval($action),
'size' => 2,
'class' => $this->error_class($id, 'action', 'interval', 'action_interval'),
));
if ($vsec) {
$interval_select = new html_select(array('name' => '_action_interval_type[' . $id . ']', 'class' => 'input-group-append'));
$interval_select->add($this->plugin->gettext('days'), 'days');
$interval_select->add($this->plugin->gettext('seconds'), 'seconds');
$out .= $interval_select->show(isset($action['seconds']) ? 'seconds' : 'days');
}
else {
$out .= "\n" . html::span('input-group-append', html::span('input-group-text', $this->plugin->gettext('days')));
}
$out .= '</div></div>';
// flags
$flags = array(
'read' => '\\Seen',
'answered' => '\\Answered',
'flagged' => '\\Flagged',
'deleted' => '\\Deleted',
'draft' => '\\Draft',
);
$flags_target = (array) $action['target'];
$custom_flags = array();
$is_flag_action = preg_match('/^(set|add|remove)flag$/', $action['type']);
if ($is_flag_action) {
$custom_flags = array_filter($flags_target, function($v) use($flags) {
return !in_array_nocase($v, $flags);
});
}
$flout = '';
foreach ($flags as $fidx => $flag) {
$flout .= html::label(null, html::tag('input', array(
'type' => 'checkbox',
'name' => "_action_flags[$id][]",
'value' => $flag,
'checked' => $is_flag_action && in_array_nocase($flag, $flags_target),
))
. rcube::Q($this->plugin->gettext('flag'.$fidx))) . '<br>';
}
$flout .= $this->list_input($id, 'action_flags', $custom_flags, true,
$this->error_class($id, 'action', 'flags', 'action_flags'));
$out .= html::div(array(
'id' => 'action_flags' . $id,
'style' => 'display:' . ($is_flag_action ? 'inline' : 'none'),
'class' => trim('checklist ' . $this->error_class($id, 'action', 'flags', 'action_flags')),
), $flout);
// set variable
$set_modifiers = array(
'lower',
'upper',
'lowerfirst',
'upperfirst',
'quotewildcard',
'length'
);
$out .= '<div id="action_set' .$id.'" style="display:' .($action['type']=='set' ? 'inline' : 'none') .'">';
foreach (array('name', 'value') as $unit) {
$out .= '<span class="label">' .rcube::Q($this->plugin->gettext('setvar' . $unit)) . '</span><br>';
$out .= html::tag('input', array(
'type' => 'text',
'name' => '_action_var' . $unit . '[' . $id . ']',
'id' => 'action_var' . $unit . $id,
'value' => $action[$unit],
'size' => 35,
'class' => $this->error_class($id, 'action', $unit, 'action_var' . $unit),
));
$out .= '<br>';
}
$out .= '<span class="label">' .rcube::Q($this->plugin->gettext('setvarmodifiers')) . '</span>';
foreach ($set_modifiers as $s_m) {
$s_m_id = 'action_varmods' . $id . $s_m;
$out .= '<br>' . html::tag('input', array(
'type' => 'checkbox',
'name' => "_action_varmods[$id][]",
'value' => $s_m,
'id' => $s_m_id,
'checked' => array_key_exists($s_m, (array)$action) && $action[$s_m],
))
.rcube::Q($this->plugin->gettext('var' . $s_m));
}
$out .= '</div>';
// notify
$notify_methods = (array) $this->rc->config->get('managesieve_notify_methods');
$importance_options = $this->notify_importance_options;
if (empty($notify_methods)) {
$notify_methods = $this->notify_methods;
}
list($method, $target) = explode(':', $action['method'], 2);
$method = strtolower($method);
if ($method && !in_array($method, $notify_methods)) {
$notify_methods[] = $method;
}
$select_method = new html_select(array(
'name' => "_action_notifymethod[$id]",
'id' => "_action_notifymethod$id",
'class' => 'input-group-prepend ' . $this->error_class($id, 'action', 'method', 'action_notifymethod'),
));
foreach ($notify_methods as $m_n) {
$select_method->add(rcube::Q($this->rc->text_exists('managesieve.notifymethod'.$m_n) ? $this->plugin->gettext('managesieve.notifymethod'.$m_n) : $m_n), $m_n);
}
$select_importance = new html_select(array(
'name' => "_action_notifyimportance[$id]",
'id' => "_action_notifyimportance$id",
'class' => $this->error_class($id, 'action', 'importance', 'action_notifyimportance')
));
foreach ($importance_options as $io_v => $io_n) {
$select_importance->add(rcube::Q($this->plugin->gettext($io_n)), $io_v);
}
// @TODO: nice UI for mailto: (other methods too) URI parameters
$out .= '<div id="action_notify' .$id.'" style="display:' .($action['type'] == 'notify' ? 'inline' : 'none') .'" class="composite">';
$out .= '<span class="label">' .rcube::Q($this->plugin->gettext('notifytarget')) . '</span><br>';
$out .= '<div class="input-group">';
$out .= $select_method->show($method);
$out .= html::tag('input', array(
'type' => 'text',
'name' => '_action_notifytarget[' . $id . ']',
'id' => 'action_notifytarget' . $id,
'value' => $target,
'size' => 25,
'class' => $this->error_class($id, 'action', 'target', 'action_notifytarget'),
));
$out .= '</div>';
$out .= '<br><span class="label">'. rcube::Q($this->plugin->gettext('notifymessage')) .'</span><br>';
$out .= html::tag('textarea', array(
'name' => '_action_notifymessage[' . $id . ']',
'id' => 'action_notifymessage' . $id,
'rows' => 3,
'cols' => 35,
'class' => $this->error_class($id, 'action', 'message', 'action_notifymessage'),
), rcube::Q($action['message'], 'strict', false));
if (in_array('enotify', $this->exts)) {
$out .= '<br><span class="label">' .rcube::Q($this->plugin->gettext('notifyfrom')) . '</span><br>';
$out .= html::tag('input', array(
'type' => 'text',
'name' => '_action_notifyfrom[' . $id . ']',
'id' => 'action_notifyfrom' . $id,
'value' => $action['from'],
'size' => 35,
'class' => $this->error_class($id, 'action', 'from', 'action_notifyfrom'),
));
}
$out .= '<br><span class="label">' . rcube::Q($this->plugin->gettext('notifyimportance')) . '</span><br>';
$out .= $select_importance->show($action['importance'] ? (int) $action['importance'] : 2);
$out .= '<div id="action_notifyoption_div' . $id . '">'
.'<span class="label">' . rcube::Q($this->plugin->gettext('notifyoptions')) . '</span><br>'
.$this->list_input($id, 'action_notifyoption', (array)$action['options'], true,
$this->error_class($id, 'action', 'options', 'action_notifyoption'), 30) . '</div>';
$out .= '</div>';
if (in_array('editheader', $this->exts)) {
$action['pos'] = $action['last'] ? 'last' : '';
$pos1_selector = new html_select(array(
'name' => "_action_addheader_pos[$id]",
'id' => "action_addheader_pos$id",
'class' => $this->error_class($id, 'action', 'pos', 'action_addheader_pos')
));
$pos1_selector->add($this->plugin->gettext('headeratstart'), '');
$pos1_selector->add($this->plugin->gettext('headeratend'), 'last');
$pos2_selector = new html_select(array(
'name' => "_action_delheader_pos[$id]",
'id' => "action_delheader_pos$id",
'class' => $this->error_class($id, 'action', 'pos', 'action_delheader_pos')
));
$pos2_selector->add($this->plugin->gettext('headerfromstart'), '');
$pos2_selector->add($this->plugin->gettext('headerfromend'), 'last');
// addheader
$out .= '<div id="action_addheader' .$id.'" style="display:' .($action['type'] == 'addheader' ? 'inline' : 'none') .'" class="composite">';
$out .= '<label class="label" for="action_addheader_name' . $id .'">' .rcube::Q($this->plugin->gettext('headername')) . '</label><br>';
$out .= html::tag('input', array(
'type' => 'text',
'name' => '_action_addheader_name[' . $id . ']',
'id' => 'action_addheader_name' . $id,
'value' => $action['name'],
'size' => 35,
'class' => $this->error_class($id, 'action', 'name', 'action_addheader_name'),
));
$out .= '<br><label class="label" for="action_addheader_value' . $id .'">'. rcube::Q($this->plugin->gettext('headervalue')) .'</label><br>';
$out .= html::tag('input', array(
'type' => 'text',
'name' => '_action_addheader_value[' . $id . ']',
'id' => 'action_addheader_value' . $id,
'value' => $action['value'],
'size' => 35,
'class' => $this->error_class($id, 'action', 'value', 'action_addheader_value'),
));
$out .= '<br><label class="label" for="action_addheader_pos' . $id .'">'. rcube::Q($this->plugin->gettext('headerpos')) .'</label><br>';
$out .= $pos1_selector->show($action['pos']);
$out .= '</div>';
// deleteheader
$out .= '<div id="action_deleteheader' .$id.'" style="display:' .($action['type'] == 'deleteheader' ? 'inline' : 'none') .'" class="composite">';
$out .= '<label class="label" for="action_delheader_name' . $id .'">' .rcube::Q($this->plugin->gettext('headername')) . '</label><br>';
$out .= html::tag('input', array(
'type' => 'text',
'name' => '_action_delheader_name[' . $id . ']',
'id' => 'action_delheader_name' . $id,
'value' => $action['name'],
'size' => 35,
'class' => $this->error_class($id, 'action', 'name', 'action_delheader_name'),
));
$out .= '<br><label class="label" for="action_delheader_value' . $id .'">'. rcube::Q($this->plugin->gettext('headerpatterns')) .'</label><br>';
$out .= $this->list_input($id, 'action_delheader_value', $action['value'], true,
$this->error_class($id, 'action', 'value', 'action_delheader_value')) . "\n";
$out .= '<br><div class="adv input-group">';
$out .= html::span('label input-group-prepend', html::label(array(
'class' => 'input-group-text', 'for' => 'action_delheader_op'.$id), rcube::Q($this->plugin->gettext('headermatchtype'))));
$out .= $this->match_type_selector('action_delheader_op', $id, $action['match-type'], null, 'basic');
$out .= '</div>';
$out .= '<div class="adv input-group">';
$out .= html::span('label input-group-prepend', html::label(array(
'class' => 'input-group-text', 'for' => 'action_delheader_comp_op'.$id), rcube::Q($this->plugin->gettext('comparator'))));
$out .= $this->comparator_selector($action['comparator'], 'action_delheader_comp', $id);
$out .= '</div>';
$out .= '<br><label class="label" for="action_delheader_index' . $id .'">'. rcube::Q($this->plugin->gettext('headeroccurrence')) .'</label><br>';
$out .= '<div class="input-group">';
$out .= html::tag('input', array(
'type' => 'text',
'name' => '_action_delheader_index[' . $id . ']',
'id' => 'action_delheader_index' . $id,
'value' => $action['index'] ? intval($action['index']) : '',
'size' => 5,
'class' => $this->error_class($id, 'action', 'index', 'action_delheader_index'),
));
$out .= ' ' . $pos2_selector->show($action['pos']);
$out .= '</div></div>';
}
// mailbox select
if ($action['type'] == 'fileinto') {
// make sure non-existing (or unsubscribed) mailbox is listed (#1489956)
if ($mailbox = $this->mod_mailbox($action['target'], 'out')) {
$additional = array($mailbox);
}
}
else {
$mailbox = '';
}
$select = $this->rc->folder_selector(array(
'maxlength' => 100,
'id' => 'action_mailbox' . $id,
'name' => "_action_mailbox[$id]",
'style' => 'display:'.(empty($action['type']) || $action['type'] == 'fileinto' ? 'inline' : 'none'),
'additional' => $additional,
));
$out .= $select->show($mailbox);
$out .= '</td>';
// add/del buttons
$add_label = rcube::Q($this->plugin->gettext('add'));
$del_label = rcube::Q($this->plugin->gettext('del'));
$out .= '<td class="rowbuttons">';
$out .= sprintf('<a href="#" id="actionadd%s" title="%s" onclick="rcmail.managesieve_actionadd(%s)" class="button create add">'
. '<span class="inner">%s</span></a>', $id, $add_label, $id, $add_label);
$out .= sprintf('<a href="#" id="actiondel%s" title="%s" onclick="rcmail.managesieve_actiondel(%s)" class="button delete del%s">'
. '<span class="inner">%s</span></a>', $id, $del_label, $id, ($rows_num < 2 ? ' disabled' : ''), $del_label);
$out .= '</td>';
$out .= '</tr></table>';
$out .= $div ? "</div>\n" : '';
return $out;
}
protected function genid()
{
return preg_replace('/[^0-9]/', '', microtime(true));
}
protected function strip_value($str, $allow_html = false, $trim = true)
{
if (is_array($str)) {
foreach ($str as $idx => $val) {
$val = $this->strip_value($val, $allow_html, $trim);
if ($val === '') {
unset($str[$idx]);
}
}
return $str;
}
if (!$allow_html) {
$str = strip_tags($str);
}
return $trim ? trim($str) : $str;
}
protected 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 'error';
}
return '';
}
protected function add_tip($id, $str, $error=false)
{
if ($error) {
$class = 'sieve error';
}
$this->tips[] = array($id, $class ?: '', $str);
}
protected function print_tips()
{
if (empty($this->tips)) {
return;
}
$script = rcmail_output::JS_OBJECT_NAME.'.managesieve_tip_register('.json_encode($this->tips).');';
$this->rc->output->add_script($script, 'docready');
}
protected function list_input($id, $name, $value, $enabled, $class, $size = null, $hidden = false)
{
$value = (array) $value;
$value = array_map(array('rcube', 'Q'), $value);
$value = implode("\n", $value);
return html::tag('textarea', array(
'data-type' => 'list',
'data-size' => $size,
'data-hidden' => $hidden ?: null,
'name' => '_' . $name . '[' . $id . ']',
'id' => $name.$id,
'disabled' => !$enabled,
'class' => $class,
'style' => 'display:none',
), $value);
}
/**
* Validate input for date part elements
*/
protected function validate_date_part($type, $value)
{
// we do simple validation of date/part format
switch ($type) {
case 'date': // yyyy-mm-dd
return preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $value);
case 'iso8601':
return preg_match('/^[0-9: .,ZWT+-]+$/', $value);
case 'std11':
return preg_match('/^((Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s+)?[0-9]{1,2}\s+'
. '(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+[0-9]{2,4}\s+'
. '[0-9]{2}:[0-9]{2}(:[0-9]{2})?\s+([+-]*[0-9]{4}|[A-Z]{1,3})$', $value);
case 'julian':
return preg_match('/^[0-9]+$/', $value);
case 'time': // hh:mm:ss
return preg_match('/^[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $value);
case 'year':
return preg_match('/^[0-9]{4}$/', $value);
case 'month':
return preg_match('/^[0-9]{2}$/', $value) && $value > 0 && $value < 13;
case 'day':
return preg_match('/^[0-9]{2}$/', $value) && $value > 0 && $value < 32;
case 'hour':
return preg_match('/^[0-9]{2}$/', $value) && $value < 24;
case 'minute':
return preg_match('/^[0-9]{2}$/', $value) && $value < 60;
case 'second':
// According to RFC5260, seconds can be from 00 to 60
return preg_match('/^[0-9]{2}$/', $value) && $value < 61;
case 'weekday':
return preg_match('/^[0-9]$/', $value) && $value < 7;
case 'zone':
return preg_match('/^[+-][0-9]{4}$/', $value);
}
}
/**
* 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
*/
protected function mod_mailbox($mailbox, $mode = 'out')
{
$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')) {
// 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;
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']);
// make sure the script exist
if (in_array($name, $this->list)) {
$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);
}
}
// When no script listing allowed limit the list to the defined script
if (in_array('list_sets', $this->disabled_actions)) {
$script_name = $this->rc->config->get('managesieve_script_name', 'roundcube');
$this->list = array_intersect($this->list, array($script_name));
$this->active = null;
if (in_array($script_name, $this->list)) {
// Because its the only allowed script make sure its active
$this->activate_script($script_name);
}
}
// reindex
if (!empty($this->list)) {
$this->list = array_values($this->list);
}
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 && array_search($name, (array) $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 $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 $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 (empty($filter['actions'])) {
continue;
}
$fname = $filter['name'] ?: "#$i";
$result[] = array(
'id' => $idx,
'name' => $fname,
'class' => $filter['disabled'] ? 'disabled' : '',
);
$i++;
}
return $result;
}
/**
* Initializes internal script data
*/
protected function init_script()
{
if (!$this->sieve->script) {
return;
}
$this->script = $this->sieve->script->as_array();
$headers = array();
$exceptions = array('date', 'currentdate', 'size', 'body');
// find common headers used in script, will be added to the list
// of available (predefined) headers (#1489271)
foreach ($this->script as $rule) {
foreach ((array) $rule['tests'] as $test) {
if ($test['test'] == 'header') {
foreach ((array) $test['arg1'] as $header) {
$lc_header = strtolower($header);
// skip special names to not confuse UI
if (in_array($lc_header, $exceptions)) {
continue;
}
if (!isset($this->headers[$lc_header]) && !isset($headers[$lc_header])) {
$headers[$lc_header] = $header;
}
}
}
}
}
ksort($headers);
$this->headers += $headers;
}
/**
* Get all e-mail addresses of the user
*/
protected function user_emails()
{
$addresses = $this->rc->user->list_emails();
foreach ($addresses as $idx => $email) {
$addresses[$idx] = $email['email'];
}
$addresses = array_unique($addresses);
sort($addresses);
return $addresses;
}
/**
* Convert configured default headers into internal format
*/
protected function get_default_headers()
{
$default = array('Subject', 'From', 'To');
$headers = (array) $this->rc->config->get('managesieve_default_headers', $default);
$keys = array_map('strtolower', $headers);
$headers = array_combine($keys, $headers);
// make sure there's no Date header
unset($headers['date']);
return $headers;
}
/**
* Match type selector
*/
protected function match_type_selector($name, $id, $test, $rule = null, $mode = 'all')
{
// matching type select (operator)
$select_op = new html_select(array(
'name' => "_{$name}[$id]",
'id' => "{$name}{$id}",
'style' => 'display:' .(!in_array($rule, array('size', 'duplicate')) ? 'inline' : 'none'),
'class' => 'operator_selector',
'onchange' => "{$name}_select(this, '{$id}')",
));
$select_op->add(rcube::Q($this->plugin->gettext('filtercontains')), 'contains');
$select_op->add(rcube::Q($this->plugin->gettext('filternotcontains')), 'notcontains');
$select_op->add(rcube::Q($this->plugin->gettext('filteris')), 'is');
$select_op->add(rcube::Q($this->plugin->gettext('filterisnot')), 'notis');
if ($mode == 'all') {
$select_op->add(rcube::Q($this->plugin->gettext('filterexists')), 'exists');
$select_op->add(rcube::Q($this->plugin->gettext('filternotexists')), 'notexists');
}
$select_op->add(rcube::Q($this->plugin->gettext('filtermatches')), 'matches');
$select_op->add(rcube::Q($this->plugin->gettext('filternotmatches')), 'notmatches');
if (in_array('regex', $this->exts)) {
$select_op->add(rcube::Q($this->plugin->gettext('filterregex')), 'regex');
$select_op->add(rcube::Q($this->plugin->gettext('filternotregex')), 'notregex');
}
if ($mode == 'all' && in_array('relational', $this->exts)) {
$select_op->add(rcube::Q($this->plugin->gettext('countisgreaterthan')), 'count-gt');
$select_op->add(rcube::Q($this->plugin->gettext('countisgreaterthanequal')), 'count-ge');
$select_op->add(rcube::Q($this->plugin->gettext('countislessthan')), 'count-lt');
$select_op->add(rcube::Q($this->plugin->gettext('countislessthanequal')), 'count-le');
$select_op->add(rcube::Q($this->plugin->gettext('countequals')), 'count-eq');
$select_op->add(rcube::Q($this->plugin->gettext('countnotequals')), 'count-ne');
$select_op->add(rcube::Q($this->plugin->gettext('valueisgreaterthan')), 'value-gt');
$select_op->add(rcube::Q($this->plugin->gettext('valueisgreaterthanequal')), 'value-ge');
$select_op->add(rcube::Q($this->plugin->gettext('valueislessthan')), 'value-lt');
$select_op->add(rcube::Q($this->plugin->gettext('valueislessthanequal')), 'value-le');
$select_op->add(rcube::Q($this->plugin->gettext('valueequals')), 'value-eq');
$select_op->add(rcube::Q($this->plugin->gettext('valuenotequals')), 'value-ne');
}
return $select_op->show($test);
}
protected function comparator_selector($comparator, $name, $id)
{
$select_comp = new html_select(array('name' => "_{$name}[$id]", 'id' => "{$name}_op{$id}"));
$select_comp->add(rcube::Q($this->plugin->gettext('default')), '');
$select_comp->add(rcube::Q($this->plugin->gettext('octet')), 'i;octet');
$select_comp->add(rcube::Q($this->plugin->gettext('asciicasemap')), 'i;ascii-casemap');
if (in_array('comparator-i;ascii-numeric', $this->exts)) {
$select_comp->add(rcube::Q($this->plugin->gettext('asciinumeric')), 'i;ascii-numeric');
}
return $select_comp->show($comparator);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Mar 19, 8:46 AM (17 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
457703
Default Alt Text
(160 KB)
Attached To
Mode
R3 roundcubemail
Attached
Detach File
Event Timeline
Log In to Comment