From 10184ea67a679d3a0650b82394ac3efb1f3023b8 Mon Sep 17 00:00:00 2001 From: hickert Date: Thu, 22 Feb 2007 07:19:36 +0000 Subject: [PATCH] New sieve filter, not yet finished. git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@5727 594d385d-05f5-0310-b6e9-bd551577e9d8 --- include/sieve/class_My_Parser.inc | 37 +++ include/sieve/class_My_Tree.inc | 120 +++++++++ include/sieve/class_semantics.inc | 8 +- include/sieve/class_sieveElement.inc | 30 +++ include/sieve/class_sieveElements.inc | 321 ++++++++++++++++++++++++ include/sieve/class_sieveManagement.inc | 124 +++++++++ 6 files changed, 639 insertions(+), 1 deletion(-) create mode 100644 include/sieve/class_My_Parser.inc create mode 100644 include/sieve/class_My_Tree.inc create mode 100644 include/sieve/class_sieveElement.inc create mode 100644 include/sieve/class_sieveElements.inc create mode 100644 include/sieve/class_sieveManagement.inc diff --git a/include/sieve/class_My_Parser.inc b/include/sieve/class_My_Parser.inc new file mode 100644 index 000000000..703d44a1f --- /dev/null +++ b/include/sieve/class_My_Parser.inc @@ -0,0 +1,37 @@ +status_text = "incomplete"; + $this->script_ = $script; + $this->tree_ = new My_Tree(Scanner::scriptStart()); + $this->tree_->setDumpFunc(array(&$this, 'dumpToken_')); + $this->scanner_ = new Scanner($this->script_); + $this->scanner_->setCommentFunc(array($this, 'comment_')); + + if ($this->commands_($this->tree_->getRoot()) && + $this->scanner_->nextTokenIs('script-end')) + { + return $this->success_('success'); + } + + return $this->status_; + } + + function dumpToken_(&$token) + { + if (is_array($token)) + { + $str = "<" . $token['text'] . "> "; + foreach ($token as $k => $v) + { + $str .= " $k:$v"; + } + return $str; + } + return strval($token); + } +} +?> diff --git a/include/sieve/class_My_Tree.inc b/include/sieve/class_My_Tree.inc new file mode 100644 index 000000000..396634a61 --- /dev/null +++ b/include/sieve/class_My_Tree.inc @@ -0,0 +1,120 @@ +dump_ = ""; + $this->mode_stack = array(); + $this->pap = array(); + $this->doDump_(0, '', true); + + $this->dump_ ="
"; + foreach($this->pap as $object){ + if(is_object($object)){ + $this->dump_ .= $object->execute()."
"; + } + } + $this->dump_ .= "
"; + return $this->dump_; + } + + + /* This function walks through the object tree generated by the "Parse" class. + * All Commands will be resolved and grouped. So the Commands and their + * parameter are combined. Like "IF" and ":comparator"... + */ + function doDump_($node_id, $prefix, $last,$num = 1) + { + /* Indicates that current comman will only be valid for a single line. + * this command type will be removed from mode_stack after displaying it. + */ + $rewoke_last = FALSE; + + /* Get node */ + $node = $this->nodes_[$node_id]; + + /* This closes the last mode */ + if($node['class'] == "block-start"){ + $tmp = array_pop($this->mode_stack); + $this->handle_elements($tmp); + $this->handle_elements(array("TYPE" => "block_start")); + } + + /* This closes the last mode */ + if($node['class'] == "block-end"){ + $tmp = array_pop($this->mode_stack); + $this->handle_elements($tmp); + $this->handle_elements(array("TYPE" => "block_end")); + } + + /* Semicolon indicates a new command */ + if($node['class'] == "semicolon"){ + $tmp =array_pop($this->mode_stack); + $this->handle_elements($tmp); + } + + /* Handle comments */ + if($node['class'] == "comment"){ + $this->mode_stack[] = array("TYPE" => $node['class']); + $rewoke_last = TRUE; + } + + /* Handle identifiers */ + $identifiers = array("if","elsif","end","reject","redirect","vacation","keep","discard","comment","fileinto","require"); + if($node['class'] == "identifier" && in_array($node['text'],$identifiers)){ + $this->mode_stack[] = array("TYPE" => $node['text']); + } + + /* Add current node to current command stack */ + end($this->mode_stack); + $key = key($this->mode_stack); + $this->mode_stack[$key]['ELEMENTS'][] = $node; + + /* Remove last mode from mode stack, cause it was only valid for a single line */ + if($rewoke_last){ + $tmp =array_pop($this->mode_stack); + $this->handle_elements($tmp); + } + + /* If this is a sub element, just call this for all childs */ + if(isset($this->childs_[$node_id])){ + $childs = $this->childs_[$node_id]; + for ($i=0; $idoDump_($childs[$i], "", $num); + } + } + } + + + function handle_elements($data) + { + if(!isset($data['TYPE'])){ + return; + } + $type = $data['TYPE']; + + $class_name= "sieve_".$type ; + if(class_exists($class_name)){ + $this->pap[] = new $class_name($data); + }else{ + echo "Missing : ".$class_name.""."
"; + } + } +} +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_semantics.inc b/include/sieve/class_semantics.inc index e4b1f4c19..80e893ebc 100644 --- a/include/sieve/class_semantics.inc +++ b/include/sieve/class_semantics.inc @@ -16,6 +16,7 @@ class Semantics function Semantics($command) { $this->command_ = $command; + $this->unknown = false; switch ($command) { @@ -329,6 +330,11 @@ class Semantics function setRequire_($text) { global $requires_; + + if(!is_array($requires_)){ + $requires_ = array(); + } + array_push($requires_, $text); return true; } @@ -550,4 +556,4 @@ class Semantics } } -?> \ No newline at end of file +?> diff --git a/include/sieve/class_sieveElement.inc b/include/sieve/class_sieveElement.inc new file mode 100644 index 000000000..b6fde6fb5 --- /dev/null +++ b/include/sieve/class_sieveElement.inc @@ -0,0 +1,30 @@ +data = @nl2br($data->dumpParseTree()); + } + + function execute() + { + return($this->data); + } +} + + + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElements.inc b/include/sieve/class_sieveElements.inc new file mode 100644 index 000000000..1bb693a98 --- /dev/null +++ b/include/sieve/class_sieveElements.inc @@ -0,0 +1,321 @@ +"); + } +} + +class sieve_elsif extends sieve_if {} +class sieve_if extends sieve_element +{ + + /* Contains all tests with an uniqe id */ + var $test_list = array(); + + /* Available test types */ + var $TESTS = array("address","allof","anyof","exists","false","header","not","size","true","envelope"); + + var $elements = array(); + + + function sieve_if($elements) + { + $this->elements = $elements; + $this->_parse($elements); + } + + function execute() + { + return("-> "._("Condition")); + } + + + function _parse($data,$id = 0) + { + /* Objects that could be tested */ + $av_methods = array("address","allof","anyof","exists","false","header","not","size","true","envelope"); + + /* Tests that could be used */ + $av_match_type= array(":is",":contains",":matches",":over",":count",":value"); + + /* Variable initialization */ + $test_method = ""; // The object that we want to test, like 'header' + $match_type = ""; // The operator like :contains + $obj_attribute = ""; // The attribute we want to check, like 'from' + $obj_match_value= ""; // The value that we want to match for. + $comparator = ""; // The comperator specifies the type of values that should be matched. + + $node = $data['ELEMENTS'][$id]; + + /* Skip the if / else identifier */ + if($node ['class'] == "identifier" && in_array($node['text'],array("if","elsif"))){ + $id ++; + $node = $data['ELEMENTS'][$id]; + } + + /* Get current command like "allof" or "header" */ + if($node ['class'] == "identifier" && in_array($node['text'],$av_methods)){ + $test_method = $node['text']; + } + + echo $id; + + /* switch different types */ + switch($test_method) + { + case "allof" : $this->_parse($elements,$id); + case "anyof" : $this->_parse($elements,$id); + + case "address" : + { + /* header :comparator :optional-operator :operator attribute match-value */ + $tmp = array(); + $tmp['OPTIONAL_OP'] =""; + $tmp['COMPARATOR'] =""; + $tmp['OPERATOR'] =""; + $tmp['ATTRIBUTE'] =""; + $tmp['MATCH-VALUE'] =""; + + + } + default : echo $test_method."
" ; + } + } +}; + + +class sieve_comment extends sieve_element +{ + var $data = ""; + + + function sieve_comment($data) + { + foreach($data['ELEMENTS'] as $node){ + $this->data .= $node['text']; + } + } + + function execute() + { + return(_("Comment")." "); + } +} + + +class sieve_require extends sieve_element +{ + var $data = array(); + + function sieve_require($data) + { + foreach($data['ELEMENTS'] as $node ){ + if(in_array($node['class'],array("quoted-string","text"))){ + $this->data[] = preg_replace("/\"/","",$node['text']); + } + } + } + + function execute() + { + $str = _("Sieve includes"); + foreach($this->data as $req){ + $str .= " ".$req.""; + } + return($str); + } +} + +class sieve_discard extends sieve_element +{ + var $data = array(); + + function sieve_discard($data) + { + } + + function execute() + { + $str = _("Discard mail"); + return($str); + } +} + + + +class sieve_reject extends sieve_element +{ + var $data = array(); + + function sieve_reject($data) + { + $str = ""; + foreach($data['ELEMENTS'] as $node ){ + if(in_array($node['class'],array("quoted-string","text"))){ + $str .= $node['text']; + } + } + $this->data = preg_replace("/\"/","",$str); + } + + function execute() + { + $str = _("Reject mail"); + $str .= " "; + return($str); + } +} + +class sieve_redirect extends sieve_element +{ + var $data = array(); + + function sieve_redirect($data) + { + foreach($data['ELEMENTS'] as $node ){ + if(in_array($node['class'],array("quoted-string","text"))){ + $this->data[] = $node['text']; + } + } + } + + function execute() + { + $str = _("Redirect to"); + foreach($this->data as $dest){ + $str .= "
"; + } + return($str); + } +} + +class sieve_fileinto extends sieve_element +{ + var $data = array(); + + function sieve_fileinto($data) + { + foreach($data['ELEMENTS'] as $node ){ + if(in_array($node['class'],array("quoted-string","text"))){ + $this->data[] = preg_replace("/\"/","",$node['text']); + } + } + } + + function execute() + { + $str = _("File into"); + + $str .= ""; + + return($str); + } +} + +class sieve_vacation extends sieve_element +{ + var $days = FALSE; + var $subject = FALSE; + var $from = ""; + var $mime = ""; + var $hanlde = ""; + var $reason = ""; + var $addresses= array(); + + function sieve_vacation($data) + { + /* Usage: vacation [":days" number] [":subject" string] + [":from" string] [":addresses" string-list] + [":mime"] [":handle" string] */ + + /* Not all attribute types are supported by the sieve class right now */ + $known_attrs = array(":days",":subject",":from",":mime",":handle"); + + /* Walk through elements */ + for($i = 0 ; $i < count($data['ELEMENTS']) ; $i ++){ + + /* get current element */ + $node = $data['ELEMENTS'][$i]; + + /* Check if tag is in the specified list of attributes */ + if($node['class'] == "tag" && in_array($node['text'],$known_attrs)){ + + $var = preg_replace("/\:/","",$node['text']); + $this->$var = $data['ELEMENTS'][$i+1]['text']; + $i ++; + } + + /* Check for addresses */ + if($node['class'] == "tag" && $node['text'] == ":addresses") { + $this->addresses = array(); + $i ++; + + /* Multiple or single address given */ + if($data['ELEMENTS'][$i]['class'] == "left-bracket"){ + while($data['ELEMENTS'][$i]['class'] != "right-bracket" && ($i < count($data['ELEMENTS']))){ + $i ++; + if($data['ELEMENTS'][$i]['class'] == "quoted-string"){ + $this->addresses[] = preg_replace("/\"/i","",$data['ELEMENTS'][$i]['text']); + } + } + }else{ + $this->addresses[] = $data['ELEMENTS'][$i]['text'] ; + } + } + + /* Add the vacation message */ + if($node['class'] == "quoted-string"){ + $this->reason = $node['text']; + } + } + } + + + function execute() + { + $str =""; + $str .=""._("Vacation message").""; + foreach($this->addresses as $addr){ + $str .="
"; + } + $str .="
"; + + return($str); + } +} + +class sieve_block_start extends sieve_element +{ + function execute() + { + return("
"); + } +} + +class sieve_block_end extends sieve_element +{ + function execute() + { + return("
"); + } +} + +/* This class handles the keep statement */ +class sieve_keep extends sieve_element +{ + function execute() + { + return("-> "._("Keep message")); + } +} +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveManagement.inc b/include/sieve/class_sieveManagement.inc new file mode 100644 index 000000000..945a6d284 --- /dev/null +++ b/include/sieve/class_sieveManagement.inc @@ -0,0 +1,124 @@ + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +class sieveManagement extends plugin +{ + var $parent = NULL; + var $scripts= array(); + + + function sieveManagement($config,$dn,$parent) + { + $this->parent = $parent; + plugin::plugin($config,$dn); + + + /* Connect to sieve class and try to get all available sieve scripts */ + $cfg= $this->config->data['SERVERS']['IMAP'][$this->parent->gosaMailServer]; + + /* Log into the mail server */ + $sieve= new sieve($cfg["sieve_server"], $cfg["sieve_port"], $this->parent->uid, + $cfg["password"], $cfg["admin"]); + + /* Try to login */ + if (!$sieve->sieve_login()){ + print_red(sprintf(_("Can't log into SIEVE server. Server says '%s'."), + to_string($sieve->error_raw))); + return; + } + + /* Get all sieve scripts names */ + if($sieve->sieve_listscripts()){ + if (is_array($sieve->response)){ + foreach($sieve->response as $key => $name){ + $this->scripts[$key]['NAME'] = $name; + } + } + } + + /* Get script contents */ + foreach($this->scripts as $key => $script){ + $p = new My_Parser; + $sieve->sieve_getscript($script['NAME']); + + $script = ""; + foreach($sieve->response as $line){ + $script.=$line; + } + + $this->scripts[$key]['SCRIPT'] = $script; + $this->scripts[$key]['MSG'] = ""; + $ret = $p->parse($script); + if(!$ret){ + $this->scripts[$key]['MSG'] = "".$p->status_text.""; + $this->scripts[$key]['STATUS'] = FALSE; + }else{ + $this->scripts[$key]['STATUS'] = TRUE; + } + $this->scripts[$key]['PARSER'] = $p; + } + } + + function execute() + { + $once = TRUE; + foreach($_POST as $name => $value){ + if(preg_match("/^editscript_/",$name) && $once){ + $script = preg_replace("/^editscript_/","",$name); + $script = preg_replace("/_(x|y)/","",$script); + $once = FALSE; + + $obj_handler = new sieveElement; + $data = $this->scripts[$script]['PARSER']; + $obj_handler->resolve_to_object($data); + return($obj_handler->execute()); + } + } + + + $List = new divSelectBox("sieveManagement"); + + foreach($this->scripts as $key => $script){ + + $field1 = array("string" => $script['NAME']); + + if($script['STATUS']){ + $field2 = array("string" => _("Parse successful")); + }else{ + $field2 = array("string" => _("Parse failed") .$script['MSG']); + } + + $field3 = array("string" => _("Script length")." : ".strlen($script['SCRIPT'])); + $field4 = array("string" => ""); + + $List ->AddEntry(array($field1,$field2,$field3,$field4)); + } + + return($List->DrawList()); + } + + function save_object() + { + + } +} + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> -- 2.30.2