X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=include%2Fsieve%2Fclass_semantics.inc;h=1c00051c052bb1f477b3eead6c19f9433e7ce445;hb=0d96e184dc6107bff6f32f24b4cda64ddd01c35a;hp=e37d5c6313541234afa95c7d207867dbcef42ea4;hpb=003d76f426422c935a4fb0914247eea28bdf0ab3;p=gosa.git diff --git a/include/sieve/class_semantics.inc b/include/sieve/class_semantics.inc index e37d5c631..1c00051c0 100644 --- a/include/sieve/class_semantics.inc +++ b/include/sieve/class_semantics.inc @@ -1,22 +1,24 @@ command_ = $command; - $this->unknown = false; switch ($command) { @@ -27,7 +29,7 @@ class Semantics case 'require': /* require */ $this->s_ = array( - 'valid_after' => array('script-start', 'require'), + 'valid_after' => '(script-start|require)', 'arguments' => array( array('class' => 'string', 'list' => true, 'name' => 'require-string', 'occurrences' => '1', 'call' => 'setRequire_', 'values' => array( array('occurrences' => '+', 'regex' => '"'. $this->requireStrings_ .'"'), @@ -40,8 +42,7 @@ class Semantics case 'if': /* if */ $this->s_ = array( - 'valid_after' => array('script-start', 'require', 'if', 'elsif', 'else', - 'reject', 'fileinto', 'redirect', 'stop', 'keep', 'discard'), + 'valid_after' => str_replace('(', '(script-start|', $this->nonTestCommands_), 'arguments' => array( array('class' => 'identifier', 'occurrences' => '1', 'values' => array( array('occurrences' => '1', 'regex' => $this->testCommands_, 'name' => 'test') @@ -56,7 +57,7 @@ class Semantics case 'elsif': /* elsif */ $this->s_ = array( - 'valid_after' => array('if', 'elsif'), + 'valid_after' => '(if|elsif)', 'arguments' => array( array('class' => 'identifier', 'occurrences' => '1', 'values' => array( array('occurrences' => '1', 'regex' => $this->testCommands_, 'name' => 'test') @@ -71,7 +72,7 @@ class Semantics case 'else': /* else */ $this->s_ = array( - 'valid_after' => array('if', 'elsif'), + 'valid_after' => '(if|elsif)', 'arguments' => array( array('class' => 'block-start', 'occurrences' => '1', 'values' => array( array('occurrences' => '1', 'regex' => '{', 'name' => 'block') @@ -84,22 +85,24 @@ class Semantics /******************* * action commands */ + case 'discard': case 'keep': case 'stop': - case 'discard': - /* keep / stop / discard */ + /* discard / keep / stop */ $this->s_ = array( - 'valid_after' => array('script-start', 'require', 'if', 'elsif', 'else', - 'reject', 'fileinto', 'redirect', 'stop', 'keep', 'discard') + 'valid_after' => str_replace('(', '(script-start|', $this->nonTestCommands_) ); break; case 'fileinto': - /* fileinto */ + /* fileinto [":copy"] */ $this->s_ = array( 'requires' => 'fileinto', - 'valid_after' => array('require', 'if', 'elsif', 'else', 'reject', 'fileinto', 'redirect', 'stop', 'keep', 'discard'), + 'valid_after' => $this->nonTestCommands_, 'arguments' => array( + array('class' => 'tag', 'occurrences' => '?', 'values' => array( + array('occurrences' => '?', 'regex' => ':copy', 'requires' => 'copy', 'name' => 'copy') + )), array('class' => 'string', 'occurrences' => '1', 'values' => array( array('occurrences' => '1', 'regex' => '".*"', 'name' => 'folder') )) @@ -107,11 +110,23 @@ class Semantics ); break; + case 'mark': + case 'unmark': + /* mark / unmark */ + $this->s_ = array( + 'requires' => 'imapflags', + 'valid_after' => $this->nonTestCommands_ + ); + break; + case 'redirect': - /* redirect */ + /* redirect [":copy"] */ $this->s_ = array( - 'valid_after' => array('script-start', 'require', 'if', 'elsif', 'else', 'reject', 'fileinto', 'redirect', 'stop', 'keep', 'discard'), + 'valid_after' => str_replace('(', '(script-start|', $this->nonTestCommands_), 'arguments' => array( + array('class' => 'tag', 'occurrences' => '?', 'values' => array( + array('occurrences' => '?', 'regex' => ':copy', 'requires' => 'copy', 'name' => 'size-type') + )), array('class' => 'string', 'occurrences' => '1', 'values' => array( array('occurrences' => '1', 'regex' => '".*"', 'name' => 'address') )) @@ -123,10 +138,27 @@ class Semantics /* reject */ $this->s_ = array( 'requires' => 'reject', - 'valid_after' => array('require', 'if', 'elsif', 'else', 'reject', 'fileinto', 'redirect', 'stop', 'keep', 'discard'), + 'valid_after' => $this->nonTestCommands_, 'arguments' => array( array('class' => 'string', 'occurrences' => '1', 'values' => array( - array('occurrences' => '1', 'regex' => '.*', 'name' => 'reason') + array('occurrences' => '1', 'regex' => '("|).*("|)', 'name' => 'reason') + )) + ) + ); + break; + + case 'setflag': + case 'addflag': + case 'removeflag': + /* setflag */ + /* addflag */ + /* removeflag */ + $this->s_ = array( + 'requires' => 'imapflags', + 'valid_after' =>$this->nonTestCommands_, + 'arguments' => array( + array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array( + array('occurrences' => '+', 'regex' => '".*"', 'name' => 'key') )) ) ); @@ -136,7 +168,7 @@ class Semantics /* vacation [":days" number] [":addresses" string-list] [":subject" string] [":mime"] */ $this->s_ = array( 'requires' => 'vacation', - 'valid_after' => array('require', 'if', 'elsif', 'else', 'reject', 'fileinto', 'redirect', 'stop', 'keep', 'discard'), + 'valid_after' => $this->nonTestCommands_, 'arguments' => array( array('class' => 'tag', 'occurrences' => '*', 'values' => array( array('occurrences' => '?', 'regex' => ':days', 'name' => 'days', @@ -163,7 +195,7 @@ class Semantics array('occurrences' => '?', 'regex' => ':mime', 'name' => 'mime') )), array('class' => 'string', 'occurrences' => '1', 'values' => array( - array('occurrences' => '1', 'regex' => '".*"', 'name' => 'reason') + array('occurrences' => '1', 'regex' => '.*', 'name' => 'reason') )) ) ); @@ -176,10 +208,10 @@ class Semantics case 'address': /* address [address-part: tag] [comparator: tag] [match-type: tag] */ $this->s_ = array( - 'valid_after' => array('if', 'elsif', 'anyof', 'allof', 'not'), + 'valid_after' => $this->testsValidAfter_, 'arguments' => array( array('class' => 'tag', 'occurrences' => '*', 'post-call' => 'checkTags_', 'values' => array( - array('occurrences' => '?', 'regex' => ':(is|contains|matches|count|value)', 'call' => 'setMatchType_', 'name' => 'match-type'), + array('occurrences' => '?', 'regex' => ':(is|contains|matches|count|value|regex)', 'call' => 'setMatchType_', 'name' => 'match-type'), array('occurrences' => '?', 'regex' => ':(all|localpart|domain|user|detail)', 'call' => 'checkAddrPart_', 'name' => 'address-part'), array('occurrences' => '?', 'regex' => ':comparator', 'name' => 'comparator', 'add' => array( @@ -205,7 +237,7 @@ class Semantics /* allof anyof */ $this->s_ = array( - 'valid_after' => array('if', 'elsif', 'anyof', 'allof', 'not'), + 'valid_after' => $this->testsValidAfter_, 'arguments' => array( array('class' => 'left-parant', 'occurrences' => '1', 'values' => array( array('occurrences' => '1', 'regex' => '\(', 'name' => 'test-list') @@ -221,10 +253,10 @@ class Semantics /* envelope [address-part: tag] [comparator: tag] [match-type: tag] */ $this->s_ = array( 'requires' => 'envelope', - 'valid_after' => array('if', 'elsif', 'anyof', 'allof', 'not'), + 'valid_after' => $this->testsValidAfter_, 'arguments' => array( array('class' => 'tag', 'occurrences' => '*', 'post-call' => 'checkTags_', 'values' => array( - array('occurrences' => '?', 'regex' => ':(is|contains|matches|count|value)', 'call' => 'setMatchType_', 'name' => 'match-type'), + array('occurrences' => '?', 'regex' => ':(is|contains|matches|count|value|regex)', 'call' => 'setMatchType_', 'name' => 'match-type'), array('occurrences' => '?', 'regex' => ':(all|localpart|domain|user|detail)', 'call' => 'checkAddrPart_', 'name' => 'address-part'), array('occurrences' => '?', 'regex' => ':comparator', 'name' => 'comparator', 'add' => array( @@ -248,7 +280,7 @@ class Semantics case 'exists': /* exists */ $this->s_ = array( - 'valid_after' => array('if', 'elsif', 'anyof', 'allof', 'not'), + 'valid_after' => $this->testsValidAfter_, 'arguments' => array( array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array( array('occurrences' => '+', 'regex' => '".*"', 'name' => 'header') @@ -260,10 +292,10 @@ class Semantics case 'header': /* header [comparator: tag] [match-type: tag] */ $this->s_ = array( - 'valid_after' => array('if', 'elsif', 'anyof', 'allof', 'not'), + 'valid_after' => $this->testsValidAfter_, 'arguments' => array( array('class' => 'tag', 'occurrences' => '*', 'post-call' => 'checkTags_', 'values' => array( - array('occurrences' => '?', 'regex' => ':(is|contains|matches|count|value)', 'call' => 'setMatchType_', 'name' => 'match-type'), + array('occurrences' => '?', 'regex' => ':(is|contains|matches|count|value|regex)', 'call' => 'setMatchType_', 'name' => 'match-type'), array('occurrences' => '?', 'regex' => ':comparator', 'name' => 'comparator', 'add' => array( array('class' => 'string', 'occurrences' => '1', 'call' => 'setComparator_', 'values' => array( @@ -286,7 +318,7 @@ class Semantics case 'not': /* not */ $this->s_ = array( - 'valid_after' => array('if', 'elsif', 'anyof', 'allof', 'not'), + 'valid_after' => $this->testsValidAfter_, 'arguments' => array( array('class' => 'identifier', 'occurrences' => '1', 'values' => array( array('occurrences' => '1', 'regex' => $this->testCommands_, 'name' => 'test') @@ -298,7 +330,7 @@ class Semantics case 'size': /* size <":over" / ":under"> */ $this->s_ = array( - 'valid_after' => array('if', 'elsif', 'anyof', 'allof', 'not'), + 'valid_after' => $this->testsValidAfter_, 'arguments' => array( array('class' => 'tag', 'occurrences' => '1', 'values' => array( array('occurrences' => '1', 'regex' => ':(over|under)', 'name' => 'size-type') @@ -314,7 +346,7 @@ class Semantics case 'false': /* true / false */ $this->s_ = array( - 'valid_after' => array('if', 'elsif', 'anyof', 'allof', 'not') + 'valid_after' => $this->testsValidAfter_ ); break; @@ -327,25 +359,32 @@ class Semantics } } - function setRequire_($text) + function setExtensionFuncs($setFn, $checkFn) { - global $requires_; - - if(!is_array($requires_)){ - $requires_ = array(); + if (is_callable($setFn) && is_callable($checkFn)) + { + $this->registerExtensionFn_ = $setFn; + $this->isExtensionRegisteredFn_ = $checkFn; } + } - array_push($requires_, $text); + function setRequire_($extension) + { + call_user_func($this->registerExtensionFn_, $extension); return true; } + function wasRequired_($extension) + { + return call_user_func($this->isExtensionRegisteredFn_, $extension); + } + function setMatchType_($text) { // Do special processing for relational test extension if ($text == ':count' || $text == ':value') { - global $requires_; - if (!in_array('"relational"', $requires_)) + if (!$this->wasRequired_('relational')) { $this->message = 'missing require for match-type '. $text; return false; @@ -357,6 +396,12 @@ class Semantics )) ); } + // Do special processing for regex match-type extension + else if ($text == ':regex' && !$this->wasRequired_('regex')) + { + $this->message = 'missing require for match-type '. $text; + return false; + } $this->matchType_ = $text; return true; } @@ -371,8 +416,7 @@ class Semantics { if ($text == ':user' || $text == ':detail') { - global $requires_; - if (!in_array('"subaddress"', $requires_)) + if (!$this->wasRequired_('subaddress')) { $this->message = 'missing require for tag '. $text; return false; @@ -393,9 +437,30 @@ class Semantics return true; } - function validAfter($prev) + function validCommand($prev, $line) { - return in_array($prev, $this->s_['valid_after']); + // Check if command is known + if ($this->unknown) + { + $this->message = 'line '. $line .': unknown command "'. $this->command_ .'"'; + return false; + } + + // Check if the command needs to be required + if (isset($this->s_['requires']) && !$this->wasRequired_($this->s_['requires'])) + { + $this->message = 'line '. $line .': missing require for command "'. $this->command_ .'"'; + return false; + } + + // Check if command may appear here + if (!ereg($this->s_['valid_after'], $prev)) + { +# $this->message = 'line '. $line .': "'. $this->command_ .'" may not appear after "'. $prev .'"'; +# return false; + } + + return true; } function validClass_($class, $id) @@ -459,16 +524,6 @@ class Semantics { $name = $class . ($class != $text ? " $text" : ''); - // Check if the command needs to be required - // TODO: move this to somewhere more appropriate - global $requires_; - if (isset($this->s_['requires']) && - !in_array('"'.$this->s_['requires'].'"', $requires_)) - { - $this->message = 'line '. $line .': missing require for '. $this->command_; - return false; - } - // Make sure the argument has a valid class if (!$this->validClass_($class, $name)) { @@ -482,8 +537,7 @@ class Semantics if (preg_match('/^'. $val['regex'] .'$/m', $text)) { // Check if the argument value needs a 'require' - if (isset($val['requires']) && - !in_array('"'.$val['requires'].'"', $requires_)) + if (isset($val['requires']) && !$this->wasRequired_($val['requires'])) { $this->message = 'line '. $line .': missing require for '. $val['name'] .' '. $text; return false;