Code

removed some unecessary code.
[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();
19   function execute()
20   {
21     return($this->dump());
22   }
24   /* Create a html interface for the current sieve filter 
25    */
26   function dump()
27   {
28     /**************
29      * Handle new elements 
30      **************/
32     /* Only parse the tokens once */
33     if(!count($this->pap)){
34       $this->dump_ = "";
35       $this->mode_stack = array();
36       $this->pap = array();
37       $this->doDump_(0, '', true);
38     }
40     /* Create html results */
41     $smarty = get_smarty();
43     $this -> dump_ = "";
44     foreach($this->pap as $key => $object){
45       if(is_object($object)){
46         $this->dump_ .= preg_replace("/>/",">\n",$object->execute()); 
47       }
48     }
49     
50     return($this->dump_);
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     reset($this->pap);
148     foreach($this->pap as $key => $obj){
150       if(in_array(get_class($obj),array("sieve_if",
151                                         "sieve_elsif",
152                                         "sieve_vacation",
153                                         "sieve_comment",
154                                         "sieve_reject",
155                                         "sieve_fileinto",
156                                         "sieve_require",
157                                         "sieve_redirect"))){
160         if(isset($this->pap[$key]) && method_exists($this->pap[$key],"save_object")){
161           $this->pap[$key]->save_object();
162         }
163       }
164     }
165   }
168   /* Remove the object at the given position */
169   function remove_object($key_id)
170   {
171     $class = get_class($this->pap[$key_id]);
172     if(in_array($class,array("sieve_if"))){
173       $block_start= $key_id;
174       $block_end  = $this->get_block_end($key_id);
175       for($i = $block_start ; $i <= $block_end ; $i ++ ){
176         unset($this->pap[$i]);
177       }
178     }else{
179       unset($this->pap[$key_id]);
180     }
181     $tmp = array();
182     foreach($this->pap as $element){
183       $tmp[] = $element;
184     }
185     $this->pap = $tmp;
186   }
189   /* This function moves a given element to another position.
190    * Single elements like "keep;" will simply be moved one posisition down/up.
191    * Multiple elements like if-elsif-else will be moved as block. 
192    * 
193    *  $key_id     specified the element that should be moved.
194    *  $direction  specifies to move elements "up" or "down"
195    */
196   function move_up_down($key_id,$direction = "down")
197   {
198      
199     /* Get the current element to decide what to move. */ 
200     $e_class = get_class($this->pap[$key_id]);
201       
202     if(in_array($e_class,array("sieve_if"))){
203       $block_start= $key_id;
204       $block_end  = $this->get_block_end($key_id);
206       /* Depending on the direction move up down */
207       if($direction == "down"){
208         $next_free  = $this->_get_next_free_move_slot($block_end,$direction); 
209       }else{
210         $next_free  = $this->_get_next_free_move_slot($block_start,$direction); 
211       }
213       /* Move the given block */ 
214       $this->move_multiple_elements($block_start,$block_end,$next_free);
215     }
217     if(in_array($e_class,array( "sieve_stop",
218                                 "sieve_keep",
219                                 "sieve_require",
220                                 "sieve_comment",
221                                 "sieve_vacation",
222                                 "sieve_stop",   
223                                 "sieve_reject", 
224                                 "sieve_fileinto",
225                                 "sieve_redirect", 
226                                 "sieve_discard"))){
227       $this->move_single_element($key_id,$this->_get_next_free_move_slot($key_id,$direction));
228     }
229   }
231   
232   /* Move the given block to position */
233   function move_multiple_elements($start,$end,$to)
234   {
235     /* Use class names for testing */
236     $data = $this->pap;
238     /* Get block to move */
239     $block_to_move = array_slice($data,$start, ($end - $start +1));
241     /* We want do move this block up */
242     if($end > $to){
243       
244       /* Get start block */
245       $start_block = array_slice($data,0,$to);
247       /* Get Get all elements between the block to move 
248        *  and next free position 
249        */
250       $block_to_free = array_slice($data,$to ,$start - $to );  
251       $block_to_end = array_slice($data,$end+1);
252       $new = array();
253       foreach($start_block as $block){
254         $new[] = $block;
255       }
256       foreach($block_to_move as $block){
257         $new[] = $block;
258       }
259       foreach($block_to_free as $block){
260         $new[] = $block;
261       }
262       foreach($block_to_end as $block){
263         $new[] = $block;
264       }
265       $old = $this->pap;
266       $this->pap = $new;
267     }
268     
270     /* We want to move this block down. */
271     if($to > $end){
273       /* Get start block */
274       $start_block = array_slice($data,0,$start);
276       /* Get Get all elements between the block to move 
277        *  and next free position 
278        */
279       $block_to_free = array_slice($data,$end +1,($to - $end  ));  
281       /* Get the rest 
282        */
283       $block_to_end = array_slice($data,$to+1);
285       $new = array();
286       foreach($start_block as $block){
287         $new[] = $block;
288       }
289       foreach($block_to_free as $block){
290         $new[] = $block;
291       }
292       foreach($block_to_move as $block){
293         $new[] = $block;
294       }
295       foreach($block_to_end as $block){
296         $new[] = $block;
297       }
298       $old = $this->pap;
299       $this->pap = $new;
300     }
301   }  
303   
304   /* This function returns the id of the element 
305    *  where the current block ends  
306    */
307   function get_block_end($start)
308   {
309     /* Only execute if this is a really a block element. 
310      * Block elements is only sieve_if
311      */
312     if(in_array(get_class($this->pap[$start]),array("sieve_if"))){
314       $class      = get_class($this->pap[$start]);
315       $next_class = get_class($this->pap[$start+1]);
316       $block_depth = 0;
318       $end = FALSE;
320       while(!$end && $start < count($this->pap)){
321  
322         if($class == "sieve_block_start"){
323           $block_depth ++;
324         }
326         if($class == "sieve_block_end"){
327           $block_depth --;
328         }
330         if( $block_depth == 0 && 
331             $class == "sieve_block_end" && 
332             !in_array($next_class,array("sieve_else","sieve_elsif"))){
333           $end = TRUE;
334           $start --;
335         }
336         $start ++;       
337         $class      = get_class($this->pap[$start]);
338         $next_class = get_class($this->pap[$start+1]);
339       }
340     }
341     return($start);
342   }
345   /* This function moves the single element at 
346    *  position $from to position $to.
347    */
348   function move_single_element($from,$to)
349   {
350     if($from == $to) {
351       return;
352     }
354     $ret = array();
355     $tmp = $this->pap;
357     $begin = array();
358     $middle = array();
359     $end = array();
360     $element = $this->pap[$from];
362     if($from > $to ){
364       /* Get all element in fron to element to move */    
365       if($from  != 0){
366         $begin = array_slice($tmp,0,$to);
367       }
369       /* Get all elements between */
370       $middle = array_slice($tmp,$to , ($from - ($to) ));  
371     
372       /* Get the rest */ 
373       $end  = array_slice($tmp,$from+1);
374  
375       foreach($begin as $data){
376         $ret[] = $data;
377       }
378       $ret[] = $element;
379       foreach($middle as $data){
380         $ret[] = $data;
381       }
382       foreach($end as $data){
383         $ret[] = $data;
384       }
385       $this->pap = $ret;
386     }
387     if($from < $to ){
389       /* Get all element in fron to element to move */    
390       if($from  != 0){
391         $begin = array_slice($tmp,0,$from);
392       }
394       /* Get all elements between */
395       $middle = array_slice($tmp,$from+1 , ($to - ($from)));  
396     
397       /* Get the rest */ 
398       $end  = array_slice($tmp,$to+1);
399  
400       foreach($begin as $data){
401         $ret[] = $data;
402       }
403       foreach($middle as $data){
404         $ret[] = $data;
405       }
406       $ret[] = $element;
407       foreach($end as $data){
408         $ret[] = $data;
409       }
410       $this->pap = $ret;
411     }
412   }
415   /* Returns the next free position where we 
416    *  can add a new sinle element 
417    *    $key_id     = Current position
418    *    $direction  = Forward or backward.
419    */
420   function _get_next_free_move_slot($key_id,$direction)
421   {
422     $last_class = "";
423     $current_class ="";
424     $next_class = "";
426     /* After this elements we can add new elements 
427      *  without having any trouble.
428      */
429     $allowed_to_add_after = array("sieve_keep",
430                                   "sieve_require", 
431                                   "sieve_stop", 
432                                   "sieve_reject", 
433                                   "sieve_fileinto", 
434                                   "sieve_redirect", 
435                                   "sieve_discard",
436                                   "sieve_comment",
437                                   "sieve_block_start"
438                                  );
440     /* Before this elements we can add new elements 
441      *  without having any trouble.
442      */
443     $allowed_to_add_before = array("sieve_keep",
444                                   "sieve_require", 
445                                   "sieve_stop", 
446                                   "sieve_reject", 
447                                   "sieve_fileinto", 
448                                   "sieve_comment",
449                                   "sieve_redirect", 
450                                   "sieve_discard",
451                                   "sieve_if", 
452                                   "sieve_block_end"
453                                  );
455     if($direction == "down"){
456     
457       $test = $this->pap;
458       while($key_id < count($test)){
459         if(($key_id+1) == count($test)) {
460           return($key_id);
461         }
462         $key_id ++;
463         $current_class  = get_class($test[$key_id]);
464         if(in_array($current_class, $allowed_to_add_after)){
465           return($key_id);
466         } 
467       } 
468     }else{
469   
470       $test = $this->pap;
471       if($key_id == 0) {
472         return($key_id);
473       }
474       $key_id --;
475       while($key_id >=0 ){
476         $current_class  = get_class($test[$key_id]);
477         if(in_array($current_class, $allowed_to_add_before)){
478           return($key_id);
479         } 
480         $key_id --;
481       }
482       return(0);
483     }
484   }
487   /* Need to be reviewed */
488   function get_sieve_script()
489   {
490     $tmp ="";
491     if(count($this->pap)){
492       $buffer = "";    
493       foreach($this->pap as $part)  {
494         if(get_class($part) == "sieve_block_end"){
495           $buffer = substr($buffer,0,strlen($buffer)-(strlen(SIEVE_INDENT_TAB)));
496         }
497         $tmp2 = $part->get_sieve_script_part();
499         if(get_class($part) == "sieve_reject"){
500           $tmp.=$tmp2;
501         }else{
503           $tmp3 = split("\n",$tmp2);
504           foreach($tmp3 as $str){
505             $str2 = trim($str);
506             if(empty($str2)) continue;
507             $tmp.= $buffer.$str."\n";
508           }
509         }
510         if(get_class($part) == "sieve_block_start"){
511           $buffer .= SIEVE_INDENT_TAB;
512         }
513       }
514     }
515     if(!preg_match("/Generated by GOsa - Gonicus System Administrator/",$tmp)){
516       $tmp = "#Generated by GOsa - Gonicus System Administrator \n ".$tmp;
517     }
518     return($tmp);
519   }
521   function Add_Element()
522   {
523     $tmp = array("ELEMENTS" => array(array("class" => "qouted-string","text"=> "Bla bla, later more")));
524     $this->pap[] = new sieve_comment($tmp,rand(1000,100000));
525   }
527   function check()
528   {
529                 $msgs = array();
531     /* Some logical checks. 
532      *  like :  only sieve_comment can appear before require.
533      */
534     
535     /* Ensure that there are no command before require 
536      *  - Get id of last require tag
537      *  - Collect object types in from of this tag. 
538      *  - Check if there are tags collected that are not allowed 
539      */
540     $last_found_at = -1; 
541     $objs = array();
542     foreach($this->pap as $key => $obj){
543       if(get_class($obj) == "sieve_require"){
544         $last_found_at = $key;
545       }
546     }
547     foreach($this->pap as $key => $obj){
548       if($key == $last_found_at) break;  
549       if(!in_array(get_class($obj),array("sieve_comment","sieve_require"))){
550         $objs[] = get_class($obj);
551       }
552     }
553     if(count($objs) && $last_found_at != -1){
554       $str = _("Require must be the first command in the script.");  
555       $msgs[] = $str;
556       print_red($str);;
557     }
558     
559                 foreach($this->pap as $obj){
560                         $o_msgs = $obj->check();
561                         foreach($o_msgs as $o_msg){
562                                 $msgs[] = $o_msg;
563                         }
564                 }
565                 return($msgs);
566   }
570 /* Create valid sieve string/string-list 
571  *  out of a given array
572  */
573 function sieve_create_strings($data,$force_string = FALSE)
575   $ret = "";
576   if(is_array($data)){
577     if(count($data) == 1){
578       $ret = "\"";
579       foreach($data as $dat){
580         $ret .=$dat;
581       }
582       $ret.="\"";
583     }else{
584       foreach($data as $dat){
585         $ret.= "\"";
586         $ret.=$dat;
587         $ret.="\", ";
588       }
589       $ret = preg_replace("/,$/","",trim($ret));
590       $ret = "[".$ret."]";
591     }
592   }else{
594     $Multiline = preg_match("/\n/",$data);
595     $data = preg_replace("/\r/","",$data);;
597     if($Multiline && !$force_string){
598       $ret = "text: \r\n".$data."\r\n.\r\n";
599     }else{
600       $ret = "\"".$data."\"";
601     }
602   }
603   $ret = preg_replace("/\"\"/","\"",$ret);
604   $ret = preg_replace("/\n/","\r\n",$ret);
605   
606   return($ret);
609 /* This checks if there is a string at the current position 
610  *  in the token array. 
611  * If there is a string list at the current position,
612  *  this function will return a complete list of all
613  *  strings used in this list.
614  * It also returns an offset of the last token position 
615  */
616 function sieve_get_strings($data,$id)
618   $ret = array();
619   if($data[$id]['class'] == "left-bracket"){
620     while($data[$id]['class']  != "right-bracket" && $id < count($data)){
621       
622       if($data[$id]['class'] == "quoted-string"){
623         $ret[] = $data[$id]['text'];
624       }
625       $id ++;
626     }
627   }elseif($data[$id]['class'] == "quoted-string"){
628     $ret[] = $data[$id]['text'];
629   }elseif($data[$id]['class'] == "number"){
630     $ret[] = $data[$id]['text'];
631   }elseif($data[$id]['class'] == "multi-line"){
632     $str = trim(preg_replace("/^text:/","",$data[$id]['text']));
633     $str = trim(preg_replace("/\.$/","",$str));
634     $ret[] = $str;
635   }
636   
637   return(array("OFFSET" => $id, "STRINGS" => $ret));
640 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
641 ?>