- Applied fixes from trunk up to r5451

release-0.7
alecpl 13 years ago
parent bdb649067d
commit c994e0e7cd

@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
- Fix handling of HTML form elements in messages (#1485137)
- Fix regression in setting recipient to self when replying to a Sent message (#1487074)
- Fix listing of folders in hidden namespaces (#1486796)

@ -1,4 +1,16 @@
- Fixed setting test type to :is when none is specified
* 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]
-----------------------------------------------------------

@ -44,7 +44,6 @@ class rcube_sieve
public $script; // rcube_sieve_script object
public $current; // name of currently loaded script
private $disabled; // array of disabled extensions
private $exts; // array of supported extensions
@ -89,7 +88,17 @@ class rcube_sieve
}
$this->exts = $this->get_extensions();
$this->disabled = $disabled;
// disable features by config
if (!empty($disabled)) {
// we're working on lower-cased names
$disabled = array_map('strtolower', (array) $disabled);
foreach ($disabled as $ext) {
if (($idx = array_search($ext, $this->exts)) !== false) {
unset($this->exts[$idx]);
}
}
}
}
public function __destruct() {
@ -301,7 +310,7 @@ class rcube_sieve
private function _parse($txt)
{
// parse
$script = new rcube_sieve_script($txt, $this->disabled, $this->exts);
$script = new rcube_sieve_script($txt, $this->exts);
// fix/convert to Roundcube format
if (!empty($script->content)) {

@ -29,9 +29,9 @@ class rcube_sieve_script
private $vars = array(); // "global" variables
private $prefix = ''; // script header (comments)
private $capabilities = array(); // Sieve extensions supported by server
private $supported = array( // Sieve extensions supported by class
'fileinto', // RFC3028
'fileinto', // RFC5228
'envelope', // RFC5228
'reject', // RFC5429
'ereject', // RFC5429
'copy', // RFC3894
@ -42,30 +42,30 @@ class rcube_sieve_script
'imap4flags', // RFC5232
'include', // draft-ietf-sieve-include-12
'variables', // RFC5229
// TODO: body, notify
'body', // RFC5173
'subaddress', // RFC5233
// @TODO: enotify/notify, spamtest+virustest, mailbox, date
);
/**
* Object constructor
*
* @param string Script's text content
* @param array List of disabled extensions
* @param array List of capabilities supported by server
*/
public function __construct($script, $disabled=array(), $capabilities=array())
public function __construct($script, $capabilities=array())
{
if (!empty($disabled)) {
// we're working on lower-cased names
$disabled = array_map('strtolower', (array) $disabled);
foreach ($disabled as $ext) {
if (($idx = array_search($ext, $this->supported)) !== false) {
$capabilities = array_map('strtolower', (array) $capabilities);
// disable features by server capabilities
if (!empty($capabilities)) {
foreach ($this->supported as $idx => $ext) {
if (!in_array($ext, $capabilities)) {
unset($this->supported[$idx]);
}
}
}
$this->capabilities = array_map('strtolower', (array) $capabilities);
// Parse text content of the script
$this->_parse_text($script);
}
@ -182,7 +182,7 @@ class rcube_sieve_script
$idx = 0;
if (!empty($this->vars)) {
if (in_array('variables', (array)$this->capabilities)) {
if (in_array('variables', (array)$this->supported)) {
$has_vars = true;
array_push($exts, 'variables');
}
@ -222,34 +222,96 @@ class rcube_sieve_script
$tests[$i] .= ($test['not'] ? 'not ' : '');
$tests[$i] .= 'size :' . ($test['type']=='under' ? 'under ' : 'over ') . $test['arg'];
break;
case 'true':
$tests[$i] .= ($test['not'] ? 'false' : 'true');
break;
case 'exists':
$tests[$i] .= ($test['not'] ? 'not ' : '');
$tests[$i] .= 'exists ' . self::escape_string($test['arg']);
break;
case 'header':
$tests[$i] .= ($test['not'] ? 'not ' : '');
$tests[$i] .= 'header';
// relational operator + comparator
if (preg_match('/^(value|count)-([gteqnl]{2})/', $test['type'], $m)) {
array_push($exts, 'relational');
array_push($exts, 'comparator-i;ascii-numeric');
if (!empty($test['type'])) {
// relational operator + comparator
if (preg_match('/^(value|count)-([gteqnl]{2})/', $test['type'], $m)) {
array_push($exts, 'relational');
array_push($exts, 'comparator-i;ascii-numeric');
$tests[$i] .= 'header :' . $m[1] . ' "' . $m[2] . '" :comparator "i;ascii-numeric"';
$tests[$i] .= ' :' . $m[1] . ' "' . $m[2] . '" :comparator "i;ascii-numeric"';
}
else {
$this->add_comparator($test, $tests[$i], $exts);
if ($test['type'] == 'regex') {
array_push($exts, 'regex');
}
$tests[$i] .= ' :' . $test['type'];
}
}
else {
$tests[$i] .= ' ' . self::escape_string($test['arg1']);
$tests[$i] .= ' ' . self::escape_string($test['arg2']);
break;
case 'address':
case 'envelope':
if ($test['test'] == 'envelope') {
array_push($exts, 'envelope');
}
$tests[$i] .= ($test['not'] ? 'not ' : '');
$tests[$i] .= $test['test'];
if (!empty($test['part'])) {
$tests[$i] .= ' :' . $test['part'];
if ($test['part'] == 'user' || $test['part'] == 'detail') {
array_push($exts, 'subaddress');
}
}
$this->add_comparator($test, $tests[$i], $exts);
if (!empty($test['type'])) {
if ($test['type'] == 'regex') {
array_push($exts, 'regex');
}
$tests[$i] .= 'header :' . $test['type'];
$tests[$i] .= ' :' . $test['type'];
}
$tests[$i] .= ' ' . self::escape_string($test['arg1']);
$tests[$i] .= ' ' . self::escape_string($test['arg2']);
break;
case 'body':
array_push($exts, 'body');
$tests[$i] .= ($test['not'] ? 'not ' : '') . 'body';
$this->add_comparator($test, $tests[$i], $exts);
if (!empty($test['part'])) {
$tests[$i] .= ' :' . $test['part'];
if (!empty($test['content']) && $test['part'] == 'content') {
$tests[$i] .= ' ' . self::escape_string($test['content']);
}
}
if (!empty($test['type'])) {
if ($test['type'] == 'regex') {
array_push($exts, 'regex');
}
$tests[$i] .= ' :' . $test['type'];
}
$tests[$i] .= ' ' . self::escape_string($test['arg']);
break;
}
$i++;
}
@ -311,7 +373,7 @@ class rcube_sieve_script
case 'addflag':
case 'setflag':
case 'removeflag':
if (is_array($this->capabilities) && in_array('imap4flags', $this->capabilities))
if (in_array('imap4flags', $this->supported))
array_push($exts, 'imap4flags');
else
array_push($exts, 'imapflags');
@ -448,7 +510,7 @@ class rcube_sieve_script
// handle script header
if (empty($options['prefix'])) {
$options['prefix'] = true;
if ($prefix && strpos($prefix, 'Generated by Ingo')) {
if ($prefix && strpos($prefix, 'horde.org/ingo')) {
$options['format'] = 'INGO';
}
}
@ -559,7 +621,7 @@ class rcube_sieve_script
$header = array('test' => 'header', 'not' => $not, 'arg1' => '', 'arg2' => '');
for ($i=0, $len=count($tokens); $i<$len; $i++) {
if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) {
$i++;
$header['comparator'] = $tokens[++$i];
}
else if (!is_array($tokens[$i]) && preg_match('/^:(count|value)$/i', $tokens[$i])) {
$header['type'] = strtolower(substr($tokens[$i], 1)) . '-' . $tokens[++$i];
@ -576,6 +638,52 @@ class rcube_sieve_script
$tests[] = $header;
break;
case 'address':
case 'envelope':
$header = array('test' => $token, 'not' => $not, 'arg1' => '', 'arg2' => '');
for ($i=0, $len=count($tokens); $i<$len; $i++) {
if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) {
$header['comparator'] = $tokens[++$i];
}
else if (!is_array($tokens[$i]) && preg_match('/^:(is|contains|matches|regex)$/i', $tokens[$i])) {
$header['type'] = strtolower(substr($tokens[$i], 1));
}
else if (!is_array($tokens[$i]) && preg_match('/^:(localpart|domain|all|user|detail)$/i', $tokens[$i])) {
$header['part'] = strtolower(substr($tokens[$i], 1));
}
else {
$header['arg1'] = $header['arg2'];
$header['arg2'] = $tokens[$i];
}
}
$tests[] = $header;
break;
case 'body':
$header = array('test' => 'body', 'not' => $not, 'arg' => '');
for ($i=0, $len=count($tokens); $i<$len; $i++) {
if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) {
$header['comparator'] = $tokens[++$i];
}
else if (!is_array($tokens[$i]) && preg_match('/^:(is|contains|matches|regex)$/i', $tokens[$i])) {
$header['type'] = strtolower(substr($tokens[$i], 1));
}
else if (!is_array($tokens[$i]) && preg_match('/^:(raw|content|text)$/i', $tokens[$i])) {
$header['part'] = strtolower(substr($tokens[$i], 1));
if ($header['part'] == 'content') {
$header['content'] = $tokens[++$i];
}
}
else {
$header['arg'] = $tokens[$i];
}
}
$tests[] = $header;
break;
case 'exists':
$tests[] = array('test' => 'exists', 'not' => $not,
'arg' => array_pop($tokens));
@ -597,9 +705,7 @@ class rcube_sieve_script
}
// ...and actions block
if ($tests) {
$actions = $this->_parse_actions($content);
}
$actions = $this->_parse_actions($content);
if ($tests && $actions) {
$result = array(
@ -746,6 +852,29 @@ class rcube_sieve_script
return $result;
}
/**
*
*/
private function add_comparator($test, &$out, &$exts)
{
if (empty($test['comparator'])) {
return;
}
if ($test['comparator'] == 'i;ascii-numeric') {
array_push($exts, 'relational');
array_push($exts, 'comparator-i;ascii-numeric');
}
else if (!in_array($test['comparator'], array('i;octet', 'i;ascii-casemap'))) {
array_push($exts, 'comparator-' . $test['comparator']);
}
// skip default comparator
if ($test['comparator'] != 'i;ascii-casemap') {
$out .= ' :comparator ' . self::escape_string($test['comparator']);
}
}
/**
* Escape special chars into quoted string value or multi-line string
* or list of strings

@ -82,6 +82,25 @@ $labels['filtercreate'] = 'Create filter';
$labels['usedata'] = 'Use following data in the filter:';
$labels['nextstep'] = 'Next Step';
$labels['...'] = '...';
$labels['advancedopts'] = 'Advanced options';
$labels['body'] = 'Body';
$labels['address'] = 'address';
$labels['envelope'] = 'envelope';
$labels['modifier'] = 'modifier:';
$labels['text'] = 'text';
$labels['undecoded'] = 'undecoded (raw)';
$labels['contenttype'] = 'content type';
$labels['modtype'] = 'type:';
$labels['allparts'] = 'all';
$labels['domain'] = 'domain';
$labels['localpart'] = 'local part';
$labels['user'] = 'user';
$labels['detail'] = 'detail';
$labels['comparator'] = 'comparator:';
$labels['default'] = 'default';
$labels['octet'] = 'strict (octet)';
$labels['asciicasemap'] = 'case insensitive (ascii-casemap)';
$labels['asciinumeric'] = 'numeric (ascii-numeric)';
$messages = array();
$messages['filterunknownerror'] = 'Unknown server error.';

@ -81,6 +81,25 @@ $labels['filtercreate'] = 'Utwóż filtr';
$labels['usedata'] = 'Użyj następujących danych do utworzenia filtra:';
$labels['nextstep'] = 'Następny krok';
$labels['...'] = '...';
$labels['advancedopts'] = 'Zaawansowane opcje';
$labels['body'] = 'Treść';
$labels['address'] = 'adres';
$labels['envelope'] = 'koperta (envelope)';
$labels['modifier'] = 'modyfikator:';
$labels['text'] = 'tekst';
$labels['undecoded'] = 'nie (raw)';
$labels['contenttype'] = 'typ części (content type)';
$labels['modtype'] = 'typ:';
$labels['allparts'] = 'wszystkie';
$labels['domain'] = 'domena';
$labels['localpart'] = 'część lokalna';
$labels['user'] = 'użytkownik';
$labels['detail'] = 'detal';
$labels['comparator'] = 'komparator:';
$labels['default'] = 'domyślny';
$labels['octet'] = 'dokładny (octet)';
$labels['asciicasemap'] = 'nierozróżniający wielkości liter (ascii-casemap)';
$labels['asciinumeric'] = 'numeryczny (ascii-numeric)';
$messages = array();
$messages['filterunknownerror'] = 'Nieznany błąd serwera.';

@ -542,19 +542,28 @@ function rule_header_select(id)
size = document.getElementById('rule_size' + id),
op = document.getElementById('rule_op' + id),
target = document.getElementById('rule_target' + id),
header = document.getElementById('custom_header' + id);
header = document.getElementById('custom_header' + id),
mod = document.getElementById('rule_mod' + id),
trans = document.getElementById('rule_trans' + id),
comp = document.getElementById('rule_comp' + id);
if (obj.value == 'size') {
size.style.display = 'inline';
op.style.display = 'none';
target.style.display = 'none';
header.style.display = 'none';
mod.style.display = 'none';
trans.style.display = 'none';
comp.style.display = 'none';
}
else {
header.style.display = obj.value != '...' ? 'none' : 'inline';
size.style.display = 'none';
op.style.display = 'inline';
comp.style.display = '';
rule_op_select(id);
mod.style.display = obj.value == 'body' ? 'none' : 'block';
trans.style.display = obj.value == 'body' ? 'block' : 'none';
}
obj.style.width = obj.value == '...' ? '40px' : '';
@ -568,11 +577,41 @@ function rule_op_select(id)
target.style.display = obj.value == 'exists' || obj.value == 'notexists' ? 'none' : 'inline';
};
function rule_trans_select(id)
{
var obj = document.getElementById('rule_trans_op' + id),
target = document.getElementById('rule_trans_type' + id);
target.style.display = obj.value != 'content' ? 'none' : 'inline';
};
function rule_mod_select(id)
{
var obj = document.getElementById('rule_mod_op' + id),
target = document.getElementById('rule_mod_type' + id);
target.style.display = obj.value != 'address' && obj.value != 'envelope' ? 'none' : 'inline';
};
function rule_join_radio(value)
{
$('#rules').css('display', value == 'any' ? 'none' : 'block');
};
function rule_adv_switch(id, elem)
{
var elem = $(elem), enabled = elem.hasClass('hide'), adv = $('#rule_advanced'+id);
if (enabled) {
adv.hide();
elem.removeClass('hide').addClass('show');
}
else {
adv.show();
elem.removeClass('show').addClass('hide');
}
}
function action_type_select(id)
{
var obj = document.getElementById('action_type' + id),

@ -45,9 +45,23 @@ class managesieve extends rcube_plugin
private $list;
private $active = array();
private $headers = array(
'subject' => 'Subject',
'sender' => 'From',
'recipient' => 'To',
'subject' => 'Subject',
'from' => 'From',
'to' => 'To',
);
private $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",
);
const VERSION = '5.0';
@ -588,6 +602,11 @@ class managesieve extends rcube_plugin
$sizeitems = get_input_value('_rule_size_item', RCUBE_INPUT_POST);
$sizetargets = get_input_value('_rule_size_target', RCUBE_INPUT_POST);
$targets = get_input_value('_rule_target', RCUBE_INPUT_POST, true);
$mods = get_input_value('_rule_mod', RCUBE_INPUT_POST);
$mod_types = get_input_value('_rule_mod_type', RCUBE_INPUT_POST);
$body_trans = get_input_value('_rule_trans', RCUBE_INPUT_POST);
$body_types = get_input_value('_rule_trans_type', RCUBE_INPUT_POST, true);
$comparators = get_input_value('_rule_comp', RCUBE_INPUT_POST);
$act_types = get_input_value('_action_type', RCUBE_INPUT_POST, true);
$mailboxes = get_input_value('_action_mailbox', RCUBE_INPUT_POST, true);
$act_targets = get_input_value('_action_target', RCUBE_INPUT_POST, true);
@ -625,23 +644,101 @@ class managesieve extends rcube_plugin
}
else {
foreach ($headers as $idx => $header) {
$header = $this->strip_value($header);
$target = $this->strip_value($targets[$idx], true);
$op = $this->strip_value($ops[$idx]);
$header = $this->strip_value($header);
$target = $this->strip_value($targets[$idx], true);
$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($items[$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->gettext('cannotbeempty');
else if (!preg_match('/^[0-9]+(K|M|G)?$/i', $sizetarget.$sizeitem, $m)) {
$this->errors['tests'][$i]['sizetarget'] = $this->gettext('forbiddenchars');
$this->form['tests'][$i]['item'] = $sizeitem;
}
else
$this->form['tests'][$i]['arg'] .= $m[1];
}
else if ($header == 'body') {
$trans = $this->strip_value($body_trans[$idx]);
$trans_type = $this->strip_value($body_types[$idx], true);
// normal header
if (in_array($header, $this->headers)) {
if (preg_match('/^not/', $op))
if (preg_match('/^not/', $operator))
$this->form['tests'][$i]['not'] = true;
$type = preg_replace('/^not/', '', $op);
$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 ($target == '' && $type != 'exists')
$this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty');
else if (preg_match('/^(value|count)-/', $type) && !preg_match('/[0-9]+/', $target))
$this->errors['tests'][$i]['target'] = $this->gettext('forbiddenchars');
$this->form['tests'][$i]['part'] = $trans;
if ($trans == 'content') {
$this->form['tests'][$i]['content'] = $trans_type;
}
}
else {
$cust_header = $headers = $this->strip_value($cust_headers[$idx]);
$mod = $this->strip_value($mods[$idx]);
$mod_type = $this->strip_value($mod_types[$idx]);
if (preg_match('/^not/', $operator))
$this->form['tests'][$i]['not'] = true;
$type = preg_replace('/^not/', '', $operator);
if ($header == '...') {
$headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY);
if (!count($headers))
$this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty');
else {
foreach ($headers as $hr)
if (!preg_match('/^[a-z0-9-]+$/i', $hr))
$this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars');
}
if (empty($this->errors['tests'][$i]['header']))
$cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers;
}
if ($type == 'exists') {
$this->form['tests'][$i]['test'] = 'exists';
$this->form['tests'][$i]['arg'] = $header;
$this->form['tests'][$i]['arg'] = $header == '...' ? $cust_header : $header;
}
else {
$test = 'header';
$header = $header == '...' ? $cust_header : $header;
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'] = 'header';
$this->form['tests'][$i]['test'] = $test;
$this->form['tests'][$i]['arg1'] = $header;
$this->form['tests'][$i]['arg2'] = $target;
@ -649,65 +746,20 @@ class managesieve extends rcube_plugin
$this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty');
else if (preg_match('/^(value|count)-/', $type) && !preg_match('/[0-9]+/', $target))
$this->errors['tests'][$i]['target'] = $this->gettext('forbiddenchars');
if ($mod) {
$this->form['tests'][$i]['part'] = $mod_type;
}
}
}
else
switch ($header) {
case 'size':
$sizeop = $this->strip_value($sizeops[$idx]);
$sizeitem = $this->strip_value($items[$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.$sizeitem;
if ($sizetarget == '')
$this->errors['tests'][$i]['sizetarget'] = $this->gettext('cannotbeempty');
else if (!preg_match('/^[0-9]+(K|M|G)*$/i', $sizetarget))
$this->errors['tests'][$i]['sizetarget'] = $this->gettext('forbiddenchars');
break;
case '...':
$cust_header = $headers = $this->strip_value($cust_headers[$idx]);
if (preg_match('/^not/', $op))
$this->form['tests'][$i]['not'] = true;
$type = preg_replace('/^not/', '', $op);
if ($cust_header == '')
$this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty');
else {
$headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY);
if (!count($headers))
$this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty');
else {
foreach ($headers as $hr)
if (!preg_match('/^[a-z0-9-]+$/i', $hr))
$this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars');
}
}
if (empty($this->errors['tests'][$i]['header']))
$cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers;
if ($header != 'size' && $comparator) {
if (preg_match('/^(value|count)/', $this->form['tests'][$i]['type']))
$comparator = 'i;ascii-numeric';
$this->form['tests'][$i]['comparator'] = $comparator;
}
if ($type == 'exists') {
$this->form['tests'][$i]['test'] = 'exists';
$this->form['tests'][$i]['arg'] = $cust_header;
}
else {
$this->form['tests'][$i]['test'] = 'header';
$this->form['tests'][$i]['type'] = $type;
$this->form['tests'][$i]['arg1'] = $cust_header;
$this->form['tests'][$i]['arg2'] = $target;
if ($target == '')
$this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty');
else if (preg_match('/^(value|count)-/', $type) && !preg_match('/[0-9]+/', $target))
$this->errors['tests'][$i]['target'] = $this->gettext('forbiddenchars');
}
break;
}
$i++;
}
}
@ -1140,43 +1192,52 @@ class managesieve extends rcube_plugin
$rule = isset($this->form) ? $this->form['tests'][$id] : $this->script[$fid]['tests'][$id];
$rows_num = isset($this->form) ? sizeof($this->form['tests']) : sizeof($this->script[$fid]['tests']);
$out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : '';
$out .= '<table><tr><td class="rowactions">';
// headers select
$select_header = new html_select(array('name' => "_header[]", 'id' => 'header'.$id,
'onchange' => 'rule_header_select(' .$id .')'));
foreach($this->headers as $name => $val)
$select_header->add(Q($this->gettext($name)), Q($val));
if (in_array('body', $this->exts))
$select_header->add(Q($this->gettext('body')), 'body');
$select_header->add(Q($this->gettext('size')), 'size');
$select_header->add(Q($this->gettext('...')), '...');
// TODO: list arguments
$aout = '';
if ((isset($rule['test']) && $rule['test'] == 'header')
&& !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers))
$out .= $select_header->show($rule['arg1']);
if ((isset($rule['test']) && in_array($rule['test'], array('header', 'address', 'envelope')))
&& !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers)
) {
$aout .= $select_header->show($rule['arg1']);
}
else if ((isset($rule['test']) && $rule['test'] == 'exists')
&& !is_array($rule['arg']) && in_array($rule['arg'], $this->headers))
$out .= $select_header->show($rule['arg']);
&& !is_array($rule['arg']) && in_array($rule['arg'], $this->headers)
) {
$aout .= $select_header->show($rule['arg']);
}
else if (isset($rule['test']) && $rule['test'] == 'size')
$out .= $select_header->show('size');
$aout .= $select_header->show('size');
else if (isset($rule['test']) && $rule['test'] == 'body')
$aout .= $select_header->show('body');
else if (isset($rule['test']) && $rule['test'] != 'true')
$out .= $select_header->show('...');
$aout .= $select_header->show('...');
else
$out .= $select_header->show();
$aout .= $select_header->show();
$out .= '</td><td class="rowtargets">';
if ((isset($rule['test']) && $rule['test'] == 'header')
&& (is_array($rule['arg1']) || !in_array($rule['arg1'], $this->headers)))
$custom = is_array($rule['arg1']) ? implode(', ', $rule['arg1']) : $rule['arg1'];
else if ((isset($rule['test']) && $rule['test'] == 'exists')
&& (is_array($rule['arg']) || !in_array($rule['arg'], $this->headers)))
$custom = is_array($rule['arg']) ? implode(', ', $rule['arg']) : $rule['arg'];
if (isset($rule['test']) && in_array($rule['test'], array('header', 'address', 'envelope'))) {
if (is_array($rule['arg1']))
$custom = implode(', ', $rule['arg1']);
else if (!in_array($rule['arg1'], $this->headers))
$custom = $rule['arg1'];
}
else if (isset($rule['test']) && $rule['test'] == 'exists') {
if (is_array($rule['arg']))
$custom = implode(', ', $rule['arg']);
else if (!in_array($rule['arg'], $this->headers))
$custom = $rule['arg'];
}
$out .= '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '">
$tout = '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '">
<input type="text" name="_custom_header[]" id="custom_header_i'.$id.'" '
. $this->error_class($id, 'test', 'header', 'custom_header_i')
.' value="' .Q($custom). '" size="15" />&nbsp;</div>' . "\n";
@ -1215,33 +1276,43 @@ class managesieve extends rcube_plugin
// target input (TODO: lists)
if ($rule['test'] == 'header') {
$out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['type']);
if (in_array($rule['test'], array('header', 'address', 'envelope'))) {
$test = ($rule['not'] ? 'not' : '').($rule['type'] ? $rule['type'] : 'is');
$target = $rule['arg2'];
}
else if ($rule['test'] == 'body') {
$test = ($rule['not'] ? 'not' : '').($rule['type'] ? $rule['type'] : 'is');
$target = $rule['arg'];
}
else if ($rule['test'] == 'size') {
$out .= $select_op->show();
if (preg_match('/^([0-9]+)(K|M|G)*$/', $rule['arg'], $matches)) {
$test = '';
$target = '';
if (preg_match('/^([0-9]+)(K|M|G)?$/', $rule['arg'], $matches)) {
$sizetarget = $matches[1];
$sizeitem = $matches[2];
}
else {
$sizetarget = $rule['arg'];
$sizeitem = $rule['item'];
}
}
else {
$out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['test']);
$target = '';
$test = ($rule['not'] ? 'not' : '').$rule['test'];
$target = '';
}
$out .= '<input type="text" name="_rule_target[]" id="rule_target' .$id. '"
$tout .= $select_op->show($test);
$tout .= '<input type="text" name="_rule_target[]" id="rule_target' .$id. '"
value="' .Q($target). '" size="20" ' . $this->error_class($id, 'test', 'target', 'rule_target')
. ' style="display:' . ($rule['test']!='size' && $rule['test'] != 'exists' ? 'inline' : 'none') . '" />'."\n";
$select_size_op = new html_select(array('name' => "_rule_size_op[]", 'id' => 'rule_size_op'.$id));
$select_size_op->add(Q($this->gettext('filterunder')), 'under');
$select_size_op->add(Q($this->gettext('filterover')), 'over');
$select_size_op->add(Q($this->gettext('filterunder')), 'under');
$out .= '<div id="rule_size' .$id. '" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">';
$out .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : '');
$out .= '<input type="text" name="_rule_size_target[]" id="rule_size_i'.$id.'" value="'.$sizetarget.'" size="10" '
$tout .= '<div id="rule_size' .$id. '" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">';
$tout .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : '');
$tout .= '<input type="text" name="_rule_size_target[]" id="rule_size_i'.$id.'" value="'.$sizetarget.'" size="10" '
. $this->error_class($id, 'test', 'sizetarget', 'rule_size_i') .' />
<input type="radio" name="_rule_size_item['.$id.']" value=""'
. (!$sizeitem ? ' checked="checked"' : '') .' class="radio" />'.rcube_label('B').'
@ -1251,7 +1322,82 @@ class managesieve extends rcube_plugin
. ($sizeitem=='M' ? ' checked="checked"' : '') .' class="radio" />'.rcube_label('MB').'
<input type="radio" name="_rule_size_item['.$id.']" value="G"'
. ($sizeitem=='G' ? ' checked="checked"' : '') .' class="radio" />'.rcube_label('GB');
$out .= '</div>';
$tout .= '</div>';
// Advanced modifiers (address, envelope)
$select_mod = new html_select(array('name' => "_rule_mod[]", 'id' => 'rule_mod_op'.$id,
'onchange' => 'rule_mod_select(' .$id .')'));
$select_mod->add(Q($this->gettext('none')), '');
$select_mod->add(Q($this->gettext('address')), 'address');
if (in_array('envelope', $this->exts))
$select_mod->add(Q($this->gettext('envelope')), 'envelope');
$select_type = new html_select(array('name' => "_rule_mod_type[]", 'id' => 'rule_mod_type'.$id));
$select_type->add(Q($this->gettext('allparts')), 'all');
$select_type->add(Q($this->gettext('domain')), 'domain');
$select_type->add(Q($this->gettext('localpart')), 'localpart');
if (in_array('subaddress', $this->exts)) {
$select_type->add(Q($this->gettext('user')), 'user');
$select_type->add(Q($this->gettext('detail')), 'detail');
}
$need_mod = $rule['test'] != 'size' && $rule['test'] != 'body';
$mout = '<div id="rule_mod' .$id. '" class="adv" style="display:' . ($need_mod ? 'block' : 'none') .'">';
$mout .= ' <span>';
$mout .= Q($this->gettext('modifier')) . ' ';
$mout .= $select_mod->show($rule['test']);
$mout .= '</span>';
$mout .= ' <span id="rule_mod_type' . $id . '"';
$mout .= ' style="display:' . (in_array($rule['test'], array('address', 'envelope')) ? 'inline' : 'none') .'">';
$mout .= Q($this->gettext('modtype')) . ' ';
$mout .= $select_type->show($rule['part']);
$mout .= '</span>';
$mout .= '</div>';
// Advanced modifiers (body transformations)
$select_mod = new html_select(array('name' => "_rule_trans[]", 'id' => 'rule_trans_op'.$id,
'onchange' => 'rule_trans_select(' .$id .')'));
$select_mod->add(Q($this->gettext('text')), 'text');
$select_mod->add(Q($this->gettext('undecoded')), 'raw');
$select_mod->add(Q($this->gettext('contenttype')), 'content');
$mout .= '<div id="rule_trans' .$id. '" class="adv" style="display:' . ($rule['test'] == 'body' ? 'block' : 'none') .'">';
$mout .= ' <span>';
$mout .= Q($this->gettext('modifier')) . ' ';
$mout .= $select_mod->show($rule['part']);
$mout .= '<input type="text" name="_rule_trans_type[]" id="rule_trans_type'.$id
. '" value="'.(is_array($rule['content']) ? implode(',', $rule['content']) : $rule['content'])
.'" size="20" style="display:' . ($rule['part'] == 'content' ? 'inline' : 'none') .'"'
. $this->error_class($id, 'test', 'part', 'rule_trans_type') .' />';
$mout .= '</span>';
$mout .= '</div>';
// Advanced modifiers (body transformations)
$select_comp = new html_select(array('name' => "_rule_comp[]", 'id' => 'rule_comp_op'.$id));
$select_comp->add(Q($this->gettext('default')), '');
$select_comp->add(Q($this->gettext('octet')), 'i;octet');
$select_comp->add(Q($this->gettext('asciicasemap')), 'i;ascii-casemap');
if (in_array('comparator-i;ascii-numeric', $this->exts)) {
$select_comp->add(Q($this->gettext('asciinumeric')), 'i;ascii-numeric');
}
$mout .= '<div id="rule_comp' .$id. '" class="adv" style="display:' . ($rule['test'] != 'size' ? 'block' : 'none') .'">';
$mout .= ' <span>';
$mout .= Q($this->gettext('comparator')) . ' ';
$mout .= $select_comp->show($rule['comparator']);
$mout .= '</span>';
$mout .= '</div>';
// Build output table
$out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : '';
$out .= '<table><tr>';
$out .= '<td class="advbutton">';
$out .= '<a href="#" id="ruleadv' . $id .'" title="'. Q($this->gettext('advancedopts')). '"
onclick="rule_adv_switch(' . $id .', this)" class="show">&nbsp;&nbsp;</a>';
$out .= '</td>';
$out .= '<td class="rowactions">' . $aout . '</td>';
$out .= '<td class="rowtargets">' . $tout . "\n";
$out .= '<div id="rule_advanced' .$id. '" style="display:none">' . $mout . '</div>';
$out .= '</td>';
// add/del buttons
@ -1260,7 +1406,8 @@ class managesieve extends rcube_plugin
onclick="rcmail.managesieve_ruleadd(' . $id .')" class="button add"></a>';
$out .= '<a href="#" id="ruledel' . $id .'" title="'. Q($this->gettext('del')). '"
onclick="rcmail.managesieve_ruledel(' . $id .')" class="button del' . ($rows_num<2 ? ' disabled' : '') .'"></a>';
$out .= '</td></tr></table>';
$out .= '</td>';
$out .= '</tr></table>';
$out .= $div ? "</div>\n" : '';

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
http://pear.php.net/dtd/tasks-1.0.xsd
http://pear.php.net/dtd/package-2.0
http://pear.php.net/dtd/package-2.0.xsd">
<name>managesieve</name>
<channel>pear.roundcube.net</channel>
<summary>Sieve filters manager for Roundcube</summary>
<description>
Adds a possibility to manage Sieve scripts (incoming mail filters).
It's clickable interface which operates on text scripts and communicates
with server using managesieve protocol. Adds Filters tab in Settings.
</description>
<lead>
<name>Aleksander Machniak</name>
<user>alec</user>
<email>alec@alec.pl</email>
<active>yes</active>
</lead>
<date>2011-11-17</date>
<version>
<release>5.0</release>
<api>5.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license>
<notes>-</notes>
<contents>
<dir baseinstalldir="/" name="/">
<file name="managesieve.php" role="php">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="managesieve.js" role="data">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="localization/bg_BG.inc" role="data"></file>
<file name="localization/cs_CZ.inc" role="data"></file>
<file name="localization/de_CH.inc" role="data"></file>
<file name="localization/de_DE.inc" role="data"></file>
<file name="localization/el_GR.inc" role="data"></file>
<file name="localization/en_GB.inc" role="data"></file>
<file name="localization/en_US.inc" role="data"></file>
<file name="localization/es_AR.inc" role="data"></file>
<file name="localization/es_ES.inc" role="data"></file>
<file name="localization/et_EE.inc" role="data"></file>
<file name="localization/fi_FI.inc" role="data"></file>
<file name="localization/fr_FR.inc" role="data"></file>
<file name="localization/gl_ES.inc" role="data"></file>
<file name="localization/hr_HR.inc" role="data"></file>
<file name="localization/hu_HU.inc" role="data"></file>
<file name="localization/it_IT.inc" role="data"></file>
<file name="localization/ja_JP.inc" role="data"></file>
<file name="localization/lv_LV.inc" role="data"></file>
<file name="localization/nb_NO.inc" role="data"></file>
<file name="localization/nl_NL.inc" role="data"></file>
<file name="localization/pl_PL.inc" role="data"></file>
<file name="localization/pt_BR.inc" role="data"></file>
<file name="localization/pt_PT.inc" role="data"></file>
<file name="localization/ru_RU.inc" role="data"></file>
<file name="localization/sk_SK.inc" role="data"></file>
<file name="localization/sl_SI.inc" role="data"></file>
<file name="localization/sv_SE.inc" role="data"></file>
<file name="localization/uk_UA.inc" role="data"></file>
<file name="localization/zh_CN.inc" role="data"></file>
<file name="localization/zh_TW.inc" role="data"></file>
<file name="skins/default/managesieve.css" role="data"></file>
<file name="skins/default/managesieve_mail.css" role="data"></file>
<file name="skins/default/templates/filteredit.html" role="data"></file>
<file name="skins/default/templates/managesieve.html" role="data"></file>
<file name="skins/default/templates/setedit.html" role="data"></file>
<file name="skins/default/images/add.png" role="data"></file>
<file name="skins/default/images/del.png" role="data"></file>
<file name="skins/default/images/down_small.gif" role="data"></file>
<file name="skins/default/images/filter.png" role="data"></file>
<file name="skins/default/images/up_small.gif" role="data"></file>
<file name="managesieve.php" role="php"></file>
<file name="lib/rcube_sieve.php" role="php"></file>
<file name="lib/rcube_sieve_script.php" role="php"></file>
<file name="lib/Net/Sieve.php" role="php"></file>
<file name="config.inc.php.dist" role="data"></file>
</dir>
<!-- / -->
</contents>
<dependencies>
<required>
<php>
<min>5.2.1</min>
</php>
<pearinstaller>
<min>1.7.0</min>
</pearinstaller>
</required>
</dependencies>
<phprelease/>
</package>

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

@ -149,6 +149,35 @@ div.rulerow table, div.actionrow table
min-width: 620px;
}
td
{
vertical-align: top;
}
td.advbutton
{
width: 1%;
}
td.advbutton a
{
display: block;
padding-top: 14px;
height: 6px;
width: 12px;
text-decoration: none;
}
td.advbutton a.show
{
background: url(images/down_small.gif) center no-repeat;
}
td.advbutton a.hide
{
background: url(images/up_small.gif) center no-repeat;
}
td.rowbuttons
{
text-align: right;
@ -169,6 +198,11 @@ td.rowtargets
padding-left: 3px;
}
td.rowtargets div.adv
{
padding-top: 3px;
}
input.disabled, input.disabled:hover
{
color: #999999;
@ -183,6 +217,7 @@ input.box,
input.radio
{
border: 0;
margin-top: 0;
}
select.operator_selector
@ -190,6 +225,7 @@ select.operator_selector
width: 200px;
}
td.rowtargets span,
span.label
{
color: #666666;
@ -243,7 +279,7 @@ a.button.add
background: url(images/add.png) no-repeat;
width: 30px;
height: 20px;
margin-right: 4px;
margin-right: 4px;
display: inline-block;
}

@ -6,7 +6,7 @@ Main test of script parser
include '../lib/rcube_sieve_script.php';
$txt = '
require ["fileinto","vacation","reject","relational","comparator-i;ascii-numeric","imapflags"];
require ["fileinto","reject","envelope"];
# rule:[spam]
if anyof (header :contains "X-DSPAM-Result" "Spam")
{
@ -14,28 +14,17 @@ if anyof (header :contains "X-DSPAM-Result" "Spam")
stop;
}
# rule:[test1]
if anyof (header :contains ["From","To"] "test@domain.tld")
if anyof (header :comparator "i;ascii-casemap" :contains ["From","To"] "test@domain.tld")
{
discard;
stop;
}
# rule:[test2]
if anyof (not header :contains ["Subject"] "[test]", header :contains "Subject" "[test2]")
if anyof (not header :comparator "i;octet" :contains ["Subject"] "[test]", header :contains "Subject" "[test2]")
{
fileinto "test";
stop;
}
# rule:[test-vacation]
if anyof (header :contains "Subject" "vacation")
{
vacation :days 1 text:
# test
test test /* test */
test
.
;
stop;
}
# rule:[comments]
if anyof (true) /* comment
* "comment" #comment */ {
@ -44,24 +33,40 @@ if anyof (true) /* comment
}
# rule:[reject]
if size :over 5000K {
reject "Message over 5MB size limit. Please contact me before sending this.";
reject "Message over 5MB size limit. Please contact me before sending this.";
}
# rule:[false]
if false # size :over 5000K
{
stop; /* rule disabled */
}
# rule:[true]
if true
{
stop;
}
# rule:[redirect]
if header :value "ge" :comparator "i;ascii-numeric"
["X-Spam-score"] ["14"] {redirect "test@test.tld";}
# rule:[imapflags]
if header :matches "Subject" "^Test$" {
setflag "\\\\Seen";
addflag ["\\\\Answered","\\\\Deleted"];
fileinto "Test";
# rule:[address test]
if address :all :is "From" "nagios@domain.tld"
{
fileinto "domain.tld";
stop;
}
# rule:[envelope test]
if envelope :domain :is "From" "domain.tld"
{
fileinto "domain.tld";
stop;
}
';
$s = new rcube_sieve_script($txt);
echo $s->as_text();
// -------------------------------------------------------------------------------
?>
--EXPECT--
require ["fileinto","vacation","reject","relational","comparator-i;ascii-numeric","imapflags"];
require ["fileinto","reject","envelope"];
# rule:[spam]
if header :contains "X-DSPAM-Result" "Spam"
{
@ -75,22 +80,11 @@ if header :contains ["From","To"] "test@domain.tld"
stop;
}
# rule:[test2]
if anyof (not header :contains "Subject" "[test]", header :contains "Subject" "[test2]")
if anyof (not header :comparator "i;octet" :contains "Subject" "[test]", header :contains "Subject" "[test2]")
{
fileinto "test";
stop;
}
# rule:[test-vacation]
if header :contains "Subject" "vacation"
{
vacation :days 1 text:
# test
test test /* test */
test
.
;
stop;
}
# rule:[comments]
if true
{
@ -101,14 +95,26 @@ if size :over 5000K
{
reject "Message over 5MB size limit. Please contact me before sending this.";
}
# rule:[redirect]
if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-score" "14"
# rule:[false]
if false # size :over 5000K
{
redirect "test@test.tld";
stop;
}
# rule:[imapflags]
if header :matches "Subject" "^Test$"
# rule:[true]
if true
{
setflag "\\Seen";
addflag ["\\Answered","\\Deleted"];
stop;
}
fileinto "Test";
# rule:[address test]
if address :all :is "From" "nagios@domain.tld"
{
fileinto "domain.tld";
stop;
}
# rule:[envelope test]
if envelope :domain :is "From" "domain.tld"
{
fileinto "domain.tld";
stop;
}

@ -0,0 +1,49 @@
--TEST--
Test of Sieve body extension (RFC5173)
--SKIPIF--
--FILE--
<?php
include '../lib/rcube_sieve_script.php';
$txt = '
require ["body","fileinto"];
if body :raw :contains "MAKE MONEY FAST"
{
stop;
}
if body :content "text" :contains ["missile","coordinates"]
{
fileinto "secrets";
}
if body :content "audio/mp3" :contains ""
{
fileinto "jukebox";
}
if body :text :contains "project schedule"
{
fileinto "project/schedule";
}
';
$s = new rcube_sieve_script($txt);
echo $s->as_text();
?>
--EXPECT--
require ["body","fileinto"];
if body :raw :contains "MAKE MONEY FAST"
{
stop;
}
if body :content "text" :contains ["missile","coordinates"]
{
fileinto "secrets";
}
if body :content "audio/mp3" :contains ""
{
fileinto "jukebox";
}
if body :text :contains "project schedule"
{
fileinto "project/schedule";
}

@ -0,0 +1,28 @@
--TEST--
Test of Sieve vacation extension (RFC5232)
--SKIPIF--
--FILE--
<?php
include '../lib/rcube_sieve_script.php';
$txt = '
require ["imapflags"];
# rule:[imapflags]
if header :matches "Subject" "^Test$" {
setflag "\\\\Seen";
addflag ["\\\\Answered","\\\\Deleted"];
}
';
$s = new rcube_sieve_script($txt, array('imapflags'));
echo $s->as_text();
?>
--EXPECT--
require ["imapflags"];
# rule:[imapflags]
if header :matches "Subject" "^Test$"
{
setflag "\\Seen";
addflag ["\\Answered","\\Deleted"];
}

@ -0,0 +1,30 @@
--TEST--
Test of Sieve include extension
--SKIPIF--
--FILE--
<?php
include '../lib/rcube_sieve_script.php';
$txt = '
require ["include"];
include "script.sieve";
# rule:[two]
if true
{
include :optional "second.sieve";
}
';
$s = new rcube_sieve_script($txt, array(), array('variables'));
echo $s->as_text();
?>
--EXPECT--
require ["include"];
include "script.sieve";
# rule:[two]
if true
{
include :optional "second.sieve";
}

@ -10,7 +10,7 @@ $txt = '
# EDITOR_VERSION 123
';
$s = new rcube_sieve_script($txt, array());
$s = new rcube_sieve_script($txt, array('body'));
echo $s->as_text();
?>

@ -0,0 +1,25 @@
--TEST--
Test of prefix comments handling
--SKIPIF--
--FILE--
<?php
include '../lib/rcube_sieve_script.php';
$txt = '
# this is a comment
# and the second line
require ["variables"];
set "b" "c";
';
$s = new rcube_sieve_script($txt, array(), array('variables'));
echo $s->as_text();
?>
--EXPECT--
# this is a comment
# and the second line
require ["variables"];
set "b" "c";

@ -0,0 +1,25 @@
--TEST--
Test of Sieve relational extension (RFC5231)
--SKIPIF--
--FILE--
<?php
include '../lib/rcube_sieve_script.php';
$txt = '
require ["relational","comparator-i;ascii-numeric"];
# rule:[redirect]
if header :value "ge" :comparator "i;ascii-numeric"
["X-Spam-score"] ["14"] {redirect "test@test.tld";}
';
$s = new rcube_sieve_script($txt);
echo $s->as_text();
?>
--EXPECT--
require ["relational","comparator-i;ascii-numeric"];
# rule:[redirect]
if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-score" "14"
{
redirect "test@test.tld";
}

@ -0,0 +1,39 @@
--TEST--
Test of Sieve vacation extension (RFC5230)
--SKIPIF--
--FILE--
<?php
include '../lib/rcube_sieve_script.php';
$txt = '
require ["vacation"];
# rule:[test-vacation]
if anyof (header :contains "Subject" "vacation")
{
vacation :days 1 text:
# test
test test /* test */
test
.
;
stop;
}
';
$s = new rcube_sieve_script($txt);
echo $s->as_text();
?>
--EXPECT--
require ["vacation"];
# rule:[test-vacation]
if header :contains "Subject" "vacation"
{
vacation :days 1 text:
# test
test test /* test */
test
.
;
stop;
}

@ -0,0 +1,39 @@
--TEST--
Test of Sieve variables extension
--SKIPIF--
--FILE--
<?php
include '../lib/rcube_sieve_script.php';
$txt = '
require ["variables"];
set "honorific" "Mr";
set "vacation" text:
Dear ${HONORIFIC} ${last_name},
I am out, please leave a message after the meep.
.
;
set :length "b" "${a}";
set :lower "b" "${a}";
set :upperfirst "b" "${a}";
set :upperfirst :lower "b" "${a}";
set :quotewildcard "b" "Rock*";
';
$s = new rcube_sieve_script($txt, array(), array('variables'));
echo $s->as_text();
?>
--EXPECT--
require ["variables"];
set "honorific" "Mr";
set "vacation" text:
Dear ${HONORIFIC} ${last_name},
I am out, please leave a message after the meep.
.
;
set :length "b" "${a}";
set :lower "b" "${a}";
set :upperfirst "b" "${a}";
set :upperfirst :lower "b" "${a}";
set :quotewildcard "b" "Rock*";

@ -0,0 +1,38 @@
--TEST--
Test of Sieve subaddress extension (RFC5233)
--SKIPIF--
--FILE--
<?php
include '../lib/rcube_sieve_script.php';
$txt = '
require ["envelope","subaddress","fileinto"];
if envelope :user "To" "postmaster"
{
fileinto "postmaster";
stop;
}
if envelope :detail :is "To" "mta-filters"
{
fileinto "mta-filters";
stop;
}
';
$s = new rcube_sieve_script($txt);
echo $s->as_text();
// -------------------------------------------------------------------------------
?>
--EXPECT--
require ["envelope","subaddress","fileinto"];
if envelope :user "To" "postmaster"
{
fileinto "postmaster";
stop;
}
if envelope :detail :is "To" "mta-filters"
{
fileinto "mta-filters";
stop;
}

@ -132,7 +132,7 @@ class newmail_notifier extends rcube_plugin
*/
function notify($args)
{
if ($this->notified) {
if ($this->notified || !empty($_GET['_refresh'])) {
return $args;
}

@ -3178,7 +3178,7 @@ class rcube_imap
if (is_array($ns)) {
foreach ($ns as $ns_data) {
if (strlen($ns_data[0])) {
$search = $ns_data[0];
$search[] = $ns_data[0];
}
}
}

@ -5738,7 +5738,7 @@ function rcube_webmail()
this.plain2html = function(plainText, id)
{
var lock = this.set_busy(true, 'converting');
$(document.getElementById(id)).val('<pre>'+plainText+'</pre>');
$(document.getElementById(id)).val(plainText ? '<pre>'+plainText+'</pre>' : '');
this.set_busy(false, null, lock);
};

@ -1,6 +1,8 @@
/*
SpellCheck
jQuery'fied spell checker based on GoogieSpell 4.0
(which was published under GPL "version 2 or any later version")
Copyright (C) 2006 Amir Salihefendic
Copyright (C) 2009 Aleksander Machniak
Copyright (C) 2011 Kolab Systems AG

Loading…
Cancel
Save