parent = $parent; $this->_construct($root); } function execute() { return($this->dump()); } /* Create a html interface for the current sieve filter */ function dump() { /************** * Handle new elements **************/ /* Only parse the tokens once */ if(!count($this->pap)){ $this->dump_ = ""; $this->mode_stack = array(); $this->pap = array(); $this->doDump_(0, '', true); /* Add left elements */ if(count($this->mode_stack)){ foreach($this->mode_stack as $element){ $this->handle_elements( $element,preg_replace("/[^0-9]/","",microtime())); } } } /* Create html results */ $smarty = get_smarty(); $block_indent_start = $smarty->fetch(get_template_path("templates/block_indent_start.tpl",TRUE,dirname(__FILE__))); $block_indent_stop = $smarty->fetch(get_template_path("templates/block_indent_stop.tpl",TRUE,dirname(__FILE__))); $this -> dump_ = ""; $ends = array(); $ends_complete_block = array(); foreach($this->pap as $key => $object){ if(is_object($object)){ $end = $this->get_block_end($key,false); $end2 = $this->get_block_end($key); if($end != $key && in_array_strict(get_class($object),array("sieve_if"))){ $ends_complete_block[$end2] = $end2; $this->dump_ .= "
"; $this->dump_ .= "
"; } if(isset($ends[$key])){ $this->dump_ .= $block_indent_stop; } $this->dump_ .= preg_replace("/>/",">\n",$object->execute()); if($end != $key && in_array_strict(get_class($object),array("sieve_if","sieve_else","sieve_elsif"))) { $ends[$end] = $end; $this->dump_ .= $block_indent_start; } if(isset($ends_complete_block[$key])){ $this->dump_ .= "
"; $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]; /* Get last element class and type */ $last_class = ""; $last_type = ""; if(count($this->mode_stack)){ $key = key($this->mode_stack); $tmp = array_reverse($this->mode_stack[$key]['ELEMENTS']); $last_class = $tmp[key($tmp)]['class']; if(isset($this->mode_stack[$key]['TYPE'])){ $last_type = $this->mode_stack[$key]['TYPE']; } } /* This closes the last mode */ if($node['class'] == "block-start"){ $tmp = array_pop($this->mode_stack); $this->handle_elements($tmp,$node_id); $this->handle_elements(array("TYPE" => "block_start"),preg_replace("/[^0-9]/","",microtime())); } /* This closes the last mode */ if($node['class'] == "block-end"){ $tmp = array_pop($this->mode_stack); $this->handle_elements($tmp,$node_id); $this->handle_elements(array("TYPE" => "block_end"),preg_replace("/[^0-9]/","",microtime())); } /* Semicolon indicates a new command */ if($node['class'] == "semicolon"){ $tmp =array_pop($this->mode_stack); $this->handle_elements($tmp,$node_id); } /* We can't handle comments within if tag right now */ if(!in_array_ics($last_type,array("if","elsif"))){ /* Comments require special attention. * We do not want to create a single comment element * foreach each "#comment" string found in the script. * Sometimes comments are used like this * # This is a comment * # and it still is a comment * # ... * So we combine them to one single comment. */ if($last_class != "comment" && $node['class'] == "comment"){ $tmp =array_pop($this->mode_stack); $this->handle_elements($tmp,$node_id); $this->mode_stack[] = array("TYPE" => $node['class']); } if($last_class == "comment" && $node['class'] != "comment"){ $tmp =array_pop($this->mode_stack); $this->handle_elements($tmp,$node_id); } } /* Handle identifiers */ $identifiers = array("else","if","elsif","end","reject","redirect","vacation","keep","discard","fileinto","require","stop"); if($node['class'] == "identifier" && in_array_strict($node['text'],$identifiers)){ $this->mode_stack[] = array("TYPE" => $node['text']); } if(!($last_type == "if" && $node['class'] == "comment")){ /* 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,$node_id); } /* 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); } } } /* Create a class for each resolved object. * And append this class to a list of objects. */ function handle_elements($data,$id) { if(!isset($data['TYPE'])){ return; } $type = $data['TYPE']; $class_name= "sieve_".$type ; if(class_exists($class_name)){ $this->pap[] = new $class_name($data,$id,$this); }else{ echo "Missing : ".$class_name.""."
"; } } function save_object() { reset($this->pap); foreach($this->pap as $key => $obj){ if(in_array_strict(get_class($obj),array("sieve_if", "sieve_elsif", "sieve_vacation", "sieve_comment", "sieve_reject", "sieve_fileinto", "sieve_require", "sieve_redirect"))){ if(isset($this->pap[$key]) && method_exists($this->pap[$key],"save_object")){ $this->pap[$key]->save_object(); } } } } /* Remove the object at the given position */ function remove_object($key_id) { if(count($this->pap) == 1){ msg_dialog::display(_("Warning"), _("Cannot remove last element!"), ERROR_DIALOG); return; } if(!isset($this->pap[$key_id])){ trigger_error("Can't remove element with object_id=".$key_id.", there is no object with this identifier. Remove aborted."); return(false); } $class = get_class($this->pap[$key_id]); if(in_array_strict($class,array("sieve_if","sieve_elsif","sieve_else"))){ $block_start= $key_id; $block_end = $this->get_block_end($key_id); for($i = $block_start ; $i <= $block_end ; $i ++ ){ unset($this->pap[$i]); } }else{ unset($this->pap[$key_id]); } $tmp = array(); foreach($this->pap as $element){ $tmp[] = $element; } $this->pap = $tmp; } /* This function moves a given element to another position. * Single elements like "keep;" will simply be moved one posisition down/up. * Multiple elements like if-elsif-else will be moved as block. * * $key_id specified the element that should be moved. * $direction specifies to move elements "up" or "down" */ function move_up_down($key_id,$direction = "down") { /* Get the current element to decide what to move. */ $e_class = get_class($this->pap[$key_id]); if(in_array_strict($e_class,array("sieve_if"))){ $block_start= $key_id; $block_end = $this->get_block_end($key_id); /* Depending on the direction move up down */ if($direction == "down"){ $next_free = $this->_get_next_free_move_slot($block_end,$direction); }else{ $next_free = $this->_get_next_free_move_slot($block_start,$direction); } /* Move the given block */ $this->move_multiple_elements($block_start,$block_end,$next_free); } if(in_array_strict($e_class,array( "sieve_stop", "sieve_keep", "sieve_require", "sieve_comment", "sieve_vacation", "sieve_stop", "sieve_reject", "sieve_fileinto", "sieve_redirect", "sieve_discard"))){ $this->move_single_element($key_id,$this->_get_next_free_move_slot($key_id,$direction)); } } /* Move the given block to position */ function move_multiple_elements($start,$end,$to) { /* Use class names for testing */ $data = $this->pap; /* Get block to move */ $block_to_move = array_slice($data,$start, ($end - $start +1)); /* We want do move this block up */ if($end > $to){ /* Get start block */ $start_block = array_slice($data,0,$to); /* Get Get all elements between the block to move * and next free position */ $block_to_free = array_slice($data,$to ,$start - $to ); $block_to_end = array_slice($data,$end+1); $new = array(); foreach($start_block as $block){ $new[] = $block; } foreach($block_to_move as $block){ $new[] = $block; } foreach($block_to_free as $block){ $new[] = $block; } foreach($block_to_end as $block){ $new[] = $block; } $old = $this->pap; $this->pap = $new; } /* We want to move this block down. */ if($to > $end){ /* Get start block */ $start_block = array_slice($data,0,$start); /* Get Get all elements between the block to move * and next free position */ $block_to_free = array_slice($data,$end +1,($to - $end )); /* Get the rest */ $block_to_end = array_slice($data,$to+1); $new = array(); foreach($start_block as $block){ $new[] = $block; } foreach($block_to_free as $block){ $new[] = $block; } foreach($block_to_move as $block){ $new[] = $block; } foreach($block_to_end as $block){ $new[] = $block; } $old = $this->pap; $this->pap = $new; } } /* This function returns the id of the element * where the current block ends */ function get_block_end($start,$complete = TRUE) { /* Only execute if this is a really a block element. * Block elements is only sieve_if */ if(in_array_strict(get_class($this->pap[$start]),array("sieve_if","sieve_elsif","sieve_else"))){ $class = get_class($this->pap[$start]); $next_class = get_class($this->pap[$start+1]); $block_depth = 0; $end = FALSE; while(!$end && $start < count($this->pap)){ if($class == "sieve_block_start"){ $block_depth ++; } if($class == "sieve_block_end"){ $block_depth --; } if($complete){ if( $block_depth == 0 && $class == "sieve_block_end" && !in_array_strict($next_class,array("sieve_else","sieve_elsif"))){ $end = TRUE; $start --; } }else{ if( $block_depth == 0 && $class == "sieve_block_end" ){ $end = TRUE; $start --; } } $start ++; $class = get_class($this->pap[$start]); if(isset($this->pap[$start+1])){ $next_class = get_class($this->pap[$start+1]); }else{ $next_class =""; } } } return($start); } /* This function moves the single element at * position $from to position $to. */ function move_single_element($from,$to) { if($from == $to) { return; } $ret = array(); $tmp = $this->pap; $begin = array(); $middle = array(); $end = array(); $element = $this->pap[$from]; if($from > $to ){ /* Get all element in fron to element to move */ if($from != 0){ $begin = array_slice($tmp,0,$to); } /* Get all elements between */ $middle = array_slice($tmp,$to , ($from - ($to) )); /* Get the rest */ $end = array_slice($tmp,$from+1); foreach($begin as $data){ $ret[] = $data; } $ret[] = $element; foreach($middle as $data){ $ret[] = $data; } foreach($end as $data){ $ret[] = $data; } $this->pap = $ret; } if($from < $to ){ /* Get all element in fron to element to move */ if($from != 0){ $begin = array_slice($tmp,0,$from); } /* Get all elements between */ $middle = array_slice($tmp,$from+1 , ($to - ($from))); /* Get the rest */ $end = array_slice($tmp,$to+1); foreach($begin as $data){ $ret[] = $data; } foreach($middle as $data){ $ret[] = $data; } $ret[] = $element; foreach($end as $data){ $ret[] = $data; } $this->pap = $ret; } } /* Returns the next free position where we * can add a new sinle element * $key_id = Current position * $direction = Forward or backward. */ function _get_next_free_move_slot($key_id,$direction,$include_self = FALSE) { $last_class = ""; $current_class =""; $next_class = ""; /* After this elements we can add new elements * without having any trouble. */ $allowed_to_add_after = array("sieve_keep", "sieve_require", "sieve_stop", "sieve_reject", "sieve_fileinto", "sieve_redirect", "sieve_discard", "sieve_comment", "sieve_block_start" ); /* Before this elements we can add new elements * without having any trouble. */ $allowed_to_add_before = array("sieve_keep", "sieve_require", "sieve_stop", "sieve_reject", "sieve_fileinto", "sieve_comment", "sieve_redirect", "sieve_discard", "sieve_if", "sieve_block_end" ); if($direction == "down"){ $test = $this->pap; while($key_id < count($test)){ if(($key_id+1) == count($test)) { return($key_id); } if(!$include_self){ $key_id ++; } $include_self = FALSE; $current_class = get_class($test[$key_id]); if(in_array_strict($current_class, $allowed_to_add_after)){ return($key_id); } } }else{ $test = $this->pap; if($key_id == 0) { return($key_id); } if(!$include_self){ $key_id --; } while($key_id >=0 ){ $current_class = get_class($test[$key_id]); if(in_array_strict($current_class, $allowed_to_add_before)){ return($key_id); } $key_id --; } return(0); } } /* Need to be reviewed */ function get_sieve_script() { $tmp =""; if(count($this->pap)){ $buffer = ""; foreach($this->pap as $part) { if(get_class($part) == "sieve_block_end"){ $buffer = substr($buffer,0,strlen($buffer)-(strlen(SIEVE_INDENT_TAB))); } $tmp2 = $part->get_sieve_script_part(); $tmp3 = preg_split("/\n/",$tmp2); foreach($tmp3 as $str){ $str2 = trim($str); /* If the current line only contains an '.' * we must skip the line indent. * The text: statement uses a single '.' to mark the text end. * This '.' must be the only char in the current line, no * whitespaces are allowed here. */ if($str2 == "."){ $tmp.=$str."\n"; }else{ $tmp.= $buffer.$str."\n"; } } if(get_class($part) == "sieve_block_start"){ $buffer .= SIEVE_INDENT_TAB; } } } if(!preg_match("/Generated by GOsa - Gonicus System Administrator/",$tmp)){ # $tmp = "#Generated by GOsa - Gonicus System Administrator \n ".$tmp; } return($tmp); } function check() { $msgs = array(); /* Some logical checks. * like : only sieve_comment can appear before require. */ /* Ensure that there are no command before require * - Get id of last require tag * - Collect object types in from of this tag. * - Check if there are tags collected that are not allowed */ $last_found_at = -1; $objs = array(); foreach($this->pap as $key => $obj){ if(get_class($obj) == "sieve_require"){ $last_found_at = $key; } } foreach($this->pap as $key => $obj){ if($key == $last_found_at) break; if(!in_array_strict(get_class($obj),array("sieve_comment","sieve_require"))){ $objs[] = get_class($obj); } } if(count($objs) && $last_found_at != -1){ $str = _("Require must be the first command in the script."); $msgs[] = $str; msg_dialog::display(_("Error"), $str, ERROR_DIALOG); } foreach($this->pap as $obj){ $o_msgs = $obj->check(); foreach($o_msgs as $o_msg){ $msgs[] = $o_msg; } } return($msgs); } /* We are forced to add a new require. * This function is called by the * sieveElement_Classes->parent->add_require() */ function add_require($str) { $require_id = -1; foreach($this->pap as $key => $obj){ if(get_class($obj) == "sieve_require"){ $require_id = $key; } } /* No require found, add one */ if($require_id == -1){ $require = new sieve_require(NULL,preg_replace("/[^0-9]/","",microtime()),$this); $require -> Add_Require($str); $new = array(); $new[] = $require; foreach($this->pap as $obj){ $new[] = $obj; } $this->pap = $new; } else { $this->pap[$require_id]->Add_Require($str); } } } /* Create valid sieve string/string-list * out of a given array */ function sieve_create_strings($data,$force_string = FALSE) { $ret = ""; if(is_array($data)){ if(count($data) == 1){ $ret = "\""; foreach($data as $dat){ $ret .=$dat; } $ret.="\""; }else{ foreach($data as $dat){ $ret.= "\""; $ret.=$dat; $ret.="\", "; } $ret = preg_replace("/,$/","",trim($ret)); $ret = "[".$ret."]"; } # $ret = preg_replace("/\"\"/","\"",$ret); }else{ $Multiline = preg_match("/\n/",$data); $data = preg_replace("/\r/","",$data);; if($Multiline && !$force_string){ $ret = "text: \r\n".$data."\r\n.\r\n"; }else{ $ret = "\"".$data."\""; $ret = preg_replace("/\"\"/","\"",$ret); } } $ret = preg_replace("/\n/","\r\n",$ret); return($ret); } /* This checks if there is a string at the current position * in the token array. * If there is a string list at the current position, * this function will return a complete list of all * strings used in this list. * It also returns an offset of the last token position */ function sieve_get_strings($data,$id) { $ret = array(); if($data[$id]['class'] == "left-bracket"){ while(isset($data[$id]) && $data[$id]['class'] != "right-bracket" && $id < count($data)){ if($data[$id]['class'] == "quoted-string"){ $text = $data[$id]['text']; $text= preg_replace("/^\"/","",$text); $text= preg_replace("/\"$/","",$text); $ret[] = $text; } $id ++; } }elseif($data[$id]['class'] == "quoted-string"){ $text = $data[$id]['text']; $text= preg_replace("/^\"/","",$text); $text= preg_replace("/\"$/","",$text); $ret[] = $text; }elseif($data[$id]['class'] == "number"){ $ret[] = $data[$id]['text']; }elseif($data[$id]['class'] == "multi-line"){ $str = trim(preg_replace("/^text:/","",$data[$id]['text'])); $str = trim(preg_replace("/\.$/","",$str)); $ret[] = $str; } return(array("OFFSET" => $id, "STRINGS" => $ret)); } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?>