Code

Some changes.
[gosa.git] / include / sieve / class_My_Tree.inc
1 <?php
5 /* This class is inherited from the original 'Tree'
6  *  class written by Heiko Hund.
7  * It is partly rewritten to create a useable html interface 
8  *  for each single sieve token. 
9  * This gives us the ability to edit existing sieve filters. 
10  */
11 class My_Tree extends Tree
12 {
13   var $dumpFn_;
14   var $dump_;
16   var $mode_stack = array();
17   var $pap              = array();
20   /* Create a html interface for the current sieve filter 
21    */
22   function dump()
23   {
24     error_reporting(E_ALL);
26     /* Only parse the tokens once */
27     if(!count($this->pap)){
28       $this->dump_ = "";
29       $this->mode_stack = array();
30       $this->pap = array();
31       $this->doDump_(0, '', true);
32     }
34     /* Create html results */
35     $smarty = get_smarty();
36     $smarty->fetch(get_template_path("templates/element_stop.tpl",TRUE,dirname(__FILE__)));
38     $this -> dump_ = "";
39     foreach($this->pap as $key => $object){
40       if(is_object($object)){
41         $this->dump_ .= preg_replace("/>/",">\n",$object->execute()); 
42       }
43     }
44     
46     /* Create html results */
47     $smarty = get_smarty();
48     $smarty->assign("Contents",$this->dump_);
49     $ret = $smarty->fetch(get_template_path("templates/edit_frame_base.tpl",TRUE,dirname(__FILE__)));
50     return ($ret);
51   }
54   /* This function walks through the object tree generated by the "Parse" class.
55    * All Commands will be resolved and grouped. So the Commands and their 
56    *  parameter are combined. Like "IF" and ":comparator"...
57    */  
58   function doDump_($node_id, $prefix, $last,$num = 1)
59   {
60     /* Indicates that current comman will only be valid for a single line. 
61      *  this command type will be removed from mode_stack after displaying it.
62      */
63     $rewoke_last = FALSE;
65     /* Get node */ 
66     $node = $this->nodes_[$node_id];
68     /* This closes the last mode */
69     if($node['class'] == "block-start"){
70       $tmp = array_pop($this->mode_stack);
71       $this->handle_elements($tmp,$node_id);
72       $this->handle_elements(array("TYPE" => "block_start"),$node_id);
73     }
75     /* This closes the last mode */
76     if($node['class'] == "block-end"){
77       $tmp = array_pop($this->mode_stack);
78       $this->handle_elements($tmp,$node_id);
79       $this->handle_elements(array("TYPE" => "block_end"),$node_id);
80     }
82     /* Semicolon indicates a new command */
83     if($node['class'] == "semicolon"){
84       $tmp =array_pop($this->mode_stack);
85       $this->handle_elements($tmp,$node_id);
86     }
88     /* Handle comments */
89     if($node['class'] == "comment"){
90       $this->mode_stack[] = array("TYPE" => $node['class']);
91       $rewoke_last = TRUE;
92     }
94     /* Handle identifiers */
95     $identifiers = array("else","if","elsif","end","reject","redirect","vacation","keep","discard","comment","fileinto","require","stop");
96     if($node['class'] == "identifier" && in_array($node['text'],$identifiers)){
97       $this->mode_stack[] = array("TYPE" => $node['text']); 
98     }
100     /* Add current node to current command stack */
101     end($this->mode_stack);
102     $key = key($this->mode_stack);
103     $this->mode_stack[$key]['ELEMENTS'][] = $node;
105     /* Remove last mode from mode stack, cause it was only valid for a single line */
106     if($rewoke_last){
107       $tmp =array_pop($this->mode_stack);
108       $this->handle_elements($tmp,$node_id);
109     }
111     /* If this is a sub element, just call this for all childs */       
112     if(isset($this->childs_[$node_id])){
113       $childs = $this->childs_[$node_id];
114       for ($i=0; $i<count($childs); ++$i)
115       {
116         $c_last = false;
117         if ($i+1 == count($childs))
118         {
119           $c_last = true;
120         }
121         $this->doDump_($childs[$i], "", $num);
122       }
123     }
124   }
127   /* Create a class for each resolved object.
128    * And append this class to a list of objects.
129    */
130   function handle_elements($data,$id)
131   {
132     if(!isset($data['TYPE'])){
133       return;
134     }
135     $type = $data['TYPE'];
136     
137     $class_name= "sieve_".$type ;
138     if(class_exists($class_name)){
139       $this->pap[] = new $class_name($data,$id);
140     }else{
141       echo "<font color='red'>Missing : ".$class_name."</font>"."<br>";
142     }
143   }
145   function save_object()
146   {
147     foreach($this->pap as $key => $obj){
149       if(in_array(get_class($obj),array("sieve_if","sieve_elsif","sieve_vacation","sieve_comment","sieve_reject","sieve_fileinto","sieve_require","sieve_redirect"))){
150         $this->pap[$key]->save_object();
151       }
153       $once = TRUE;
154       foreach($_POST as $name => $value){
156         if(isset($obj->object_id) && preg_match("/^Remove_Object_".$obj->object_id."_/",$name) && $once){
157           $once = FALSE;
158           $this->remove_object($key);
159         }
160         if(isset($obj->object_id) && preg_match("/^Move_Up_Object_".$obj->object_id."_/",$name) && $once){
161           $this->move_up_down($key,"up");
162           $once = FALSE;
163         }
164         if(isset($obj->object_id) && preg_match("/^Move_Down_Object_".$obj->object_id."_/",$name) && $once){
165           $this->move_up_down($key,"down");
166           $once = FALSE;
167         }
168       }
169     }
170   }
173   function remove_object($key_id){
174     unset($this->pap[$key_id]);
175   }
178   /* This function moves a given element to another position.
179    * Single elements like "keep;" will simply be moved one posisition down/up.
180    * Multiple elements like if-elsif-else will be moved as block. 
181    * 
182    *  $key_id     specified the element that should be moved.
183    *  $direction  specifies to move elements "up" or "down"
184    */
185   function move_up_down($key_id,$direction = "down")
186   {
187      
188     /* Get the current element to decide what to move. */ 
189     $e_class = get_class($this->pap[$key_id]);
190       
191     
192     if(in_array($e_class,array("sieve_if"))){
193       echo "move block";
194     }
196     if(in_array($e_class,array("sieve_stop","sieve_keep","sieve_require", "sieve_stop", "sieve_reject", "sieve_fileinto", "sieve_redirect", "sieve_discard"))){
197       echo "move single ".$key_id." to ".$this->_get_next_free_move_slot($key_id,$direction)."<br>";
198       $this->move_single_element_to($key_id,$this->_get_next_free_move_slot($key_id,$direction));
199     }
200   }
203   function move_single_element_to($from,$to)
204   {
205     if($from == $to) return;
207     $ret = array();
210     $tmp = $this->pap;
212 #    $tmp = array();
213  #  foreach($this->pap as $class){
214   #    $tmp[] = get_class($class);
215    # }
217     if($from > $to ){
219       $element = $this->pap[$from];
221       $begin = array();
222       $middle = array();
223       $end = array();
225       /* Get all element in fron to element to move */    
226       if($from  != 0){
227         $begin = array_slice($tmp,0,$to);
228       }
230       /* Get all elements between */
231       $middle = array_slice($tmp,$to , ($from - ($to) ));  
232     
233       /* Get the rest */ 
234       $end  = array_slice($tmp,$from+1);
235  
236       foreach($begin as $data){
237         $ret[] = $data;
238       }
239       $ret[] = $element;
240       foreach($middle as $data){
241         $ret[] = $data;
242       }
243       foreach($end as $data){
244         $ret[] = $data;
245       }
247 #      print_a(array("Anfang" => $begin ,$element, "middle" => $middle, "end" => $end));
249       $this->pap = $ret;
250     }
251     if($from < $to ){
253       $element = $this->pap[$from];
255       $begin = array();
256       $middle = array();
257       $end = array();
259       /* Get all element in fron to element to move */    
260       if($from  != 0){
261         $begin = array_slice($tmp,0,$from);
262       }
264       /* Get all elements between */
265       $middle = array_slice($tmp,$from+1 , ($to - ($from)));  
266     
267       /* Get the rest */ 
268       $end  = array_slice($tmp,$to+1);
269  
270       foreach($begin as $data){
271         $ret[] = $data;
272       }
273       foreach($middle as $data){
274         $ret[] = $data;
275       }
276       $ret[] = $element;
277       foreach($end as $data){
278         $ret[] = $data;
279       }
280       $this->pap = $ret;
281     }
282   }
285   function _get_next_free_move_slot($key_id,$direction)
286   {
287     $last_class = "";
288     $current_class ="";
289     $next_class = "";
291     $allowed_to_add_after = array("sieve_keep",
292                                   "sieve_require", 
293                                   "sieve_stop", 
294                                   "sieve_reject", 
295                                   "sieve_fileinto", 
296                                   "sieve_redirect", 
297                                   "sieve_discard",
298                                   "sieve_block_end");
300     if($direction == "down"){
301       $test = $this->pap;
304       while($key_id < count($test)){
305        
306         if(($key_id+1) == count($test)) return($key_id);
308         $key_id ++;
310         $current_class  = get_class($test[$key_id]);
311         if(in_array($current_class, $allowed_to_add_after)){
312           return($key_id);
313         } 
314       }
315     }else{
317       $test = $this->pap;
319       if($key_id == 0) return($key_id);
320     
321       $key_id --;
322       while($key_id >=0 ){
324         $current_class  = get_class($test[$key_id]);
325         if(in_array($current_class, $allowed_to_add_after)){
326           return($key_id);
327         } 
328         $key_id --;
329       }
330     }
331   }
333   function move_object_up($key_id)
334   {
335     $new = array();
336     $add_now = NULL;
337     $key_id --;
339     if(!$key_id < 0) return;
340   
341     foreach($this->pap as $key => $data){
342       if($key == $key_id){
343         $add_now = $data;
344         continue;
345       }else{
346         $new[] = $data;
347       }
349       if($add_now != NULL){
350           
351         $new[] = $add_now;
352         $add_now = NULL;
353       }
354     }
355     if($add_now != NULL){
356       $new[] = $add_now;
357     }
358     $this->pap = $new;
359   }
362   /* This function moves the given element one position down 
363    *  if the next position is between 
364    *   '}' 'else[if]' or 'if' '{' use next available
365    */
366   function move_object_down($key_id)
367   {
368     $new = array();
369     $add_now = NULL;
371     /* Walk through all elements, till we found the given id.
372      *  If we found it, skip adding the current element,
373      *  first add the next element followed by the current.
374      */
375     foreach($this->pap as $key => $data){
377       /* Have we found the given id */
378       if($key == $key_id){
379         $add_now = $data;
380         $last_class = get_class($data);
381         continue;
382       }else{
383       
384         /* Add entry */
385         $new[] = $data;
386       }
388       /* We have skipped adding an element before,
389        *  try to add it now, if the position allows this.
390        */
391       if($add_now != NULL){
393         /* Don't allow adding an element directly after 
394          *  if/else/elsif 
395          */
396         if(in_array(get_class($data),array("sieve_if","sieve_elsif","sieve_else"))){
397           continue;
398         }
400         /* If this is an block end, check if there 
401          *  follows an if/else/elsif and skip adding the element in this case.
402          */
403         $next ="";
404         if(isset($this->pap[$key+1])){
405           $next = get_class($this->pap[$key+1]);
406         }
407         if(in_array(get_class($data),array("sieve_block_end")) && in_array($next,array("sieve_elsif","sieve_else"))){
408           continue;
409         }
410   
411         /* Add element, position seems to be ok */
412         $new[] = $add_now;
413         $add_now = NULL;
414       }
415     }
417     /* Element wasn't added, add it as last element */
418     if($add_now != NULL){
419       $new[] = $add_now;
420     }
421     $this->pap = $new;
422   }
425   /* Need to be reviewed */
426   function get_sieve_script()
427   {
428     $tmp ="";
429     if(count($this->pap)){
430       $buffer = "";    
431       foreach($this->pap as $part)  {
432         if(get_class($part) == "sieve_block_end"){
433           $buffer = substr($buffer,0,strlen($buffer)-(strlen(SIEVE_INDENT_TAB)));
434         }
435         $tmp2 = $part->get_sieve_script_part();
437         if(get_class($part) == "sieve_reject"){
438           $tmp.=$tmp2;
439         }else{
441           $tmp3 = split("\n",$tmp2);
442           foreach($tmp3 as $str){
443             $str2 = trim($str);
444             if(empty($str2)) continue;
445             $tmp.= $buffer.$str."\n";
446           }
447         }
448         if(get_class($part) == "sieve_block_start"){
449           $buffer .= SIEVE_INDENT_TAB;
450         }
451       }
452     }
453     if(!preg_match("/Generated by GOsa - Gonicus System Administrator/",$tmp)){
454       $tmp = "#Generated by GOsa - Gonicus System Administrator \n ".$tmp;
455     }
456     return($tmp);
457   }
459   function Add_Element()
460   {
461     $tmp = array("ELEMENTS" => array(array("class" => "qouted-string","text"=> "Bla bla, later more")));
462     $this->pap[] = new sieve_comment($tmp,rand(1000,100000));
463   }
467 /* Create valid sieve string/string-list 
468  *  out of a given array
469  */
470 function sieve_create_strings($data)
472   $ret = "";
473   if(is_array($data)){
474     if(count($data) == 1){
475       $ret = "\"";
476       foreach($data as $dat){
477         $ret .=$dat;
478       }
479       $ret.="\"";
480     }else{
481       foreach($data as $dat){
482         $ret.= "\"";
483         $ret.=$dat;
484         $ret.="\", ";
485       }
486       $ret = preg_replace("/,$/","",trim($ret));
487       $ret = "[".$ret."]";
488     }
489   }else{
491     $Multiline = preg_match("/\n/",$data);
492     $data = preg_replace("/\r/","",$data);;
494     if($Multiline){
495       $ret = "text: \r\n".$data."\r\n.\r\n";
496     }else{
497       $ret = "\"".$data."\"";
498     }
499   }
500   $ret = preg_replace("/\"\"/","\"",$ret);
501   $ret = preg_replace("/\n/","\r\n",$ret);
502   
503   return($ret);
506 /* This checks if there is a string at the current position 
507  *  in the token array. 
508  * If there is a string list at the current position,
509  *  this function will return a complete list of all
510  *  strings used in this list.
511  * It also returns an offset of the last token position 
512  */
513 function sieve_get_strings($data,$id)
515   $ret = array();
516   if($data[$id]['class'] == "left-bracket"){
517     while($data[$id]['class']  != "right-bracket" && $id < count($data)){
518       
519       if($data[$id]['class'] == "quoted-string"){
520         $ret[] = $data[$id]['text'];
521       }
522       $id ++;
523     }
524   }elseif($data[$id]['class'] == "quoted-string"){
525     $ret[] = $data[$id]['text'];
526   }elseif($data[$id]['class'] == "number"){
527     $ret[] = $data[$id]['text'];
528   }
529   return(array("OFFSET" => $id, "STRINGS" => $ret));
532 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
533 ?>