Changeset 5441 in subversion


Ignore:
Timestamp:
Nov 17, 2011 8:18:48 AM (18 months ago)
Author:
alec
Message:
  • 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
Location:
trunk/plugins/managesieve
Files:
7 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/plugins/managesieve/Changelog

    r5440 r5441  
     1* version 5.0-rc1 [2011-11-17] 
     2----------------------------------------------------------- 
    13- Fixed sorting of scripts, scripts including aware of the sort order 
    24- Fixed import of rules with unsupported tests 
     5- Added 'address' and 'envelope' tests support 
     6- Added 'body' extension support (RFC5173) 
     7- Added 'subaddress' extension support (RFC5233) 
     8- Added comparators support 
     9- Changed Sender/Recipient labels to From/To 
     10- Fixed importing rule names from Ingo 
     11- Fixed handling of extensions disabled in config 
    312 
    413* version 5.0-beta [2011-10-17] 
  • trunk/plugins/managesieve/lib/rcube_sieve.php

    r5300 r5441  
    4545    public $script;                 // rcube_sieve_script object 
    4646    public $current;                // name of currently loaded script 
    47     private $disabled;              // array of disabled extensions 
    4847    private $exts;                  // array of supported extensions 
    4948 
     
    9089 
    9190        $this->exts     = $this->get_extensions(); 
    92         $this->disabled = $disabled; 
     91 
     92        // disable features by config 
     93        if (!empty($disabled)) { 
     94            // we're working on lower-cased names 
     95            $disabled = array_map('strtolower', (array) $disabled); 
     96            foreach ($disabled as $ext) { 
     97                if (($idx = array_search($ext, $this->exts)) !== false) { 
     98                    unset($this->exts[$idx]); 
     99                } 
     100            } 
     101        } 
    93102    } 
    94103 
     
    302311    { 
    303312        // parse 
    304         $script = new rcube_sieve_script($txt, $this->disabled, $this->exts); 
     313        $script = new rcube_sieve_script($txt, $this->exts); 
    305314 
    306315        // fix/convert to Roundcube format 
  • trunk/plugins/managesieve/lib/rcube_sieve_script.php

    r5440 r5441  
    3232    private $capabilities = array(); // Sieve extensions supported by server 
    3333    private $supported = array(     // Sieve extensions supported by class 
    34         'fileinto',                 // RFC3028 
     34        'fileinto',                 // RFC5228 
     35        'envelope',                 // RFC5228 
    3536        'reject',                   // RFC5429 
    3637        'ereject',                  // RFC5429 
     
    4344        'include',                  // draft-ietf-sieve-include-12 
    4445        'variables',                // RFC5229 
    45         // TODO: body, notify 
     46        'body',                     // RFC5173 
     47        'subaddress',               // RFC5233 
     48        // @TODO: enotify/notify, spamtest+virustest, mailbox, date 
    4649    ); 
    4750 
     
    5053     * 
    5154     * @param  string  Script's text content 
    52      * @param  array   List of disabled extensions 
    5355     * @param  array   List of capabilities supported by server 
    5456     */ 
    55     public function __construct($script, $disabled=array(), $capabilities=array()) 
    56     { 
    57         if (!empty($disabled)) { 
    58             // we're working on lower-cased names 
    59             $disabled = array_map('strtolower', (array) $disabled); 
    60             foreach ($disabled as $ext) { 
    61                 if (($idx = array_search($ext, $this->supported)) !== false) { 
     57    public function __construct($script, $capabilities=array()) 
     58    { 
     59        $this->capabilities = array_map('strtolower', (array) $capabilities); 
     60 
     61        // disable features by server capabilities 
     62        if (!empty($this->capabilities)) { 
     63            foreach ($this->supported as $idx => $ext) { 
     64                if (!in_array($ext, $this->capabilities)) { 
    6265                    unset($this->supported[$idx]); 
    6366                } 
    6467            } 
    6568        } 
    66  
    67         $this->capabilities = array_map('strtolower', (array) $capabilities); 
    6869 
    6970        // Parse text content of the script 
     
    183184 
    184185        if (!empty($this->vars)) { 
    185             if (in_array('variables', (array)$this->capabilities)) { 
     186            if (in_array('variables', (array)$this->supported)) { 
    186187                $has_vars = true; 
    187188                array_push($exts, 'variables'); 
     
    223224                        $tests[$i] .= 'size :' . ($test['type']=='under' ? 'under ' : 'over ') . $test['arg']; 
    224225                        break; 
     226 
    225227                    case 'true': 
    226228                        $tests[$i] .= ($test['not'] ? 'false' : 'true'); 
    227229                        break; 
     230 
    228231                    case 'exists': 
    229232                        $tests[$i] .= ($test['not'] ? 'not ' : ''); 
    230233                        $tests[$i] .= 'exists ' . self::escape_string($test['arg']); 
    231234                        break; 
     235 
    232236                    case 'header': 
    233237                        $tests[$i] .= ($test['not'] ? 'not ' : ''); 
    234  
    235                         // relational operator + comparator 
    236                         if (preg_match('/^(value|count)-([gteqnl]{2})/', $test['type'], $m)) { 
    237                             array_push($exts, 'relational'); 
    238                             array_push($exts, 'comparator-i;ascii-numeric'); 
    239  
    240                             $tests[$i] .= 'header :' . $m[1] . ' "' . $m[2] . '" :comparator "i;ascii-numeric"'; 
    241                         } 
    242                         else { 
     238                        $tests[$i] .= 'header'; 
     239 
     240                        if (!empty($test['type'])) { 
     241                            // relational operator + comparator 
     242                            if (preg_match('/^(value|count)-([gteqnl]{2})/', $test['type'], $m)) { 
     243                                array_push($exts, 'relational'); 
     244                                array_push($exts, 'comparator-i;ascii-numeric'); 
     245 
     246                                $tests[$i] .= ' :' . $m[1] . ' "' . $m[2] . '" :comparator "i;ascii-numeric"'; 
     247                            } 
     248                            else { 
     249                                $this->add_comparator($test, $tests[$i], $exts); 
     250 
     251                                if ($test['type'] == 'regex') { 
     252                                    array_push($exts, 'regex'); 
     253                                } 
     254 
     255                                $tests[$i] .= ' :' . $test['type']; 
     256                            } 
     257                        } 
     258 
     259                        $tests[$i] .= ' ' . self::escape_string($test['arg1']); 
     260                        $tests[$i] .= ' ' . self::escape_string($test['arg2']); 
     261                        break; 
     262 
     263                    case 'address': 
     264                    case 'envelope': 
     265                        if ($test['test'] == 'envelope') { 
     266                            array_push($exts, 'envelope'); 
     267                        } 
     268 
     269                        $tests[$i] .= ($test['not'] ? 'not ' : ''); 
     270                        $tests[$i] .= $test['test']; 
     271 
     272                        if (!empty($test['part'])) { 
     273                            $tests[$i] .= ' :' . $test['part']; 
     274                            if ($test['part'] == 'user' || $test['part'] == 'detail') { 
     275                                array_push($exts, 'subaddress'); 
     276                            } 
     277                        } 
     278 
     279                        $this->add_comparator($test, $tests[$i], $exts); 
     280 
     281                        if (!empty($test['type'])) { 
    243282                            if ($test['type'] == 'regex') { 
    244283                                array_push($exts, 'regex'); 
    245284                            } 
    246  
    247                             $tests[$i] .= 'header :' . $test['type']; 
     285                            $tests[$i] .= ' :' . $test['type']; 
    248286                        } 
    249287 
    250288                        $tests[$i] .= ' ' . self::escape_string($test['arg1']); 
    251289                        $tests[$i] .= ' ' . self::escape_string($test['arg2']); 
     290                        break; 
     291 
     292                    case 'body': 
     293                        array_push($exts, 'body'); 
     294 
     295                        $tests[$i] .= ($test['not'] ? 'not ' : '') . 'body'; 
     296 
     297                        $this->add_comparator($test, $tests[$i], $exts); 
     298 
     299                        if (!empty($test['part'])) { 
     300                            $tests[$i] .= ' :' . $test['part']; 
     301 
     302                            if (!empty($test['content']) && $test['part'] == 'content') { 
     303                                $tests[$i] .= ' ' . self::escape_string($test['content']); 
     304                            } 
     305                        } 
     306 
     307                        if (!empty($test['type'])) { 
     308                            if ($test['type'] == 'regex') { 
     309                                array_push($exts, 'regex'); 
     310                            } 
     311                            $tests[$i] .= ' :' . $test['type']; 
     312                        } 
     313 
     314                        $tests[$i] .= ' ' . self::escape_string($test['arg']); 
    252315                        break; 
    253316                    } 
     
    312375                    case 'setflag': 
    313376                    case 'removeflag': 
    314                         if (is_array($this->capabilities) && in_array('imap4flags', $this->capabilities)) 
     377                        if (in_array('imap4flags', $this->supported)) 
    315378                            array_push($exts, 'imap4flags'); 
    316379                        else 
     
    449512            if (empty($options['prefix'])) { 
    450513                $options['prefix'] = true; 
    451                 if ($prefix && strpos($prefix, 'Generated by Ingo')) { 
     514                if ($prefix && strpos($prefix, 'horde.org/ingo')) { 
    452515                    $options['format'] = 'INGO'; 
    453516                } 
     
    560623                for ($i=0, $len=count($tokens); $i<$len; $i++) { 
    561624                    if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) { 
    562                         $i++; 
     625                        $header['comparator'] = $tokens[++$i]; 
    563626                    } 
    564627                    else if (!is_array($tokens[$i]) && preg_match('/^:(count|value)$/i', $tokens[$i])) { 
     
    571634                        $header['arg1'] = $header['arg2']; 
    572635                        $header['arg2'] = $tokens[$i]; 
     636                    } 
     637                } 
     638 
     639                $tests[] = $header; 
     640                break; 
     641 
     642            case 'address': 
     643            case 'envelope': 
     644                $header = array('test' => $token, 'not' => $not, 'arg1' => '', 'arg2' => ''); 
     645                for ($i=0, $len=count($tokens); $i<$len; $i++) { 
     646                    if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) { 
     647                        $header['comparator'] = $tokens[++$i]; 
     648                    } 
     649                    else if (!is_array($tokens[$i]) && preg_match('/^:(is|contains|matches|regex)$/i', $tokens[$i])) { 
     650                        $header['type'] = strtolower(substr($tokens[$i], 1)); 
     651                    } 
     652                    else if (!is_array($tokens[$i]) && preg_match('/^:(localpart|domain|all|user|detail)$/i', $tokens[$i])) { 
     653                        $header['part'] = strtolower(substr($tokens[$i], 1)); 
     654                    } 
     655                    else { 
     656                        $header['arg1'] = $header['arg2']; 
     657                        $header['arg2'] = $tokens[$i]; 
     658                    } 
     659                } 
     660 
     661                $tests[] = $header; 
     662                break; 
     663 
     664            case 'body': 
     665                $header = array('test' => 'body', 'not' => $not, 'arg' => ''); 
     666                for ($i=0, $len=count($tokens); $i<$len; $i++) { 
     667                    if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) { 
     668                        $header['comparator'] = $tokens[++$i]; 
     669                    } 
     670                    else if (!is_array($tokens[$i]) && preg_match('/^:(is|contains|matches|regex)$/i', $tokens[$i])) { 
     671                        $header['type'] = strtolower(substr($tokens[$i], 1)); 
     672                    } 
     673                    else if (!is_array($tokens[$i]) && preg_match('/^:(raw|content|text)$/i', $tokens[$i])) { 
     674                        $header['part'] = strtolower(substr($tokens[$i], 1)); 
     675 
     676                        if ($header['part'] == 'content') { 
     677                            $header['content'] = $tokens[++$i]; 
     678                        } 
     679                    } 
     680                    else { 
     681                        $header['arg'] = $tokens[$i]; 
    573682                    } 
    574683                } 
     
    743852 
    744853        return $result; 
     854    } 
     855 
     856    /** 
     857     * 
     858     */ 
     859    private function add_comparator($test, &$out, &$exts) 
     860    { 
     861        if (empty($test['comparator'])) { 
     862            return; 
     863        } 
     864 
     865        if ($test['comparator'] == 'i;ascii-numeric') { 
     866            array_push($exts, 'relational'); 
     867            array_push($exts, 'comparator-i;ascii-numeric'); 
     868        } 
     869        else if (!in_array($test['comparator'], array('i;octet', 'i;ascii-casemap'))) { 
     870            array_push($exts, 'comparator-' . $test['comparator']); 
     871        } 
     872 
     873        // skip default comparator 
     874        if ($test['comparator'] != 'i;ascii-casemap') { 
     875            $out .= ' :comparator ' . self::escape_string($test['comparator']); 
     876        } 
    745877    } 
    746878 
  • trunk/plugins/managesieve/localization/en_US.inc

    r5340 r5441  
    8383$labels['nextstep'] = 'Next Step'; 
    8484$labels['...'] = '...'; 
     85$labels['advancedopts'] = 'Advanced options'; 
     86$labels['body'] = 'Body'; 
     87$labels['address'] = 'address'; 
     88$labels['envelope'] = 'envelope'; 
     89$labels['modifier'] = 'modifier:'; 
     90$labels['text'] = 'text'; 
     91$labels['undecoded'] = 'undecoded (raw)'; 
     92$labels['contenttype'] = 'content type'; 
     93$labels['modtype'] = 'type:'; 
     94$labels['allparts'] = 'all'; 
     95$labels['domain'] = 'domain'; 
     96$labels['localpart'] = 'local part'; 
     97$labels['user'] = 'user'; 
     98$labels['detail'] = 'detail'; 
     99$labels['comparator'] = 'comparator:'; 
     100$labels['default'] = 'default'; 
     101$labels['octet'] = 'strict (octet)'; 
     102$labels['asciicasemap'] = 'case insensitive (ascii-casemap)'; 
     103$labels['asciinumeric'] = 'numeric (ascii-numeric)'; 
    85104 
    86105$messages = array(); 
  • trunk/plugins/managesieve/localization/pl_PL.inc

    r5340 r5441  
    9797$labels['nextstep'] = 'Następny krok'; 
    9898$labels['...'] = '...'; 
     99$labels['advancedopts'] = 'Zaawansowane opcje'; 
     100$labels['body'] = 'Treść'; 
     101$labels['address'] = 'adres'; 
     102$labels['envelope'] = 'koperta (envelope)'; 
     103$labels['modifier'] = 'modyfikator:'; 
     104$labels['text'] = 'tekst'; 
     105$labels['undecoded'] = 'nie (raw)'; 
     106$labels['contenttype'] = 'typ części (content type)'; 
     107$labels['modtype'] = 'typ:'; 
     108$labels['allparts'] = 'wszystkie'; 
     109$labels['domain'] = 'domena'; 
     110$labels['localpart'] = 'część lokalna'; 
     111$labels['user'] = 'uÅŒytkownik'; 
     112$labels['detail'] = 'detal'; 
     113$labels['comparator'] = 'komparator:'; 
     114$labels['default'] = 'domyślny'; 
     115$labels['octet'] = 'dokładny (octet)'; 
     116$labels['asciicasemap'] = 'nierozróŌniajÄ 
     117cy wielkości liter (ascii-casemap)'; 
     118$labels['asciinumeric'] = 'numeryczny (ascii-numeric)'; 
    99119 
    100120$messages = array(); 
  • trunk/plugins/managesieve/managesieve.js

    r5348 r5441  
    543543    op = document.getElementById('rule_op' + id), 
    544544    target = document.getElementById('rule_target' + id), 
    545     header = document.getElementById('custom_header' + id); 
     545    header = document.getElementById('custom_header' + id), 
     546    mod = document.getElementById('rule_mod' + id), 
     547    trans = document.getElementById('rule_trans' + id), 
     548    comp = document.getElementById('rule_comp' + id); 
    546549 
    547550  if (obj.value == 'size') { 
     
    550553    target.style.display = 'none'; 
    551554    header.style.display = 'none'; 
     555    mod.style.display = 'none'; 
     556    trans.style.display = 'none'; 
     557    comp.style.display = 'none'; 
    552558  } 
    553559  else { 
     
    555561    size.style.display = 'none'; 
    556562    op.style.display = 'inline'; 
     563    comp.style.display = ''; 
    557564    rule_op_select(id); 
     565    mod.style.display = obj.value == 'body' ? 'none' : 'block'; 
     566    trans.style.display = obj.value == 'body' ? 'block' : 'none'; 
    558567  } 
    559568 
     
    569578}; 
    570579 
     580function rule_trans_select(id) 
     581{ 
     582  var obj = document.getElementById('rule_trans_op' + id), 
     583    target = document.getElementById('rule_trans_type' + id); 
     584 
     585  target.style.display = obj.value != 'content' ? 'none' : 'inline'; 
     586}; 
     587 
     588function rule_mod_select(id) 
     589{ 
     590  var obj = document.getElementById('rule_mod_op' + id), 
     591    target = document.getElementById('rule_mod_type' + id); 
     592 
     593  target.style.display = obj.value != 'address' && obj.value != 'envelope' ? 'none' : 'inline'; 
     594}; 
     595 
    571596function rule_join_radio(value) 
    572597{ 
    573598  $('#rules').css('display', value == 'any' ? 'none' : 'block'); 
    574599}; 
     600 
     601function rule_adv_switch(id, elem) 
     602{ 
     603  var elem = $(elem), enabled = elem.hasClass('hide'), adv = $('#rule_advanced'+id); 
     604 
     605  if (enabled) { 
     606    adv.hide(); 
     607    elem.removeClass('hide').addClass('show'); 
     608  } 
     609  else { 
     610    adv.show(); 
     611    elem.removeClass('show').addClass('hide'); 
     612  } 
     613} 
    575614 
    576615function action_type_select(id) 
  • trunk/plugins/managesieve/managesieve.php

    r5348 r5441  
    4646    private $active = array(); 
    4747    private $headers = array( 
    48         'subject'   => 'Subject', 
    49         'sender'    => 'From', 
    50         'recipient' => 'To', 
     48        'subject' => 'Subject', 
     49        'from'    => 'From', 
     50        'to'      => 'To', 
     51    ); 
     52    private $addr_headers = array( 
     53        // Required 
     54        "from", "to", "cc", "bcc", "sender", "resent-from", "resent-to", 
     55        // Additional (RFC 822 / RFC 2822) 
     56        "reply-to", "resent-reply-to", "resent-sender", "resent-cc", "resent-bcc", 
     57        // Non-standard (RFC 2076, draft-palme-mailext-headers-08.txt) 
     58        "for-approval", "for-handling", "for-comment", "apparently-to", "errors-to", 
     59        "delivered-to", "return-receipt-to", "x-admin", "read-receipt-to", 
     60        "x-confirm-reading-to", "return-receipt-requested", 
     61        "registered-mail-reply-requested-by", "mail-followup-to", "mail-reply-to", 
     62        "abuse-reports-to", "x-complaints-to", "x-report-abuse-to", 
     63        // Undocumented 
     64        "x-beenthere", 
    5165    ); 
    5266 
     
    589603            $sizetargets    = get_input_value('_rule_size_target', RCUBE_INPUT_POST); 
    590604            $targets        = get_input_value('_rule_target', RCUBE_INPUT_POST, true); 
     605            $mods           = get_input_value('_rule_mod', RCUBE_INPUT_POST); 
     606            $mod_types      = get_input_value('_rule_mod_type', RCUBE_INPUT_POST); 
     607            $body_trans     = get_input_value('_rule_trans', RCUBE_INPUT_POST); 
     608            $body_types     = get_input_value('_rule_trans_type', RCUBE_INPUT_POST, true); 
     609            $comparators    = get_input_value('_rule_comp', RCUBE_INPUT_POST); 
    591610            $act_types      = get_input_value('_action_type', RCUBE_INPUT_POST, true); 
    592611            $mailboxes      = get_input_value('_action_mailbox', RCUBE_INPUT_POST, true); 
     
    626645            else { 
    627646                foreach ($headers as $idx => $header) { 
    628                     $header = $this->strip_value($header); 
    629                     $target = $this->strip_value($targets[$idx], true); 
    630                     $op     = $this->strip_value($ops[$idx]); 
    631  
    632                     // normal header 
    633                     if (in_array($header, $this->headers)) { 
    634                         if (preg_match('/^not/', $op)) 
     647                    $header     = $this->strip_value($header); 
     648                    $target     = $this->strip_value($targets[$idx], true); 
     649                    $operator   = $this->strip_value($ops[$idx]); 
     650                    $comparator = $this->strip_value($comparators[$idx]); 
     651 
     652                    if ($header == 'size') { 
     653                        $sizeop     = $this->strip_value($sizeops[$idx]); 
     654                        $sizeitem   = $this->strip_value($items[$idx]); 
     655                        $sizetarget = $this->strip_value($sizetargets[$idx]); 
     656 
     657                        $this->form['tests'][$i]['test'] = 'size'; 
     658                        $this->form['tests'][$i]['type'] = $sizeop; 
     659                        $this->form['tests'][$i]['arg']  = $sizetarget; 
     660 
     661                        if ($sizetarget == '') 
     662                            $this->errors['tests'][$i]['sizetarget'] = $this->gettext('cannotbeempty'); 
     663                        else if (!preg_match('/^[0-9]+(K|M|G)?$/i', $sizetarget.$sizeitem, $m)) { 
     664                            $this->errors['tests'][$i]['sizetarget'] = $this->gettext('forbiddenchars'); 
     665                            $this->form['tests'][$i]['item'] = $sizeitem; 
     666                        } 
     667                        else 
     668                            $this->form['tests'][$i]['arg'] .= $m[1]; 
     669                    } 
     670                    else if ($header == 'body') { 
     671                        $trans      = $this->strip_value($body_trans[$idx]); 
     672                        $trans_type = $this->strip_value($body_types[$idx], true); 
     673 
     674                        if (preg_match('/^not/', $operator)) 
    635675                            $this->form['tests'][$i]['not'] = true; 
    636                         $type = preg_replace('/^not/', '', $op); 
     676                        $type = preg_replace('/^not/', '', $operator); 
     677 
     678                        if ($type == 'exists') { 
     679                            $this->errors['tests'][$i]['op'] = true; 
     680                        } 
     681 
     682                        $this->form['tests'][$i]['test'] = 'body'; 
     683                        $this->form['tests'][$i]['type'] = $type; 
     684                        $this->form['tests'][$i]['arg']  = $target; 
     685 
     686                        if ($target == '' && $type != 'exists') 
     687                            $this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty'); 
     688                        else if (preg_match('/^(value|count)-/', $type) && !preg_match('/[0-9]+/', $target)) 
     689                            $this->errors['tests'][$i]['target'] = $this->gettext('forbiddenchars'); 
     690 
     691                        $this->form['tests'][$i]['part'] = $trans; 
     692                        if ($trans == 'content') { 
     693                            $this->form['tests'][$i]['content'] = $trans_type; 
     694                        } 
     695                    } 
     696                    else { 
     697                        $cust_header = $headers = $this->strip_value($cust_headers[$idx]); 
     698                        $mod      = $this->strip_value($mods[$idx]); 
     699                        $mod_type = $this->strip_value($mod_types[$idx]); 
     700 
     701                        if (preg_match('/^not/', $operator)) 
     702                            $this->form['tests'][$i]['not'] = true; 
     703                        $type = preg_replace('/^not/', '', $operator); 
     704 
     705                        if ($header == '...') { 
     706                            $headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY); 
     707 
     708                            if (!count($headers)) 
     709                                $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); 
     710                            else { 
     711                                foreach ($headers as $hr) 
     712                                    if (!preg_match('/^[a-z0-9-]+$/i', $hr)) 
     713                                        $this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars'); 
     714                            } 
     715 
     716                            if (empty($this->errors['tests'][$i]['header'])) 
     717                                $cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers; 
     718                        } 
    637719 
    638720                        if ($type == 'exists') { 
    639721                            $this->form['tests'][$i]['test'] = 'exists'; 
    640                             $this->form['tests'][$i]['arg'] = $header; 
     722                            $this->form['tests'][$i]['arg'] = $header == '...' ? $cust_header : $header; 
    641723                        } 
    642724                        else { 
     725                            $test   = 'header'; 
     726                            $header = $header == '...' ? $cust_header : $header; 
     727 
     728                            if ($mod == 'address' || $mod == 'envelope') { 
     729                                $found = false; 
     730                                if (empty($this->errors['tests'][$i]['header'])) { 
     731                                    foreach ((array)$header as $hdr) { 
     732                                        if (!in_array(strtolower(trim($hdr)), $this->addr_headers)) 
     733                                            $found = true; 
     734                                    } 
     735                                } 
     736                                if (!$found) 
     737                                    $test = $mod; 
     738                            } 
     739 
    643740                            $this->form['tests'][$i]['type'] = $type; 
    644                             $this->form['tests'][$i]['test'] = 'header'; 
     741                            $this->form['tests'][$i]['test'] = $test; 
    645742                            $this->form['tests'][$i]['arg1'] = $header; 
    646743                            $this->form['tests'][$i]['arg2'] = $target; 
     
    650747                            else if (preg_match('/^(value|count)-/', $type) && !preg_match('/[0-9]+/', $target)) 
    651748                                $this->errors['tests'][$i]['target'] = $this->gettext('forbiddenchars'); 
     749 
     750                            if ($mod) { 
     751                                $this->form['tests'][$i]['part'] = $mod_type; 
     752                            } 
    652753                        } 
    653754                    } 
    654                     else 
    655                         switch ($header) { 
    656                         case 'size': 
    657                             $sizeop     = $this->strip_value($sizeops[$idx]); 
    658                             $sizeitem   = $this->strip_value($items[$idx]); 
    659                             $sizetarget = $this->strip_value($sizetargets[$idx]); 
    660  
    661                             $this->form['tests'][$i]['test'] = 'size'; 
    662                             $this->form['tests'][$i]['type'] = $sizeop; 
    663                             $this->form['tests'][$i]['arg']  = $sizetarget.$sizeitem; 
    664  
    665                             if ($sizetarget == '') 
    666                                 $this->errors['tests'][$i]['sizetarget'] = $this->gettext('cannotbeempty'); 
    667                             else if (!preg_match('/^[0-9]+(K|M|G)*$/i', $sizetarget)) 
    668                                 $this->errors['tests'][$i]['sizetarget'] = $this->gettext('forbiddenchars'); 
    669                             break; 
    670                         case '...': 
    671                             $cust_header = $headers = $this->strip_value($cust_headers[$idx]); 
    672  
    673                             if (preg_match('/^not/', $op)) 
    674                                 $this->form['tests'][$i]['not'] = true; 
    675                             $type = preg_replace('/^not/', '', $op); 
    676  
    677                             if ($cust_header == '') 
    678                                 $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); 
    679                             else { 
    680                                 $headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY); 
    681  
    682                                 if (!count($headers)) 
    683                                     $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); 
    684                                 else { 
    685                                     foreach ($headers as $hr) 
    686                                         if (!preg_match('/^[a-z0-9-]+$/i', $hr)) 
    687                                             $this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars'); 
    688                                 } 
    689                             } 
    690  
    691                             if (empty($this->errors['tests'][$i]['header'])) 
    692                                 $cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers; 
    693  
    694                             if ($type == 'exists') { 
    695                                 $this->form['tests'][$i]['test'] = 'exists'; 
    696                                 $this->form['tests'][$i]['arg']  = $cust_header; 
    697                             } 
    698                             else { 
    699                                 $this->form['tests'][$i]['test'] = 'header'; 
    700                                 $this->form['tests'][$i]['type'] = $type; 
    701                                 $this->form['tests'][$i]['arg1'] = $cust_header; 
    702                                 $this->form['tests'][$i]['arg2'] = $target; 
    703  
    704                                 if ($target == '') 
    705                                     $this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty'); 
    706                                 else if (preg_match('/^(value|count)-/', $type) && !preg_match('/[0-9]+/', $target)) 
    707                                     $this->errors['tests'][$i]['target'] = $this->gettext('forbiddenchars'); 
    708                             } 
    709                             break; 
    710                         } 
     755 
     756                    if ($header != 'size' && $comparator) { 
     757                        if (preg_match('/^(value|count)/', $this->form['tests'][$i]['type'])) 
     758                            $comparator = 'i;ascii-numeric'; 
     759 
     760                        $this->form['tests'][$i]['comparator'] = $comparator; 
     761                    } 
     762 
    711763                    $i++; 
    712764                } 
     
    11411193        $rows_num = isset($this->form) ? sizeof($this->form['tests']) : sizeof($this->script[$fid]['tests']); 
    11421194 
    1143         $out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : ''; 
    1144  
    1145         $out .= '<table><tr><td class="rowactions">'; 
    1146  
    11471195        // headers select 
    11481196        $select_header = new html_select(array('name' => "_header[]", 'id' => 'header'.$id, 
     
    11501198        foreach($this->headers as $name => $val) 
    11511199            $select_header->add(Q($this->gettext($name)), Q($val)); 
     1200        if (in_array('body', $this->exts)) 
     1201            $select_header->add(Q($this->gettext('body')), 'body'); 
    11521202        $select_header->add(Q($this->gettext('size')), 'size'); 
    11531203        $select_header->add(Q($this->gettext('...')), '...'); 
    11541204 
    11551205        // TODO: list arguments 
    1156  
    1157         if ((isset($rule['test']) && $rule['test'] == 'header') 
    1158             && !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers)) 
    1159             $out .= $select_header->show($rule['arg1']); 
     1206        $aout = ''; 
     1207 
     1208        if ((isset($rule['test']) && in_array($rule['test'], array('header', 'address', 'envelope'))) 
     1209            && !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers) 
     1210        ) { 
     1211            $aout .= $select_header->show($rule['arg1']); 
     1212        } 
    11601213        else if ((isset($rule['test']) && $rule['test'] == 'exists') 
    1161             && !is_array($rule['arg']) && in_array($rule['arg'], $this->headers)) 
    1162             $out .= $select_header->show($rule['arg']); 
     1214            && !is_array($rule['arg']) && in_array($rule['arg'], $this->headers) 
     1215        ) { 
     1216            $aout .= $select_header->show($rule['arg']); 
     1217        } 
    11631218        else if (isset($rule['test']) && $rule['test'] == 'size') 
    1164             $out .= $select_header->show('size'); 
     1219            $aout .= $select_header->show('size'); 
     1220        else if (isset($rule['test']) && $rule['test'] == 'body') 
     1221            $aout .= $select_header->show('body'); 
    11651222        else if (isset($rule['test']) && $rule['test'] != 'true') 
    1166             $out .= $select_header->show('...'); 
     1223            $aout .= $select_header->show('...'); 
    11671224        else 
    1168             $out .= $select_header->show(); 
    1169  
    1170         $out .= '</td><td class="rowtargets">'; 
    1171  
    1172         if ((isset($rule['test']) && $rule['test'] == 'header') 
    1173             && (is_array($rule['arg1']) || !in_array($rule['arg1'], $this->headers))) 
    1174             $custom = is_array($rule['arg1']) ? implode(', ', $rule['arg1']) : $rule['arg1']; 
    1175         else if ((isset($rule['test']) && $rule['test'] == 'exists') 
    1176             && (is_array($rule['arg']) || !in_array($rule['arg'], $this->headers))) 
    1177             $custom = is_array($rule['arg']) ? implode(', ', $rule['arg']) : $rule['arg']; 
    1178  
    1179         $out .= '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '"> 
     1225            $aout .= $select_header->show(); 
     1226 
     1227        if (isset($rule['test']) && in_array($rule['test'], array('header', 'address', 'envelope'))) { 
     1228            if (is_array($rule['arg1'])) 
     1229                $custom = implode(', ', $rule['arg1']); 
     1230            else if (!in_array($rule['arg1'], $this->headers)) 
     1231                $custom = $rule['arg1']; 
     1232        } 
     1233        else if (isset($rule['test']) && $rule['test'] == 'exists') { 
     1234            if (is_array($rule['arg'])) 
     1235                $custom = implode(', ', $rule['arg']); 
     1236            else if (!in_array($rule['arg'], $this->headers)) 
     1237                $custom = $rule['arg']; 
     1238        } 
     1239 
     1240        $tout = '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '"> 
    11801241            <input type="text" name="_custom_header[]" id="custom_header_i'.$id.'" ' 
    11811242            . $this->error_class($id, 'test', 'header', 'custom_header_i') 
     
    12161277        // target input (TODO: lists) 
    12171278 
    1218         if ($rule['test'] == 'header') { 
    1219             $out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['type']); 
     1279        if (in_array($rule['test'], array('header', 'address', 'envelope'))) { 
     1280            $tout .= $select_op->show(($rule['not'] ? 'not' : '').$rule['type']); 
    12201281            $target = $rule['arg2']; 
    12211282        } 
    12221283        else if ($rule['test'] == 'size') { 
    1223             $out .= $select_op->show(); 
    1224             if (preg_match('/^([0-9]+)(K|M|G)*$/', $rule['arg'], $matches)) { 
     1284            $tout .= $select_op->show(); 
     1285            if (preg_match('/^([0-9]+)(K|M|G)?$/', $rule['arg'], $matches)) { 
    12251286                $sizetarget = $matches[1]; 
    12261287                $sizeitem = $matches[2]; 
    12271288            } 
     1289            else { 
     1290                $sizetarget = $rule['arg']; 
     1291                $sizeitem = $rule['item']; 
     1292            } 
    12281293        } 
    12291294        else { 
    1230             $out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['test']); 
    1231             $target = ''; 
    1232         } 
    1233  
    1234         $out .= '<input type="text" name="_rule_target[]" id="rule_target' .$id. '" 
     1295            $tout .= $select_op->show(($rule['not'] ? 'not' : '').$rule['test']); 
     1296            $target = $rule['test'] == 'body' ? $rule['arg'] : ''; 
     1297        } 
     1298 
     1299        $tout .= '<input type="text" name="_rule_target[]" id="rule_target' .$id. '" 
    12351300            value="' .Q($target). '" size="20" ' . $this->error_class($id, 'test', 'target', 'rule_target') 
    12361301            . ' style="display:' . ($rule['test']!='size' && $rule['test'] != 'exists' ? 'inline' : 'none') . '" />'."\n"; 
    12371302 
    12381303        $select_size_op = new html_select(array('name' => "_rule_size_op[]", 'id' => 'rule_size_op'.$id)); 
     1304        $select_size_op->add(Q($this->gettext('filterover')), 'over'); 
    12391305        $select_size_op->add(Q($this->gettext('filterunder')), 'under'); 
    1240         $select_size_op->add(Q($this->gettext('filterover')), 'over'); 
    1241  
    1242         $out .= '<div id="rule_size' .$id. '" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">'; 
    1243         $out .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : ''); 
    1244         $out .= '<input type="text" name="_rule_size_target[]" id="rule_size_i'.$id.'" value="'.$sizetarget.'" size="10" '  
     1306 
     1307        $tout .= '<div id="rule_size' .$id. '" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">'; 
     1308        $tout .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : ''); 
     1309        $tout .= '<input type="text" name="_rule_size_target[]" id="rule_size_i'.$id.'" value="'.$sizetarget.'" size="10" '  
    12451310            . $this->error_class($id, 'test', 'sizetarget', 'rule_size_i') .' /> 
    12461311            <input type="radio" name="_rule_size_item['.$id.']" value=""' 
     
    12521317            <input type="radio" name="_rule_size_item['.$id.']" value="G"' 
    12531318                . ($sizeitem=='G' ? ' checked="checked"' : '') .' class="radio" />'.rcube_label('GB'); 
    1254         $out .= '</div>'; 
     1319        $tout .= '</div>'; 
     1320 
     1321        // Advanced modifiers (address, envelope) 
     1322        $select_mod = new html_select(array('name' => "_rule_mod[]", 'id' => 'rule_mod_op'.$id, 
     1323            'onchange' => 'rule_mod_select(' .$id .')')); 
     1324        $select_mod->add(Q($this->gettext('none')), ''); 
     1325        $select_mod->add(Q($this->gettext('address')), 'address'); 
     1326        if (in_array('envelope', $this->exts)) 
     1327            $select_mod->add(Q($this->gettext('envelope')), 'envelope'); 
     1328 
     1329        $select_type = new html_select(array('name' => "_rule_mod_type[]", 'id' => 'rule_mod_type'.$id)); 
     1330        $select_type->add(Q($this->gettext('allparts')), 'all'); 
     1331        $select_type->add(Q($this->gettext('domain')), 'domain'); 
     1332        $select_type->add(Q($this->gettext('localpart')), 'localpart'); 
     1333        if (in_array('subaddress', $this->exts)) { 
     1334            $select_type->add(Q($this->gettext('user')), 'user'); 
     1335            $select_type->add(Q($this->gettext('detail')), 'detail'); 
     1336        } 
     1337 
     1338        $need_mod = $rule['test'] != 'size' && $rule['test'] != 'body'; 
     1339        $mout = '<div id="rule_mod' .$id. '" class="adv" style="display:' . ($need_mod ? 'block' : 'none') .'">'; 
     1340        $mout .= ' <span>'; 
     1341        $mout .= Q($this->gettext('modifier')) . ' '; 
     1342        $mout .= $select_mod->show($rule['test']); 
     1343        $mout .= '</span>'; 
     1344        $mout .= ' <span id="rule_mod_type' . $id . '"'; 
     1345        $mout .= ' style="display:' . (in_array($rule['test'], array('address', 'envelope')) ? 'inline' : 'none') .'">'; 
     1346        $mout .= Q($this->gettext('modtype')) . ' '; 
     1347        $mout .= $select_type->show($rule['part']); 
     1348        $mout .= '</span>'; 
     1349        $mout .= '</div>'; 
     1350 
     1351        // Advanced modifiers (body transformations) 
     1352        $select_mod = new html_select(array('name' => "_rule_trans[]", 'id' => 'rule_trans_op'.$id, 
     1353            'onchange' => 'rule_trans_select(' .$id .')')); 
     1354        $select_mod->add(Q($this->gettext('text')), 'text'); 
     1355        $select_mod->add(Q($this->gettext('undecoded')), 'raw'); 
     1356        $select_mod->add(Q($this->gettext('contenttype')), 'content'); 
     1357 
     1358        $mout .= '<div id="rule_trans' .$id. '" class="adv" style="display:' . ($rule['test'] == 'body' ? 'block' : 'none') .'">'; 
     1359        $mout .= ' <span>'; 
     1360        $mout .= Q($this->gettext('modifier')) . ' '; 
     1361        $mout .= $select_mod->show($rule['part']); 
     1362        $mout .= '<input type="text" name="_rule_trans_type[]" id="rule_trans_type'.$id 
     1363            . '" value="'.(is_array($rule['content']) ? implode(',', $rule['content']) : $rule['content']) 
     1364            .'" size="20" style="display:' . ($rule['part'] == 'content' ? 'inline' : 'none') .'"' 
     1365            . $this->error_class($id, 'test', 'part', 'rule_trans_type') .' />'; 
     1366        $mout .= '</span>'; 
     1367        $mout .= '</div>'; 
     1368 
     1369        // Advanced modifiers (body transformations) 
     1370        $select_comp = new html_select(array('name' => "_rule_comp[]", 'id' => 'rule_comp_op'.$id)); 
     1371        $select_comp->add(Q($this->gettext('default')), ''); 
     1372        $select_comp->add(Q($this->gettext('octet')), 'i;octet'); 
     1373        $select_comp->add(Q($this->gettext('asciicasemap')), 'i;ascii-casemap'); 
     1374        if (in_array('comparator-i;ascii-numeric', $this->exts)) { 
     1375            $select_comp->add(Q($this->gettext('asciinumeric')), 'i;ascii-numeric'); 
     1376        } 
     1377 
     1378        $mout .= '<div id="rule_comp' .$id. '" class="adv" style="display:' . ($rule['test'] != 'size' ? 'block' : 'none') .'">'; 
     1379        $mout .= ' <span>'; 
     1380        $mout .= Q($this->gettext('comparator')) . ' '; 
     1381        $mout .= $select_comp->show($rule['comparator']); 
     1382        $mout .= '</span>'; 
     1383        $mout .= '</div>'; 
     1384 
     1385        // Build output table 
     1386        $out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : ''; 
     1387        $out .= '<table><tr>'; 
     1388        $out .= '<td class="advbutton">'; 
     1389        $out .= '<a href="#" id="ruleadv' . $id .'" title="'. Q($this->gettext('advancedopts')). '" 
     1390            onclick="rule_adv_switch(' . $id .', this)" class="show">&nbsp;&nbsp;</a>'; 
     1391        $out .= '</td>'; 
     1392        $out .= '<td class="rowactions">' . $aout . '</td>'; 
     1393        $out .= '<td class="rowtargets">' . $tout . "\n"; 
     1394        $out .= '<div id="rule_advanced' .$id. '" style="display:none">' . $mout . '</div>'; 
    12551395        $out .= '</td>'; 
    12561396 
     
    12611401        $out .= '<a href="#" id="ruledel' . $id .'" title="'. Q($this->gettext('del')). '" 
    12621402            onclick="rcmail.managesieve_ruledel(' . $id .')" class="button del' . ($rows_num<2 ? ' disabled' : '') .'"></a>'; 
    1263         $out .= '</td></tr></table>'; 
     1403        $out .= '</td>'; 
     1404        $out .= '</tr></table>'; 
    12641405 
    12651406        $out .= $div ? "</div>\n" : ''; 
  • trunk/plugins/managesieve/skins/default/managesieve.css

    r5340 r5441  
    150150} 
    151151 
     152td 
     153{ 
     154  vertical-align: top; 
     155} 
     156 
     157td.advbutton 
     158{ 
     159  width: 1%; 
     160} 
     161 
     162td.advbutton a 
     163{ 
     164  display: block; 
     165  padding-top: 14px; 
     166  height: 6px; 
     167  width: 12px; 
     168  text-decoration: none; 
     169} 
     170 
     171td.advbutton a.show 
     172{ 
     173  background: url(images/down_small.gif) center no-repeat; 
     174} 
     175 
     176td.advbutton a.hide 
     177{ 
     178  background: url(images/up_small.gif) center no-repeat; 
     179} 
     180 
    152181td.rowbuttons 
    153182{ 
     
    170199} 
    171200 
     201td.rowtargets div.adv 
     202{ 
     203  padding-top: 3px; 
     204} 
     205 
    172206input.disabled, input.disabled:hover 
    173207{ 
     
    184218{ 
    185219  border: 0; 
     220  margin-top: 0; 
    186221} 
    187222 
     
    191226} 
    192227 
     228td.rowtargets span, 
    193229span.label 
    194230{ 
     
    244280  width: 30px; 
    245281  height: 20px; 
    246   margin-right: 4px;  
     282  margin-right: 4px; 
    247283  display: inline-block; 
    248284} 
  • trunk/plugins/managesieve/tests/parser.phpt

    r5440 r5441  
    77 
    88$txt = ' 
    9 require ["fileinto","reject"]; 
     9require ["fileinto","reject","envelope"]; 
    1010# rule:[spam] 
    1111if anyof (header :contains "X-DSPAM-Result" "Spam") 
     
    1515} 
    1616# rule:[test1] 
    17 if anyof (header :contains ["From","To"] "test@domain.tld") 
     17if anyof (header :comparator "i;ascii-casemap" :contains ["From","To"] "test@domain.tld") 
    1818{ 
    1919        discard; 
     
    2121} 
    2222# rule:[test2] 
    23 if anyof (not header :contains ["Subject"] "[test]", header :contains "Subject" "[test2]") 
     23if anyof (not header :comparator "i;octet" :contains ["Subject"] "[test]", header :contains "Subject" "[test2]") 
    2424{ 
    2525        fileinto "test"; 
     
    4747} 
    4848fileinto "Test"; 
     49# rule:[address test] 
     50if address :all :is "From" "nagios@domain.tld" 
     51{ 
     52        fileinto "domain.tld"; 
     53        stop; 
     54} 
     55# rule:[envelope test] 
     56if envelope :domain :is "From" "domain.tld" 
     57{ 
     58        fileinto "domain.tld"; 
     59        stop; 
     60} 
    4961'; 
    5062 
     
    5264echo $s->as_text(); 
    5365 
     66// ------------------------------------------------------------------------------- 
    5467?> 
    5568--EXPECT-- 
    56 require ["fileinto","reject"]; 
     69require ["fileinto","reject","envelope"]; 
    5770# rule:[spam] 
    5871if header :contains "X-DSPAM-Result" "Spam" 
     
    6881} 
    6982# rule:[test2] 
    70 if anyof (not header :contains "Subject" "[test]", header :contains "Subject" "[test2]") 
     83if anyof (not header :comparator "i;octet" :contains "Subject" "[test]", header :contains "Subject" "[test2]") 
    7184{ 
    7285        fileinto "test"; 
     
    94107} 
    95108fileinto "Test"; 
     109# rule:[address test] 
     110if address :all :is "From" "nagios@domain.tld" 
     111{ 
     112        fileinto "domain.tld"; 
     113        stop; 
     114} 
     115# rule:[envelope test] 
     116if envelope :domain :is "From" "domain.tld" 
     117{ 
     118        fileinto "domain.tld"; 
     119        stop; 
     120} 
  • trunk/plugins/managesieve/tests/parser_imapflags.phpt

    r5437 r5441  
    1515'; 
    1616 
    17 $s = new rcube_sieve_script($txt); 
     17$s = new rcube_sieve_script($txt, array('imapflags')); 
    1818echo $s->as_text(); 
    1919 
  • trunk/plugins/managesieve/tests/parser_kep14.phpt

    r5340 r5441  
    1111'; 
    1212 
    13 $s = new rcube_sieve_script($txt, array()); 
     13$s = new rcube_sieve_script($txt, array('body')); 
    1414echo $s->as_text(); 
    1515 
Note: See TracChangeset for help on using the changeset viewer.