Code

Updated sieve filter styles.
[gosa.git] / include / sieve / class_My_Tree.inc
index 3774ef0db044968b8a2622685ef01fb2e866dbac..ee1276a36ac3c1aba3c85281c0f2aa6b0bd2696b 100644 (file)
@@ -15,127 +15,79 @@ class My_Tree extends Tree
 
   var $mode_stack = array();
   var $pap             = array();
+  var $parent = NULL;
 
-  var $add_new          = FALSE;
-  var $add_new_id       = 0;
-  var $add_type         = "top";
-  var $add_element_type = "";
+  function My_Tree(&$root,$parent)
+  {
+    $this->parent = $parent;
+    $this->_construct($root);
+  }
+
+  function execute()
+  {
+    return($this->dump());
+  }
 
   /* Create a html interface for the current sieve filter 
    */
   function dump()
   {
-    error_reporting(E_ALL);
-
     /**************
      * Handle new elements 
      **************/
 
-    if($this->add_new){
-  
-      $element_types= array(
-          "sieve_keep"      => _("Keep"),
-          "sieve_comment"   => _("Comment"),
-          "sieve_fileinto"  => _("File into"),
-          "sieve_keep"      => _("Keep"),
-          "sieve_discard"   => _("Discard"),
-          "sieve_redirect"  => _("Redirect"),
-          "sieve_reject"    => _("Reject"),
-          "sieve_require"   => _("Require"),
-          "sieve_stop"      => _("Stop"),
-          "sieve_vacation"  => _("Vacation message"),
-          "sieve_if"        => _("If"));
-
-
-      /* Element selected */
-      if(isset($_POST['element_type']) && isset($element_types[$_POST['element_type']])){
-        $this->add_element_type = $_POST['element_type'];
-      }
-
-      /* Create new element and add it at the selected position */
-      if(isset($_POST['select_new_element_type'])){
-
-        $ele = new $this->add_element_type(NULL, preg_replace("/[^0-9]/","",microtime()));
-        $start = $end = array();
-        $found = false;  
-
-        /* Add above current element*/
-        if($this->add_type == "top"){
-          foreach($this->pap as $key => $obj){
-            if($obj->object_id == $this->add_new_id){
-              $found = true;
-            }
-            if(!$found){
-              $start[] = $obj;
-            }else{
-              $end[] = $obj;
-            }
-          }    
-        }else{
-        /* Add below current element */
-          foreach($this->pap as $key => $obj){
-            if(!$found){
-              $start[] = $obj;
-            }else{
-              $end[] = $obj;
-            }
-            if($obj->object_id == $this->add_new_id){
-              $found = true;
-            }
-          }    
-        }
-
-        /* Only add, if current element could be located */
-        if($found){
-          $new = array();
-          foreach($start as $obj){
-            $new[] = $obj;
-          }      
-          $new[] = $ele;
-          foreach($end as $obj){
-            $new[] = $obj;
-          }
-          $this->pap = $new;
-          $this->add_new = FALSE;
-        }else{
-          print_red(_("Something went wrong while adding a new entry."));
-        }
-      }
-
-    }
-
-    /* Only display select dialog if it is necessary */
-    if($this->add_new){  
-      $smarty = get_smarty();
-      $smarty->assign("element_types",$element_types );
-      $smarty->assign("element_type",$this->add_element_type);
-      $str = $smarty->fetch(get_template_path("templates/add_element.tpl",TRUE,dirname(__FILE__)));
-      return($str);
-    }
-
     /* 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(get_class($object),array("sieve_if"))){
+          $ends_complete_block[$end2] = $end2;
+          $this->dump_ .= "<div style='height:10px;'></div>";
+          $this->dump_ .= "<div class='container_'>";
+        }
+        if(isset($ends[$key])){
+          $this->dump_  .= $block_indent_stop;
+        }
         $this->dump_ .= preg_replace("/>/",">\n",$object->execute()); 
+        if($end != $key && in_array(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_ .= "</div>";
+          $this->dump_ .= "<div style='height:10px;'></div>";
+        }
       }
     }
     
-    /* Create html results */
-    $smarty = get_smarty();
-    $smarty->assign("Contents",$this->dump_);
-    $ret = $smarty->fetch(get_template_path("templates/edit_frame_base.tpl",TRUE,dirname(__FILE__)));
-    return ($ret);
+    return($this->dump_);
   }
 
 
@@ -153,18 +105,31 @@ class My_Tree extends Tree
     /* 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"),$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"),$node_id);
+      $this->handle_elements(array("TYPE" => "block_end"),preg_replace("/[^0-9]/","",microtime()));
     }
 
     /* Semicolon indicates a new command */
@@ -173,22 +138,42 @@ class My_Tree extends Tree
       $this->handle_elements($tmp,$node_id);
     }
 
-    /* Handle comments */
-    if($node['class'] == "comment"){
-      $this->mode_stack[] = array("TYPE" => $node['class']);
-      $rewoke_last = TRUE;
+    /* 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","comment","fileinto","require","stop");
+    $identifiers = array("else","if","elsif","end","reject","redirect","vacation","keep","discard","fileinto","require","stop");
     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;
+    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){
@@ -224,7 +209,7 @@ class My_Tree extends Tree
     
     $class_name= "sieve_".$type ;
     if(class_exists($class_name)){
-      $this->pap[] = new $class_name($data,$id);
+      $this->pap[] = new $class_name($data,$id,$this);
     }else{
       echo "<font color='red'>Missing : ".$class_name."</font>"."<br>";
     }
@@ -249,51 +234,28 @@ class My_Tree extends Tree
           $this->pap[$key]->save_object();
         }
       }
-
-      $once = TRUE;
-      foreach($_POST as $name => $value){
-
-        if(isset($obj->object_id) && preg_match("/^Remove_Object_".$obj->object_id."_/",$name) && $once){
-          $once = FALSE;
-          $this->remove_object($key);
-        }
-        if(isset($obj->object_id) && preg_match("/^Move_Up_Object_".$obj->object_id."_/",$name) && $once){
-          $this->move_up_down($key,"up");
-          $once = FALSE;
-        }
-        if(isset($obj->object_id) && preg_match("/^Move_Down_Object_".$obj->object_id."_/",$name) && $once){
-          $this->move_up_down($key,"down");
-          $once = FALSE;
-        }
-        if(isset($obj->object_id) && preg_match("/^Add_Object_Top_".$obj->object_id."_/",$name) && $once){
-          $this->add_new_object($obj->object_id,"top");
-          $once = FALSE;
-        }
-        if(isset($obj->object_id) && preg_match("/^Add_Object_Bottom_".$obj->object_id."_/",$name) && $once){
-          $this->add_new_object($obj->object_id,"bottom");
-          $once = FALSE;
-        }
-      }
     }
   }
 
 
-  /* Add a new object at the given position */
-  function add_new_object($id,$top_bottom = "bottom")
-  {
-    $this->add_new    = TRUE;
-    $this->add_new_id = $id;
-    $this->add_type   = $top_bottom;
-  }
-
-
   /* Remove the object at the given position */
   function remove_object($key_id)
   {
+    if(count($this->pap) == 1){
+      print_red(_("Can't remove last element."));
+      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($class,array("sieve_if"))){
+    if(in_array($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]);
       }
@@ -340,6 +302,7 @@ class My_Tree extends Tree
                                 "sieve_keep",
                                 "sieve_require",
                                 "sieve_comment",
+                                "sieve_vacation",
                                 "sieve_stop",   
                                 "sieve_reject", 
                                 "sieve_fileinto",
@@ -425,12 +388,12 @@ class My_Tree extends Tree
   /* This function returns the id of the element 
    *  where the current block ends  
    */
-  function get_block_end($start)
+  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(get_class($this->pap[$start]),array("sieve_if"))){
+    if(in_array(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]);
@@ -448,15 +411,30 @@ class My_Tree extends Tree
           $block_depth --;
         }
 
-        if( $block_depth == 0 && 
-            $class == "sieve_block_end" && 
-            !in_array($next_class,array("sieve_else","sieve_elsif"))){
-          $end = TRUE;
-          $start --;
+        if($complete){
+          if( $block_depth == 0 && 
+              $class == "sieve_block_end" && 
+              !in_array($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]);
-        $next_class = get_class($this->pap[$start+1]);
+        
+        if(isset($this->pap[$start+1])){ 
+          $next_class = get_class($this->pap[$start+1]);
+        }else{
+          $next_class ="";
+        }
       }
     }
     return($start);
@@ -538,7 +516,7 @@ class My_Tree extends Tree
    *    $key_id     = Current position
    *    $direction  = Forward or backward.
    */
-  function _get_next_free_move_slot($key_id,$direction)
+  function _get_next_free_move_slot($key_id,$direction,$include_self = FALSE)
   {
     $last_class = "";
     $current_class ="";
@@ -580,7 +558,11 @@ class My_Tree extends Tree
         if(($key_id+1) == count($test)) {
           return($key_id);
         }
-        $key_id ++;
+
+        if(!$include_self){
+          $key_id ++;
+        }
+        $include_self = FALSE;
         $current_class  = get_class($test[$key_id]);
         if(in_array($current_class, $allowed_to_add_after)){
           return($key_id);
@@ -592,7 +574,9 @@ class My_Tree extends Tree
       if($key_id == 0) {
         return($key_id);
       }
-      $key_id --;
+      if(!$include_self){
+        $key_id --;
+      }
       while($key_id >=0 ){
         $current_class  = get_class($test[$key_id]);
         if(in_array($current_class, $allowed_to_add_before)){
@@ -617,14 +601,19 @@ class My_Tree extends Tree
         }
         $tmp2 = $part->get_sieve_script_part();
 
-        if(get_class($part) == "sieve_reject"){
-          $tmp.=$tmp2;
-        }else{
-
-          $tmp3 = split("\n",$tmp2);
-          foreach($tmp3 as $str){
-            $str2 = trim($str);
-            if(empty($str2)) continue;
+        $tmp3 = 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";
           }
         }
@@ -634,28 +623,79 @@ class My_Tree extends Tree
       }
     }
     if(!preg_match("/Generated by GOsa - Gonicus System Administrator/",$tmp)){
-      $tmp = "#Generated by GOsa - Gonicus System Administrator \n ".$tmp;
+#      $tmp = "#Generated by GOsa - Gonicus System Administrator \n ".$tmp;
     }
     return($tmp);
   }
 
-  function Add_Element()
+  function check()
   {
-    $tmp = array("ELEMENTS" => array(array("class" => "qouted-string","text"=> "Bla bla, later more")));
-    $this->pap[] = new sieve_comment($tmp,rand(1000,100000));
+    $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(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;
+      print_red($str);;
+    }
+
+    foreach($this->pap as $obj){
+      $o_msgs = $obj->check();
+      foreach($o_msgs as $o_msg){
+        $msgs[] = $o_msg;
+      }
+    }
+    return($msgs);
   }
 
-  function check()
+
+  /* We are forced to add a new require.
+   *  This function is called by the 
+   *  sieveElement_Classes->parent->add_require()  
+   */ 
+  function add_require($str)
   {
-               $msgs = array();
-               foreach($this->pap as $obj){
-
-                       $o_msgs = $obj->check();
-                       foreach($o_msgs as $o_msg){
-                               $msgs[] = $o_msg;
-                       }
-               }
-               return($msgs);
+    $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);
+    } 
   }
 }
 
@@ -663,7 +703,7 @@ class My_Tree extends Tree
 /* Create valid sieve string/string-list 
  *  out of a given array
  */
-function sieve_create_strings($data)
+function sieve_create_strings($data,$force_string = FALSE)
 {
   $ret = "";
   if(is_array($data)){
@@ -687,7 +727,7 @@ function sieve_create_strings($data)
     $Multiline = preg_match("/\n/",$data);
     $data = preg_replace("/\r/","",$data);;
 
-    if($Multiline){
+    if($Multiline && !$force_string){
       $ret = "text: \r\n".$data."\r\n.\r\n";
     }else{
       $ret = "\"".$data."\"";
@@ -695,7 +735,7 @@ function sieve_create_strings($data)
   }
   $ret = preg_replace("/\"\"/","\"",$ret);
   $ret = preg_replace("/\n/","\r\n",$ret);
-  
+
   return($ret);
 }
 
@@ -710,18 +750,24 @@ function sieve_get_strings($data,$id)
 {
   $ret = array();
   if($data[$id]['class'] == "left-bracket"){
-    while($data[$id]['class']  != "right-bracket" && $id < count($data)){
-      
+    while(isset($data[$id]) && $data[$id]['class']  != "right-bracket" && $id < count($data)){
+
       if($data[$id]['class'] == "quoted-string"){
         $ret[] = $data[$id]['text'];
       }
+
       $id ++;
     }
   }elseif($data[$id]['class'] == "quoted-string"){
     $ret[] = $data[$id]['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));
 }