Code

Added new sieve Handling
authorhickert <hickert@594d385d-05f5-0310-b6e9-bd551577e9d8>
Thu, 3 May 2007 12:56:42 +0000 (12:56 +0000)
committerhickert <hickert@594d385d-05f5-0310-b6e9-bd551577e9d8>
Thu, 3 May 2007 12:56:42 +0000 (12:56 +0000)
git-svn-id: https://oss.gonicus.de/repositories/gosa/branches/2.5@6253 594d385d-05f5-0310-b6e9-bd551577e9d8

61 files changed:
html/themes/default/style.css
include/class_sieve.inc [deleted file]
include/sieve/class_My_Parser.inc [new file with mode: 0644]
include/sieve/class_My_Scanner.inc [new file with mode: 0644]
include/sieve/class_My_Tree.inc [new file with mode: 0644]
include/sieve/class_parser.inc [new file with mode: 0644]
include/sieve/class_scanner.inc [new file with mode: 0644]
include/sieve/class_semantics.inc [new file with mode: 0644]
include/sieve/class_sieve.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Block_End.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Block_Start.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Comment.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Discard.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Else_Elsif.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Fileinto.inc [new file with mode: 0644]
include/sieve/class_sieveElement_If.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Keep.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Redirect.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Reject.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Require.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Stop.inc [new file with mode: 0644]
include/sieve/class_sieveElement_Vacation.inc [new file with mode: 0644]
include/sieve/class_sieveManagement.inc [new file with mode: 0644]
include/sieve/class_tree.inc [new file with mode: 0644]
include/sieve/libsieve.inc [new file with mode: 0644]
include/sieve/templates/add_element.tpl [new file with mode: 0644]
include/sieve/templates/block_indent_start.tpl [new file with mode: 0644]
include/sieve/templates/block_indent_stop.tpl [new file with mode: 0644]
include/sieve/templates/create_script.tpl [new file with mode: 0644]
include/sieve/templates/edit_frame_base.tpl [new file with mode: 0644]
include/sieve/templates/element_address.tpl [new file with mode: 0755]
include/sieve/templates/element_allof.tpl [new file with mode: 0644]
include/sieve/templates/element_anyof.tpl [new file with mode: 0644]
include/sieve/templates/element_block_end.tpl [new file with mode: 0644]
include/sieve/templates/element_block_start.tpl [new file with mode: 0644]
include/sieve/templates/element_boolean.tpl [new file with mode: 0755]
include/sieve/templates/element_comment.tpl [new file with mode: 0644]
include/sieve/templates/element_discard.tpl [new file with mode: 0644]
include/sieve/templates/element_else.tpl [new file with mode: 0644]
include/sieve/templates/element_elsif.tpl [new file with mode: 0644]
include/sieve/templates/element_envelope.tpl [new file with mode: 0755]
include/sieve/templates/element_exists.tpl [new file with mode: 0644]
include/sieve/templates/element_fileinto.tpl [new file with mode: 0644]
include/sieve/templates/element_header.tpl [new file with mode: 0755]
include/sieve/templates/element_if.tpl [new file with mode: 0644]
include/sieve/templates/element_keep.tpl [new file with mode: 0644]
include/sieve/templates/element_redirect.tpl [new file with mode: 0644]
include/sieve/templates/element_reject.tpl [new file with mode: 0644]
include/sieve/templates/element_require.tpl [new file with mode: 0644]
include/sieve/templates/element_size.tpl [new file with mode: 0644]
include/sieve/templates/element_stop.tpl [new file with mode: 0644]
include/sieve/templates/element_vacation.tpl [new file with mode: 0644]
include/sieve/templates/import_script.tpl [new file with mode: 0644]
include/sieve/templates/management.tpl [new file with mode: 0644]
include/sieve/templates/object_container.tpl [new file with mode: 0644]
include/sieve/templates/object_container_clear.tpl [new file with mode: 0644]
include/sieve/templates/object_test_container.tpl [new file with mode: 0644]
include/sieve/templates/remove_script.tpl [new file with mode: 0644]
include/sieve/templates/select_test_type.tpl [new file with mode: 0644]
plugins/personal/mail/class_mailAccount.inc
plugins/personal/mail/generic.tpl

index 37d40101bf3e5cb4f030908ef4e0181ff35b4208..b63fbcc4363610ff4f059a80eb9fac712d1ea91c 100644 (file)
@@ -771,3 +771,368 @@ td.tbhead {
 td.tbrhead {
        border-bottom:1px solid #B0B0B0;
 }
+
+/************************
+ * Sieve
+ *  The following styles are
+ *  used to display the sieve
+ *  management user interface
+ ************************/
+
+/* Editing dialog styles
+ */
+
+table.sieve_default_table {
+    width:100%;
+    margin: 0px;
+    border-spacing: 0px ;
+    padding:0px;
+}
+
+
+/* Editing surface */
+table.editing_surface {
+    width:100%;
+    margin: 0px;
+    padding:0px;
+}
+
+/* Editing surface menu */
+td.editing_surface_menu {
+    background-color: #EEE;
+    border: 1px solid #BBB;
+    padding:5px;
+}
+
+/* Editing surface content */
+td.editing_surface_content {
+    background-color: #FFFFFF;
+    margin: 0px;
+    padding:0px;
+}
+
+/* Error message will be displayed as follows */
+div.sieve_error_msgs {
+    background-color: #ff8d00;
+    color: #000000;
+    padding:5px;
+    background-image: url("images/warning.png");
+    background-repeat: no-repeat;
+    font-weight: bold;
+}
+
+/* Source editing area */
+textarea.editing_source {
+    width:100%;
+    height:330px;
+}
+
+
+/*************
+ * Object container
+ *************/
+
+/* The container itself */
+table.object_container_container {
+    width:100%;
+    border-spacing: 0px ;
+    background-color: #F8F8F8;
+    border: solid 1px #AAAAAA;
+}
+
+/* Container cell top left */
+td.object_container_cell_top_left {
+    background-color: #EEE;
+    text-align:center;
+}
+
+/* Container cell top right */
+td.object_container_cell_top_right {
+    background-color: #EEE;
+    text-align:left;
+    padding:2px;
+    border-bottom: solid 1px #AAAAAA;
+}
+/* Container cell bottom left */
+td.object_container_cell_bottom_left {
+    width:5px;
+    background-color: #EEE;
+    text-align:center;
+    border-right: solid 1px #AAAAAA;
+}
+
+
+/*************
+ * Sieve comment
+ *************/
+
+/* Container */
+table.sieve_comment_container {
+    margin:0px;
+    padding:0px;
+    border-spacing: 0px ;
+    width:100%;
+    background-color: #F8F8F8;
+}
+
+/* Editing area */
+textarea.sieve_comment_area {
+    width:100%;
+    height:80px;
+}
+
+
+/*************
+ * Sieve require
+ *************/
+
+/* Container */
+table.sieve_require_container {
+    margin:0px;
+    padding:0px;
+    border-spacing: 0px ;
+    width:100%;
+    background-color: #F8F8F8;
+}
+/* Editing area */
+input.sieve_require_input {
+    width:100%;
+    border-spacing: 0px ;
+}
+
+
+/*************
+ * Sieve fileinto
+ *************/
+
+/* Container */
+table.sieve_fileinto_container {
+    margin:0px;
+    padding:0px;
+    border-spacing: 0px ;
+    width:100%;
+    background-color: #F8F8F8;
+}
+
+/* Editing area */
+input.sieve_fileinto_input {
+    width:300px;
+}
+select.sieve_fileinto_input {
+    width:300px;
+}
+
+
+/*************
+ * Sieve keep
+ *************/
+
+/* Container */
+table.sieve_keep_container {
+    margin:0px;
+    padding:0px;
+    border-spacing: 0px ;
+    width:100%;
+    background-color: #F8F8F8;
+}
+/* Editing area */
+td.sieve_keep_input {
+    padding-left:20px;
+}
+
+
+/*************
+ * Sieve discard
+ *************/
+
+/* Container */
+table.sieve_discard_container {
+    margin:0px;
+    padding:0px;
+    border-spacing: 0px ;
+    width:100%;
+    background-color: #F8F8F8;
+}
+
+/* Editing area */
+td.sieve_discard_input {
+    padding-left:20px;
+}
+
+
+/*************
+ * Sieve redirect
+ *************/
+
+/* Container */
+table.sieve_redirect_container {
+    margin:0px;
+    padding:0px;
+    border-spacing: 0px ;
+    width:100%;
+    background-color: #F8F8F8;
+}
+
+/* Editing area */
+td.sieve_redirect_input {
+    padding-left:20px;
+}
+textarea.sieve_redirect_input {
+    width:100%;
+    height:30px;
+}
+
+
+/*************
+ * Sieve reject
+ *************/
+
+/* Container */
+table.sieve_reject_container {
+    margin:0px;
+    padding:0px;
+    border-spacing: 0px ;
+    width:100%;
+    background-color: #F8F8F8;
+}
+
+/* Editing area */
+td.sieve_reject_input {
+    padding-left:20px;
+}
+textarea.sieve_reject_input {
+    width:100%;
+    height:55px;
+}
+
+
+/*************
+ * Sieve end
+ *************/
+
+/* Container */
+table.sieve_stop_container {
+    margin:0px;
+    padding:0px;
+    border-spacing: 0px ;
+    width:100%;
+    background-color: #F8F8F8;
+}
+
+/* Editing area */
+td.sieve_stop_input {
+    padding-left:20px;
+}
+
+
+/*************
+ * Sieve vacation
+ *************/
+
+/* Container */
+table.sieve_vacation_container {
+    margin:0px;
+    padding:0px;
+    border-spacing: 0px ;
+    width:100%;
+    background-color: #F8F8F8;
+}
+
+/* Editing area */
+td.sieve_vacation_input {
+    padding-left:20px;
+}
+
+/* Editing area */
+textarea.sieve_vacation_input {
+    width:100%;
+    height : 55px;
+}
+
+
+/*************
+ * Sieve allof
+ *************/
+
+table.sieve_allof_container {
+    width:100%;
+    border-spacing: 0px ;
+    margin: 0px;
+    padding:0px;
+    border: solid 1px #999999;
+}
+
+/* Container */
+td.sieve_allof_left {
+    text-align:center;
+    vertical-align: middle;
+    width:35px;
+    background-color: #CCCCCC;
+    border: solid 0px #EEE;
+}
+
+/* Container */
+td.sieve_allof_right {
+    background-color:#BDBDBD ;
+}
+
+/*************
+ * Sieve anyof
+ *************/
+
+table.sieve_anyof_container {
+    width:100%;
+    margin: 0px;
+    border-spacing: 0px ;
+    padding:0px;
+    border: solid 2px #CCCCCC;
+}
+
+/* Container */
+td.sieve_anyof_left {
+    text-align:center;
+    vertical-align: middle;
+    width:35px;
+    background-color: #CCCCCC;
+    border: solid 0px #EEEEEE
+}
+
+/* Container */
+td.sieve_anyof_right {
+    background-color:#BDBDBD ;
+    border: solid 1px #AAAAAA;
+}
+/*************
+ * Sieve Test Cases
+ *************/
+
+table.sieve_test_container {
+    width:100%;
+    background-color:#F8F8F8;
+    margin: 0px;
+    border-spacing: 0px ;
+    padding:0px;
+    border: solid 1px #AAAAAA;
+}
+
+table.sieve_test_case {
+    width:100%;
+    margin: 0px;
+    border-spacing: 0px ;
+    padding:0px;
+}
+
+
+
+td.container_, div.container_{
+    padding-left:2px;
+    border-left: solid 2px #F8F8F8;
+}
+
+td.container_:hover,div.container_:hover {
+    border-left: solid 2px black;
+    display:block;
+}
+
+
+
diff --git a/include/class_sieve.inc b/include/class_sieve.inc
deleted file mode 100644 (file)
index 16b50f6..0000000
+++ /dev/null
@@ -1,519 +0,0 @@
-<?
-
-/*
- * $Id: class_sieve.inc,v 1.1 2005/02/21 09:33:01 cajus Exp $ 
- *
- * Copyright 2001 Dan Ellis <danellis@rushmore.com>
- *
- * See the enclosed file COPYING for license information (GPL).  If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-// TODO before next release:   remove ::status() and dependencies
-
-
-define ("F_NO", 0);            
-define ("F_OK", 1);
-define ("F_DATA", 2);
-define ("F_HEAD", 3);
-
-define ("EC_NOT_LOGGED_IN", 0);
-define ("EC_QUOTA", 10);
-define ("EC_NOSCRIPTS", 20);
-define ("EC_UNKNOWN", 255);
-/*
-
-SIEVE-PHP.LIB VERSION 0.0.8
-
-(C) 2001 Dan Ellis.
-
-PLEASE READ THE README FILE FOR MORE INFORMATION.
-
-Basically, this is the first re-release.  Things are much better than before.
-
-Notes:
-This program/libary has bugs.
-       .       This was quickly hacked out, so please let me know what is wrong and if you feel ambitious submit
-               a patch :).
-
-Todo:
-       .       Provide better error diagnostics.                       (mostly done with ver 0.0.5)
-       .       Allow other auth mechanisms besides plain               (in progress)
-       .       Have timing mechanism when port problems arise.         (not done yet)
-       .       Maybe add the NOOP function.                            (not done yet)
-       .       Other top secret stuff....                              (some done, believe me?)
-
-Dan Ellis (danellis@rushmore.com)
-
-This program is released under the GNU Public License.
-
-You should have received a copy of the GNU Public
- License along with this package; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.        
-
-See CHANGES for updates since last release
-
-Contributers of patches:
-       Atif Ghaffar
-       Andrew Sterling Hanenkamp <sterling@hanenkamp.com>
-*/
-
-
-class sieve
-{
-  var $host;
-  var $port;
-  var $user;
-  var $pass;
-  var $auth_types;             /* a comma seperated list of allowed auth types, in order of preference */
-  var $auth_in_use;            /* type of authentication attempted */
-  
-  var $line;
-  var $fp;
-  var $retval;
-  var $tmpfile;
-  var $fh;
-  var $len;
-  var $script;
-
-  var $loggedin;
-  var $capabilities;
-  var $error;
-  var $error_raw;
-  var $responses;
-
-  //maybe we should add an errorlvl that the user will pass to new sieve = sieve(,,,,E_WARN)
-  //so we can decide how to handle certain errors?!?
-
-  //also add a connection type, like PLAIN, MD5, etc...
-
-
-  function get_response()
-  {
-    if($this->loggedin == false or feof($this->fp)){
-        $this->error = EC_NOT_LOGGED_IN;
-        $this->error_raw = "You are not logged in.";
-        return false;
-    }
-
-    unset($this->response);
-    unset($this->error);
-    unset($this->error_raw);
-
-    $this->line=fgets($this->fp,1024);
-    $this->token = split(" ", $this->line, 2);
-
-    if($this->token[0] == "NO"){
-        /* we need to try and extract the error code from here.  There are two possibilites: one, that it will take the form of:
-           NO ("yyyyy") "zzzzzzz" or, two, NO {yyyyy} "zzzzzzzzzzz" */
-        $this->x = 0;
-        list($this->ltoken, $this->mtoken, $this->rtoken) = split(" ", $this->line." ", 3);
-        if($this->mtoken[0] == "{"){
-            while($this->mtoken[$this->x] != "}" or $this->err_len < 1){
-                $this->err_len = substr($this->mtoken, 1, $this->x);
-                $this->x++;    
-            }
-            //print "<br>Trying to receive $this->err_len bytes for result<br>";
-            $this->line = fgets($this->fp,$this->err_len);
-            $this->error_raw[]=substr($this->line, 0, strlen($this->line) -2);    //we want to be nice and strip crlf's
-            $this->err_recv = strlen($this->line);
-
-           /* Avoid loop till memory is full 
-               This can happen if sieve script is modified via external scripts and not by gosa .. */
-           $max = 10000;
-            $cur = 0 ; 
-            while($this->err_recv < $this->err_len && ($cur < $max)){
-                //print "<br>Trying to receive ".($this->err_len-$this->err_recv)." bytes for result<br>";
-                $cur ++ ; 
-                $this->line = fgets($this->fp, ($this->err_len-$this->err_recv));
-                $this->error_raw[]=substr($this->line, 0, strlen($this->line) -2);    //we want to be nice and strip crlf's
-                $this->err_recv += strlen($this->line);
-            } /* end while */
-            $this->line = fgets($this->fp, 1024);      //we need to grab the last crlf, i think.  this may be a bug...
-            $this->error=EC_UNKNOWN;
-      
-        } /* end if */
-        elseif($this->mtoken[0] == "("){
-            switch($this->mtoken){
-                case "(\"QUOTA\")":
-                    $this->error = EC_QUOTA;
-                    $this->error_raw=$this->rtoken;
-                    break;
-                default:
-                    $this->error = EC_UNKNOWN;
-                    $this->error_raw=$this->rtoken;
-                    break;
-            } /* end switch */
-        } /* end elseif */
-        else{
-            $this->error = EC_UNKNOWN;
-            $this->error_raw = $this->line;
-        }     
-        return false;
-
-    } /* end if */
-    elseif(substr($this->token[0],0,-2) == "OK"){
-         return true;
-    } /* end elseif */
-    elseif($this->token[0][0] == "{"){
-        
-        /* Unable wild assumption:  that the only function that gets here is the get_script(), doesn't really matter though */       
-
-        /* the first line is the len field {xx}, which we don't care about at this point */
-        $this->line = fgets($this->fp,1024);
-        while(substr($this->line,0,2) != "OK" and substr($this->line,0,2) != "NO"){
-            $this->response[]=$this->line;
-            $this->line = fgets($this->fp, 1024);
-        }
-        if(substr($this->line,0,2) == "OK")
-            return true;
-        else
-            return false;
-    } /* end elseif */
-    elseif($this->token[0][0] == "\""){
-
-        /* I'm going under the _assumption_ that the only function that will get here is the listscripts().
-           I could very well be mistaken here, if I am, this part needs some rework */
-
-        $this->found_script=false;        
-
-        while(substr($this->line,0,2) != "OK" and substr($this->line,0,2) != "NO"){
-            $this->found_script=true;
-            list($this->ltoken, $this->rtoken) = explode(" ", $this->line." ",2);
-               //hmmm, a bug in php, if there is no space on explode line, a warning is generated...
-           
-            if(strcmp(rtrim($this->rtoken), "ACTIVE")==0){
-                $this->response["ACTIVE"] = substr(rtrim($this->ltoken),1,-1);  
-            }
-            else
-                $this->response[] = substr(rtrim($this->ltoken),1,-1);
-            $this->line = fgets($this->fp, 1024);
-        } /* end while */
-        
-        return true;
-        
-    } /* end elseif */
-    else{
-            $this->error = EC_UNKNOWN;
-            $this->error_raw = $this->line;
-            print "<b><i>UNKNOWN ERROR (Please report this line to danellis@rushmore.com to include in future releases): $this->line</i></b><br>";
-            return false;
-    } /* end else */   
-  } /* end get_response() */
-
-  function sieve($host, $port, $user, $pass, $auth="", $auth_types="PLAIN DIGEST-MD5")
-  {
-    $this->host=$host;
-    $this->port=$port;
-    $this->user=$user;
-    $this->pass=$pass;
-    if(!strcmp($auth, ""))             /* If there is no auth user, we deem the user itself to be the auth'd user */
-        $this->auth = $this->user;
-    else
-        $this->auth = $auth;
-    $this->auth_types=$auth_types;     /* Allowed authentication types */
-    $this->fp=0;
-    $this->line="";
-    $this->retval="";
-    $this->tmpfile="";
-    $this->fh=0;
-    $this->len=0;
-    $this->capabilities="";
-    $this->loggedin=false;
-    $this->error= "";
-    $this->error_raw="";
-  }
-
-  function parse_for_quotes($string)
-  {
-      /* This function tokenizes a line of input by quote marks and returns them as an array */
-
-      $start = -1;
-      $index = 0;
-
-      for($ptr = 0; $ptr < strlen($string); $ptr++){
-          if($string[$ptr] == '"' and $string[$ptr] != '\\'){
-              if($start == -1){
-                  $start = $ptr;
-              } /* end if */
-              else{
-                  $token[$index++] = substr($string, $start + 1, $ptr - $start - 1);
-                  $found = true;
-                  $start = -1;
-              } /* end else */
-
-          } /* end if */  
-
-      } /* end for */
-
-      if(isset($token))
-          return $token;
-      else
-          return false;
-  } /* end function */            
-
-  function status($string)
-  {
-      //this should probably be replaced by a smarter parser.
-
-      /*  Need to remove this and all dependencies from the class */
-
-      switch (substr($string, 0,2)){
-          case "NO":
-              return F_NO;             //there should be some function to extract the error code from this line
-                                       //NO ("quota") "You are oly allowed x number of scripts"
-              break;
-          case "OK":
-              return F_OK;
-              break;
-          default:
-              switch ($string[0]){
-                  case "{":
-                      //do parse here for {}'s  maybe modify parse_for_quotes to handle any parse delimiter?
-                      return F_HEAD;
-                      break;
-                  default:
-                      return F_DATA;
-                      break;
-              } /* end switch */
-        } /* end switch */
-  } /* end status() */
-
-  function sieve_login()
-  {
-
-    $this->fp=fsockopen($this->host,$this->port);
-    if($this->fp == false)
-        return false;
-    $this->line=fgets($this->fp,1024);
-
-    //Hack for older versions of Sieve Server.  They do not respond with the Cyrus v2. standard
-    //response.  They repsond as follows: "Cyrus timsieved v1.0.0" "SASL={PLAIN,........}"
-    //So, if we see IMLEMENTATION in the first line, then we are done.
-
-    if(ereg("IMPLEMENTATION",$this->line))
-    {
-      //we're on the Cyrus V2 sieve server
-      while(sieve::status($this->line) == F_DATA){
-
-          $this->item = sieve::parse_for_quotes($this->line);
-
-          if(strcmp($this->item[0], "IMPLEMENTATION") == 0)
-              $this->capabilities["implementation"] = $this->item[1];
-        
-          elseif(strcmp($this->item[0], "SIEVE") == 0 or strcmp($this->item[0], "SASL") == 0){
-
-              if(strcmp($this->item[0], "SIEVE") == 0)
-                  $this->cap_type="modules";
-              else
-                  $this->cap_type="auth";            
-
-              $this->modules = split(" ", $this->item[1]);
-              if(is_array($this->modules)){
-                  foreach($this->modules as $this->module)
-                      $this->capabilities[$this->cap_type][$this->module]=true;
-              } /* end if */
-              elseif(is_string($this->modules))
-                  $this->capabilites[$this->cap_type][$this->modules]=true;
-          }    
-          else{ 
-              $this->capabilities["unknown"][]=$this->line;
-          }    
-      $this->line=fgets($this->fp,1024);
-
-       }// end while
-    }
-    else
-    {
-        //we're on the older Cyrus V1. server  
-        //this version does not support module reporting.  We only have auth types.
-        $this->cap_type="auth";
-       
-        //break apart at the "Cyrus timsieve...." "SASL={......}"
-        $this->item = sieve::parse_for_quotes($this->line);
-
-        $this->capabilities["implementation"] = $this->item[0];
-
-        //we should have "SASL={..........}" now.  Break out the {xx,yyy,zzzz}
-        $this->modules = substr($this->item[1], strpos($this->item[1], "{"),strlen($this->item[1])-1);
-
-        //then split again at the ", " stuff.
-        $this->modules = split($this->modules, ", ");
-        //fill up our $this->modules property
-        if(is_array($this->modules)){
-            foreach($this->modules as $this->module)
-                $this->capabilities[$this->cap_type][$this->module]=true;
-        } /* end if */
-        elseif(is_string($this->modules))
-            $this->capabilites[$this->cap_type][$this->module]=true;
-    }
-
-
-
-
-    if(sieve::status($this->line) == F_NO){            //here we should do some returning of error codes?
-        $this->error=EC_UNKNOWN;
-        $this->error_raw = "Server not allowing connections.";
-        return false;
-    }
-
-    /* decision login to decide what type of authentication to use... */
-
-     /* Loop through each allowed authentication type and see if the server allows the type */
-     foreach(split(" ",$this->auth_types) as $auth_type)
-     {
-        if ($this->capabilities["auth"][$auth_type])
-        {
-            /* We found an auth type that is allowed. */
-            $this->auth_in_use = $auth_type;
-            break;
-        }
-     }
-    
-    /* Fill error message if no auth types are present */
-    if (!isset($this->capabilities["auth"])){
-        $this->error=EC_UNKNOWN;
-       $this->error_raw = "No authentication methods found - please check your sieve setup for missing sasl modules";
-       return false;
-    }
-
-     /* call our authentication program */  
-    return sieve::authenticate();
-
-  }
-
-  function sieve_logout()
-  {
-    if($this->loggedin==false)
-        return false;
-
-    fputs($this->fp,"LOGOUT\r\n");
-    fclose($this->fp);
-    $this->loggedin=false;
-    return true;
-  }
-
-  function sieve_sendscript($scriptname, $script)
-  {
-    if($this->loggedin==false)
-        return false;
-    $this->script=stripslashes($script);
-    $len=strlen($this->script);
-    fputs($this->fp, "PUTSCRIPT \"$scriptname\" {".$len."+}\r\n");
-    fputs($this->fp, "$this->script\r\n");
-  
-    return sieve::get_response();
-
-  }  
-  
-  //it appears the timsieved does not honor the NUMBER type.  see lex.c in timsieved src.
-  //don't expect this function to work yet.  I might have messed something up here, too.
-  function sieve_havespace($scriptname, $scriptsize)
-  {
-    if($this->loggedin==false)
-        return false;
-    fputs($this->fp, "HAVESPACE \"$scriptname\" $scriptsize\r\n");
-    return sieve::get_response();
-
-  }  
-
-  function sieve_setactivescript($scriptname)
-  {
-    if($this->loggedin==false)
-        return false;
-
-    fputs($this->fp, "SETACTIVE \"$scriptname\"\r\n");   
-    return sieve::get_response();
-
-  }
-  
-  function sieve_getscript($scriptname)
-  {
-    unset($this->script);
-    if($this->loggedin==false)
-        return false;
-
-    fputs($this->fp, "GETSCRIPT \"$scriptname\"\r\n");
-    return sieve::get_response();
-   
-  }
-
-
-  function sieve_deletescript($scriptname)
-  {
-    if($this->loggedin==false)
-        return false;
-
-    fputs($this->fp, "DELETESCRIPT \"$scriptname\"\r\n");    
-
-    return sieve::get_response();
-  }
-
-  
-  function sieve_listscripts() 
-   { 
-     fputs($this->fp, "LISTSCRIPTS\r\n"); 
-     sieve::get_response();            //should always return true, even if there are no scripts...
-     if(isset($this->found_script) and $this->found_script)
-         return true;
-     else{
-         $this->error=EC_NOSCRIPTS;    //sieve::getresponse has no way of telling wether a script was found...
-         $this->error_raw="No scripts found for this account.";
-         return false;
-     }
-   }
-
-  function sieve_alive()
-  {
-      if(!isset($this->fp) or $this->fp==0){
-          $this->error = EC_NOT_LOGGED_IN;
-          return false;
-      }
-      elseif(feof($this->fp)){                 
-          $this->error = EC_NOT_LOGGED_IN;
-          return false;
-      }
-      else
-          return true;
-  }
-
-  function authenticate()
-  {
-
-    switch ($this->auth_in_use) {
-    
-        case "PLAIN":
-            $auth=base64_encode("$this->user\0$this->auth\0$this->pass");
-   
-            $this->len=strlen($auth);                  
-            fputs($this->fp, "AUTHENTICATE \"PLAIN\" {".$this->len."+}\r\n");
-            fputs($this->fp, "$auth\r\n");
-
-            $this->line=fgets($this->fp,1024);         
-            while(sieve::status($this->line) == F_DATA)
-               $this->line=fgets($this->fp,1024);
-
-             if(sieve::status($this->line) == F_NO)
-               return false;
-             $this->loggedin=true;
-               return true;    
-             break;
-
-        default:
-            return false;
-            break;
-
-    }//end switch
-
-
-  }//end authenticate()
-
-
-}
-
-
-
-?>
diff --git a/include/sieve/class_My_Parser.inc b/include/sieve/class_My_Parser.inc
new file mode 100644 (file)
index 0000000..ac99301
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+
+/* String used to indent the different code blocks */
+define("SIEVE_INDENT_TAB","  ");
+
+
+/* This class is inherited from the original 'Parser'
+ *  class written by Heiko Hund
+ */
+class My_Parser extends Parser 
+{
+       var $parent = NULL;
+       var $registeredExtensions_ =array();
+
+       function My_Parser($parent)
+       {
+               $this->registeredExtensions_ = array();         
+               $this->parent = $parent;
+       }
+
+       function execute()
+       {
+               $ret = $this->dumpParseTree();
+               return($ret);
+       }
+       
+
+       /* Check if there are errors, collect them and return them */
+       function check()
+       {
+               return($this->tree_->check());
+       }
+       
+
+       /* Initiate parser, but use some other 
+     *  classes, that are rewritten.
+     */
+       function parse($script) 
+       {
+               $script = preg_replace("/^###GOSA/","",$script);
+
+               $this->registeredExtensions_ = array();
+        $this->status_text = "incomplete";
+        $this->script_ = $script;
+        $this->tree_ = new My_Tree(@Scanner::scriptStart(),$this);
+        $this->tree_->setDumpFunc(array(&$this, 'dumpToken_'));
+        $this->scanner_ = new My_Scanner($this->script_);
+        $this->scanner_->setCommentFunc(array($this, 'comment_'));
+
+        if ($this->commands_($this->tree_->getRoot()) &&
+            $this->scanner_->nextTokenIs('script-end'))
+        {
+                       $this->scanner_->nextToken(); 
+            return $this->success_('success');
+        }
+
+        return $this->status_;
+       }
+
+       
+       function get_sieve_script()
+       {
+               return("###GOSA\n".$this->tree_->get_sieve_script());
+       }               
+
+       
+       function save_object()
+       {
+               $this->tree_->save_object();
+       }
+
+
+       function dumpParseTree()
+       {
+               return $this->tree_->execute();
+       }
+}
+?>
diff --git a/include/sieve/class_My_Scanner.inc b/include/sieve/class_My_Scanner.inc
new file mode 100644 (file)
index 0000000..878927a
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+
+class My_Scanner extends Scanner 
+{
+       function tokenize(&$script)
+       {
+               $pos = 0;
+               $line = 1;
+               $script_length = mb_strlen($script);
+
+               while ($pos < $script_length)
+               {
+                       foreach ($this->token_match_ as $class => $regex)
+                       {
+                               if (preg_match('/^'. $regex .'/', mb_substr($script, $pos), $match))
+                               {
+                                       $length = mb_strlen($match[0]);
+
+                                       if ($class != 'whitespace')
+                                       {
+                                               array_push($this->tokens_, array(
+                                                       'class' => $class,
+                                                       'text'  => chop(mb_substr($script, $pos, $length)),
+                                                       'line'  => $line,
+                                               ));
+                                       }
+                                       if ($class == 'unknown')
+                                       {
+                                               return;
+                                       }
+
+                                       $pos += $length;
+                                       $line += mb_substr_count($match[0], "\n");
+                                       break;
+                               }
+                       }
+               }
+               array_push($this->tokens_, array(
+                       'class' => 'script-end',
+                       'text'  => 'script-end',
+                       'line'  => $line,
+               ));
+       }
+
+       var $commentFn_ = null;
+       var $tokenPos_ = 0;
+       var $tokens_ = array();
+       var $token_match_ = array (
+               'left-bracket'   =>  '\[',
+               'right-bracket'  =>  '\]',
+               'block-start'    =>  '\{',
+               'block-end'      =>  '\}',
+               'left-parant'    =>  '\(',
+               'right-parant'   =>  '\)',
+               'comma'          =>  ',',
+               'semicolon'      =>  ';',
+               'whitespace'     =>  '[ \r\n\t]+',
+               'tag'            =>  ':[[:alpha:]_][[:alnum:]_]*(?=\b)',
+               'quoted-string'  =>  '"(?:\\[\\"]|[^\x00"])*"',
+               'number'         =>  '[[:digit:]]+(?:[KMG])?(?=\b)',
+               'comment'        =>  '(?:\/\*(?:[^\*]|\*(?=[^\/]))*\*\/|#[^\r\n]*\r?\n)',
+#              'multi-line'     =>  'text:[ \t]*(?:#[^\r\n]*)?\r?\n(\.[^\r\n]+\r?\n|[^\.]*\r?\n)*\.\r?\n',
+               'multi-line'     =>  'text:[^;]*',
+               'identifier'     =>  '[[:alpha:]_][[:alnum:]_]*(?=\b)',
+               'unknown token'  =>  '[^ \r\n\t]+'
+       );
+}
+
+?>
diff --git a/include/sieve/class_My_Tree.inc b/include/sieve/class_My_Tree.inc
new file mode 100644 (file)
index 0000000..99a076f
--- /dev/null
@@ -0,0 +1,782 @@
+<?php
+
+/* This class is inherited from the original 'Tree'
+ *  class written by Heiko Hund.
+ * It is partly rewritten to create a useable html interface 
+ *  for each single sieve token. 
+ * This gives us the ability to edit existing sieve filters. 
+ */
+class My_Tree extends Tree
+{
+  var $dumpFn_;
+  var $dump_;
+
+  var $mode_stack = array();
+  var $pap             = array();
+  var $parent = NULL;
+
+  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()
+  {
+    /**************
+     * 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(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>";
+        }
+      }
+    }
+    
+    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($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; $i<count($childs); ++$i)
+      {
+        $c_last = false;
+        if ($i+1 == count($childs))
+        {
+          $c_last = true;
+        }
+        $this->doDump_($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 "<font color='red'>Missing : ".$class_name."</font>"."<br>";
+    }
+  }
+
+  function save_object()
+  {
+    reset($this->pap);
+    foreach($this->pap as $key => $obj){
+
+      if(in_array(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){
+      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","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($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($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(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($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($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($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 = 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(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);
+  }
+
+
+  /* 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:
+?>
diff --git a/include/sieve/class_parser.inc b/include/sieve/class_parser.inc
new file mode 100644 (file)
index 0000000..3458952
--- /dev/null
@@ -0,0 +1,365 @@
+<?php
+
+#include_once 'class.tree.php';
+#include_once 'class.scanner.php';
+#include_once 'class.semantics.php';
+
+class Parser
+{
+       var $scanner_;
+       var $script_;
+       var $tree_;
+       var $status_;
+       var $registeredExtensions_;
+
+       var $status_text;
+
+       function parse($script)
+       {
+               $this->registeredExtensions_ = array();
+               $this->status_text = "incomplete";
+
+               $this->script_ = $script;
+               $this->tree_ = new 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 dumpParseTree()
+       {
+               return $this->tree_->dump();
+       }
+
+       function dumpToken_(&$token)
+       {
+               if (is_array($token))
+               {
+                       $str = "<" . $token['text'] . "> ";
+                       foreach ($token as $k => $v)
+                       {
+                               $str .= " $k:$v";
+                       }
+                       return $str;
+               }
+
+               return strval($token);
+       }
+
+       function getPrevTokenText_($parent_id)
+       {
+               $childs = $this->tree_->getChilds($parent_id);
+
+               for ($i=count($childs); $i>0; --$i)
+               {
+                       $prev = $this->tree_->getNode($childs[$i-1]);
+
+                       if (in_array($prev['text'], array('{', '(', ',')))
+                       {
+                               // use command owning a block or list
+                               $prev = $this->tree_->getNode($parent_id);
+                       }
+
+                       if ($prev['class'] != 'comment')
+                       {
+                               return $prev['text'];
+                       }
+               }
+
+               $prev = $this->tree_->getNode($parent_id);
+               return $prev['text'];
+       }
+
+       function getSemantics_($token_text)
+       {
+               $semantics = new Semantics($token_text);
+               $semantics->setExtensionFuncs(array(&$this, 'registerExtension_'), array(&$this, 'isExtensionRegistered_'));
+               return $semantics;
+       }
+
+       function registerExtension_($extension)
+       {
+               array_push($this->registeredExtensions_, str_replace('"', '', $extension));
+       }
+
+       function isExtensionRegistered_($extension)
+       {
+               return (in_array($extension, $this->registeredExtensions_) ? true : false);
+       }
+
+       function success_($text = null)
+       {
+               if ($text != null)
+               {
+                       $this->status_text = $text;
+               }
+
+               return $this->status_ = true;
+       }
+
+       function error_($text, $token = null)
+       {
+               if ($token != null)
+               {
+                       $text = 'line '. $token['line'] .': '. $token['class'] . " where $text expected near ". $token['text'];
+               }
+
+               $this->status_text = $text;
+               return $this->status_ = false;
+       }
+
+       function done_()
+       {
+               $this->status_ = true;
+               return false;
+       }
+
+       /*******************************************************************************
+        * methods for recursive descent start below
+        */
+
+       function comment_($token)
+       {
+               $this->tree_->addChild($token);
+       }
+
+       function commands_($parent_id)
+       {
+               while ($this->command_($parent_id))
+                       ;
+
+               return $this->status_;
+       }
+
+       function command_($parent_id)
+       {
+               if (!$this->scanner_->nextTokenIs('identifier'))
+               {
+                       if ($this->scanner_->nextTokenIs(array('block-end', 'script-end')))
+                       {
+                               return $this->done_();
+                       }
+                       return $this->error_('identifier', $this->scanner_->peekNextToken());
+               }
+
+               // Get and check a command token
+               $token = $this->scanner_->nextToken();
+               $semantics = $this->getSemantics_($token['text']);
+               if (!$semantics->validCommand($this->getPrevTokenText_($parent_id), $token['line']))
+               {
+                       return $this->error_($semantics->message);
+               }
+
+               // Process eventual arguments
+               $this_node = $this->tree_->addChildTo($parent_id, $token);
+               if ($this->arguments_($this_node, $semantics) == false)
+               {
+                       return false;
+               }
+
+               $token = $this->scanner_->nextToken();
+               if ($token['class'] != 'semicolon')
+               {
+                       if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
+                       {
+                               return $this->error_($semantics->message);
+                       }
+
+                       if ($token['class'] == 'block-start')
+                       {
+                               $this->tree_->addChildTo($this_node, $token);
+                               $ret = $this->block_($this_node, $semantics);
+                               return $ret;
+                       }
+
+                       return $this->error_('semicolon', $token);
+               }
+
+               $this->tree_->addChildTo($this_node, $token);
+               return $this->success_();
+       }
+
+       function arguments_($parent_id, &$semantics)
+       {
+               while ($this->argument_($parent_id, &$semantics))
+                       ;
+
+               if ($this->status_ == true)
+               {
+                       $this->testlist_($parent_id, $semantics);
+               }
+
+               return $this->status_;
+       }
+
+       function argument_($parent_id, &$semantics)
+       {
+               if ($this->scanner_->nextTokenIs(array('number', 'tag')))
+               {
+                       // Check if semantics allow a number or tag
+                       $token = $this->scanner_->nextToken();
+                       if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
+                       {
+                               return $this->error_($semantics->message);
+                       }
+
+                       $this->tree_->addChildTo($parent_id, $token);
+                       return $this->success_();
+               }
+
+               return $this->stringlist_($parent_id, &$semantics);
+       }
+
+       function stringlist_($parent_id, &$semantics)
+       {
+               if (!$this->scanner_->nextTokenIs('left-bracket'))
+               {
+                       return $this->string_($parent_id, &$semantics);
+               }
+
+               $token = $this->scanner_->nextToken();
+               if (!$semantics->startStringList($token['line']))
+               {
+                       return $this->error_($semantics->message);
+               }
+               $this->tree_->addChildTo($parent_id, $token);
+
+               while ($token['class'] != 'right-bracket')
+               {
+                       if (!$this->string_($parent_id, &$semantics))
+                       {
+                               return $this->status_;
+                       }
+
+                       $token = $this->scanner_->nextToken();
+
+                       if ($token['class'] != 'comma' && $token['class'] != 'right-bracket')
+                       {
+                               return $this->error_('comma or closing bracket', $token);
+                       }
+
+                       $this->tree_->addChildTo($parent_id, $token);
+               }
+
+               $semantics->endStringList();
+               return $this->success_();
+       }
+
+       function string_($parent_id, &$semantics)
+       {
+               if (!$this->scanner_->nextTokenIs(array('quoted-string', 'multi-line')))
+               {
+                       return $this->done_();
+               }
+
+               $token = $this->scanner_->nextToken();
+               if (!$semantics->validToken('string', $token['text'], $token['line']))
+               {
+                       return $this->error_($semantics->message);
+               }
+
+               $this->tree_->addChildTo($parent_id, $token);
+               return $this->success_();
+       }
+
+       function testlist_($parent_id, &$semantics)
+       {
+               if (!$this->scanner_->nextTokenIs('left-parant'))
+               {
+                       return $this->test_($parent_id, $semantics);
+               }
+
+               $token = $this->scanner_->nextToken();
+               if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
+               {
+                       return $this->error_($semantics->message);
+               }
+               $this->tree_->addChildTo($parent_id, $token);
+
+               while ($token['class'] != 'right-parant')
+               {
+                       if (!$this->test_($parent_id, $semantics))
+                       {
+                               return $this->status_;
+                       }
+
+                       $token = $this->scanner_->nextToken();
+
+                       if ($token['class'] != 'comma' && $token['class'] != 'right-parant')
+                       {
+                               return $this->error_('comma or closing paranthesis', $token);
+                       }
+
+                       $this->tree_->addChildTo($parent_id, $token);
+               }
+
+               return $this->success_();
+       }
+
+       function test_($parent_id, &$semantics)
+       {
+               if (!$this->scanner_->nextTokenIs('identifier'))
+               {
+                       // There is no test
+                       return $this->done_();
+               }
+
+               // Check if semantics allow an identifier
+               $token = $this->scanner_->nextToken();
+               if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
+               {
+                       return $this->error_($semantics->message);
+               }
+
+               // Get semantics for this test command
+               $this_semantics = $this->getSemantics_($token['text']);
+               if (!$this_semantics->validCommand($this->getPrevTokenText_($parent_id), $token['line']))
+               {
+                       return $this->error_($this_semantics->message);
+               }
+
+               $this_node = $this->tree_->addChildTo($parent_id, $token);
+
+               // Consume eventual argument tokens
+               if (!$this->arguments_($this_node, $this_semantics))
+               {
+                       return false;
+               }
+
+               // Check if arguments were all there
+               $token = $this->scanner_->peekNextToken();
+               if (!$this_semantics->done($token['class'], $token['text'], $token['line']))
+               {
+                       return $this->error_($this_semantics->message);
+               }
+
+               return true;
+       }
+
+       function block_($parent_id, &$semantics)
+       {
+               if ($this->commands_($parent_id, $semantics))
+               {
+                       $token = $this->scanner_->nextToken();
+       
+                       if ($token['class'] != 'block-end')
+                       {
+                               return $this->error_('closing curly brace', $token);
+                       }
+       
+                       $this->tree_->addChildTo($parent_id, $token);
+                       return $this->success_();
+               }
+               return $this->status_;
+       }
+}
+
+?>
diff --git a/include/sieve/class_scanner.inc b/include/sieve/class_scanner.inc
new file mode 100644 (file)
index 0000000..3e22bb1
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+
+class Scanner
+{
+       function Scanner(&$script)
+       {
+               $this->_construct($script);
+       }
+
+       function _construct(&$script)
+       {
+               if ($script === null)
+               {
+                       return;
+               }
+
+               $this->tokenize($script);
+       }
+
+       function setCommentFunc($callback)
+       {
+               if ($callback == null || is_callable($callback))
+               {
+                       $this->commentFn_ = $callback;
+               }
+       }
+
+       function tokenize(&$script)
+       {
+               $pos = 0;
+               $line = 1;
+               $script_length = mb_strlen($script);
+
+               while ($pos < $script_length)
+               {
+                       foreach ($this->token_match_ as $class => $regex)
+                       {
+                               if (preg_match('/^'. $regex .'/', mb_substr($script, $pos), $match))
+                               {
+                                       $length = mb_strlen($match[0]);
+
+                                       if ($class != 'whitespace')
+                                       {
+                                               array_push($this->tokens_, array(
+                                                       'class' => $class,
+                                                       'text'  => chop(mb_substr($script, $pos, $length)),
+                                                       'line'  => $line,
+                                               ));
+                                       }
+                                       if ($class == 'unknown')
+                                       {
+                                               return;
+                                       }
+
+                                       $pos += $length;
+                                       $line += mb_substr_count($match[0], "\n");
+                                       break;
+                               }
+                       }
+               }
+
+               array_push($this->tokens_, array(
+                       'class' => 'script-end',
+                       'text'  => 'script-end',
+                       'line'  => $line,
+               ));
+       }
+
+       function nextTokenIs($class)
+       {
+               $offset = 0;
+               do
+               {
+                       $next = $this->tokens_[$this->tokenPos_ + $offset++]['class'];
+               }
+               while ($next == 'comment');
+
+               if (is_array($class))
+               {
+                       return in_array($next, $class);
+               }
+               else if (is_string($class))
+               {
+                       return (strcmp($next, $class) == 0);
+               }
+               return false;
+       }
+
+       function peekNextToken()
+       {
+               return $this->tokens_[$this->tokenPos_];
+       }
+
+       function nextToken()
+       {
+               $token = $this->tokens_[$this->tokenPos_++];
+               while ($token['class'] == 'comment')
+               {
+                       if ($this->commentFn_ != null)
+                       {
+                               call_user_func($this->commentFn_, $token);
+                       }
+                       $token = $this->tokens_[$this->tokenPos_++];
+               }
+               return $token;
+       }
+
+       function scriptStart()
+       {
+               return array(
+                       'class' => 'script-start',
+                       'text'  => 'script-start',
+                       'line'  => 1,
+               );
+       }
+
+       var $commentFn_ = null;
+       var $tokenPos_ = 0;
+       var $tokens_ = array();
+       var $token_match_ = array (
+               'left-bracket'   =>  '\[',
+               'right-bracket'  =>  '\]',
+               'block-start'    =>  '\{',
+               'block-end'      =>  '\}',
+               'left-parant'    =>  '\(',
+               'right-parant'   =>  '\)',
+               'comma'          =>  ',',
+               'semicolon'      =>  ';',
+               'whitespace'     =>  '[ \r\n\t]+',
+               'tag'            =>  ':[[:alpha:]_][[:alnum:]_]*(?=\b)',
+               'quoted-string'  =>  '"(?:\\[\\"]|[^\x00"])*"',
+               'number'         =>  '[[:digit:]]+(?:[KMG])?(?=\b)',
+               'comment'        =>  '(?:\/\*(?:[^\*]|\*(?=[^\/]))*\*\/|#[^\r\n]*\r?\n)',
+               'multi-line'     =>  'text:[ \t]*(?:#[^\r\n]*)?\r?\n(\.[^\r\n]+\r?\n|[^\.]*\r?\n)*\.\r?\n',
+               'identifier'     =>  '[[:alpha:]_][[:alnum:]_]*(?=\b)',
+               'unknown token'  =>  '[^ \r\n\t]+'
+       );
+}
+
+?>
\ No newline at end of file
diff --git a/include/sieve/class_semantics.inc b/include/sieve/class_semantics.inc
new file mode 100644 (file)
index 0000000..1c00051
--- /dev/null
@@ -0,0 +1,613 @@
+<?php
+
+class Semantics
+{
+       var $registerExtensionFn_;
+       var $isExtensionRegisteredFn_;
+
+       var $command_;
+       var $comparator_;
+       var $matchType_;
+       var $s_;
+       var $unknown;
+       var $message;
+       var $nonTestCommands_ = '(require|if|elsif|else|reject|fileinto|redirect|stop|keep|discard|mark|unmark|setflag|addflag|removeflag)';
+       var $testsValidAfter_ = '(if|elsif|anyof|allof|not)';
+       var $testCommands_ = '(address|envelope|header|size|allof|anyof|exists|not|true|false)';
+       var $requireStrings_ = '(envelope|fileinto|reject|vacation|relational|subaddress|regex|imapflags|copy)';
+
+       function Semantics($command)
+       {
+               $this->command_ = $command;
+               $this->unknown = false;
+               switch ($command)
+               {
+
+               /********************
+                * control commands
+                */
+               case 'require':
+                       /* require <capabilities: string-list> */
+                       $this->s_ = array(
+                               'valid_after' => '(script-start|require)',
+                               'arguments' => array(
+                                       array('class' => 'string', 'list' => true, 'name' => 'require-string', 'occurrences' => '1', 'call' => 'setRequire_', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => '"'. $this->requireStrings_ .'"'),
+                                               array('occurrences' => '+', 'regex' => '"comparator-i;(octet|ascii-casemap|ascii-numeric)"')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'if':
+                       /* if <test> <block> */
+                       $this->s_ = array(
+                               'valid_after' => str_replace('(', '(script-start|', $this->nonTestCommands_),
+                               'arguments' => array(
+                                       array('class' => 'identifier', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => $this->testCommands_, 'name' => 'test')
+                                       )),
+                                       array('class' => 'block-start', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => '{', 'name' => 'block')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'elsif':
+                       /* elsif <test> <block> */
+                       $this->s_ = array(
+                               'valid_after' => '(if|elsif)',
+                               'arguments' => array(
+                                       array('class' => 'identifier', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => $this->testCommands_, 'name' => 'test')
+                                       )),
+                                       array('class' => 'block-start', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => '{', 'name' => 'block')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'else':
+                       /* else <block> */
+                       $this->s_ = array(
+                               'valid_after' => '(if|elsif)',
+                               'arguments' => array(
+                                       array('class' => 'block-start', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => '{', 'name' => 'block')
+                                       ))
+                               )
+                       );
+                       break;
+
+
+               /*******************
+                * action commands
+                */
+               case 'discard':
+               case 'keep':
+               case 'stop':
+                       /* discard / keep / stop */
+                       $this->s_ = array(
+                               'valid_after' => str_replace('(', '(script-start|', $this->nonTestCommands_)
+                       );
+                       break;
+
+               case 'fileinto':
+                       /* fileinto [":copy"] <folder: string> */
+                       $this->s_ = array(
+                               'requires' => 'fileinto',
+                               'valid_after' => $this->nonTestCommands_,
+                               'arguments' => array(
+                                       array('class' => 'tag', 'occurrences' => '?', 'values' => array(
+                                               array('occurrences' => '?', 'regex' => ':copy', 'requires' => 'copy', 'name' => 'copy')
+                                       )),
+                                       array('class' => 'string', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => '".*"', 'name' => 'folder')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'mark':
+               case 'unmark':
+                       /* mark / unmark */
+                       $this->s_ = array(
+                               'requires' => 'imapflags',
+                               'valid_after' => $this->nonTestCommands_
+                       );
+                       break;
+
+               case 'redirect':
+                       /* redirect [":copy"] <address: string> */
+                       $this->s_ = array(
+                               'valid_after' => str_replace('(', '(script-start|', $this->nonTestCommands_),
+                               'arguments' => array(
+                                       array('class' => 'tag', 'occurrences' => '?', 'values' => array(
+                                               array('occurrences' => '?', 'regex' => ':copy', 'requires' => 'copy', 'name' => 'size-type')
+                                       )),
+                                       array('class' => 'string', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => '".*"', 'name' => 'address')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'reject':
+                       /* reject <reason: string> */
+                       $this->s_ = array(
+                               'requires' => 'reject',
+                               'valid_after' => $this->nonTestCommands_,
+                               'arguments' => array(
+                                       array('class' => 'string', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => '("|).*("|)', 'name' => 'reason')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'setflag':
+               case 'addflag':
+               case 'removeflag':
+                       /* setflag <flag-list: string-list> */
+                       /* addflag <flag-list: string-list> */
+                       /* removeflag <flag-list: string-list> */
+                       $this->s_ = array(
+                               'requires' => 'imapflags',
+                               'valid_after' =>$this->nonTestCommands_,
+                               'arguments' => array(
+                                       array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => '".*"', 'name' => 'key')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'vacation':
+                       /* vacation [":days" number] [":addresses" string-list] [":subject" string] [":mime"] <reason: string> */
+                       $this->s_ = array(
+                               'requires' => 'vacation',
+                               'valid_after' => $this->nonTestCommands_,
+                               'arguments' => array(
+                                       array('class' => 'tag', 'occurrences' => '*', 'values' => array(
+                                               array('occurrences' => '?', 'regex' => ':days', 'name' => 'days',
+                                                       'add' => array(
+                                                               array('class' => 'number', 'occurrences' => '1', 'values' => array(
+                                                                       array('occurrences' => '1', 'regex' => '.*', 'name' => 'period')
+                                                               ))
+                                                       )
+                                               ),
+                                               array('occurrences' => '?', 'regex' => ':addresses', 'name' => 'addresses',
+                                                       'add' => array(
+                                                               array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array(
+                                                                       array('occurrences' => '+', 'regex' => '".*"', 'name' => 'address')
+                                                               ))
+                                                       )
+                                               ),
+                                               array('occurrences' => '?', 'regex' => ':subject', 'name' => 'subject',
+                                                       'add' => array(
+                                                               array('class' => 'string', 'occurrences' => '1', 'values' => array(
+                                                                       array('occurrences' => '1', 'regex' => '".*"', 'name' => 'subject')
+                                                               ))
+                                                       )
+                                               ),
+                                               array('occurrences' => '?', 'regex' => ':mime', 'name' => 'mime')
+                                       )),
+                                       array('class' => 'string', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => '.*', 'name' => 'reason')
+                                       ))
+                               )
+                       );
+                       break;
+
+
+               /*****************
+                * test commands
+                */
+               case 'address':
+                       /* address [address-part: tag] [comparator: tag] [match-type: tag] <header-list: string-list> <key-list: string-list> */
+                       $this->s_ = array(
+                               'valid_after' => $this->testsValidAfter_,
+                               'arguments' => array(
+                                       array('class' => 'tag', 'occurrences' => '*', 'post-call' => 'checkTags_', 'values' => array(
+                                               array('occurrences' => '?', 'regex' => ':(is|contains|matches|count|value|regex)', 'call' => 'setMatchType_', 'name' => 'match-type'),
+                                               array('occurrences' => '?', 'regex' => ':(all|localpart|domain|user|detail)', 'call' => 'checkAddrPart_', 'name' => 'address-part'),
+                                               array('occurrences' => '?', 'regex' => ':comparator', 'name' => 'comparator',
+                                                       'add' => array(
+                                                               array('class' => 'string', 'occurrences' => '1', 'call' => 'setComparator_', 'values' => array(
+                                                                       array('occurrences' => '1', 'regex' => '"i;(octet|ascii-casemap)"', 'name' => 'comparator-string'),
+                                                                       array('occurrences' => '1', 'regex' => '"i;ascii-numeric"', 'requires' => 'comparator-i;ascii-numeric', 'name' => 'comparator-string')
+                                                               ))
+                                                       )
+                                               )
+                                       )),
+                                       array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => '".*"', 'name' => 'header')
+                                       )),
+                                       array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => '".*"', 'name' => 'key')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'allof':
+               case 'anyof':
+                       /* allof <tests: test-list>
+                          anyof <tests: test-list> */
+                       $this->s_ = array(
+                               'valid_after' => $this->testsValidAfter_,
+                               'arguments' => array(
+                                       array('class' => 'left-parant', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => '\(', 'name' => 'test-list')
+                                       )),
+                                       array('class' => 'identifier', 'occurrences' => '+', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => $this->testCommands_, 'name' => 'test')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'envelope':
+                       /* envelope [address-part: tag] [comparator: tag] [match-type: tag] <envelope-part: string-list> <key-list: string-list> */
+                       $this->s_ = array(
+                               'requires' => 'envelope',
+                               'valid_after' => $this->testsValidAfter_,
+                               'arguments' => array(
+                                       array('class' => 'tag', 'occurrences' => '*', 'post-call' => 'checkTags_', 'values' => array(
+                                               array('occurrences' => '?', 'regex' => ':(is|contains|matches|count|value|regex)', 'call' => 'setMatchType_', 'name' => 'match-type'),
+                                               array('occurrences' => '?', 'regex' => ':(all|localpart|domain|user|detail)', 'call' => 'checkAddrPart_', 'name' => 'address-part'),
+                                               array('occurrences' => '?', 'regex' => ':comparator', 'name' => 'comparator',
+                                                       'add' => array(
+                                                               array('class' => 'string', 'occurrences' => '1', 'call' => 'setComparator_', 'values' => array(
+                                                                       array('occurrences' => '1', 'regex' => '"i;(octet|ascii-casemap)"', 'name' => 'comparator-string'),
+                                                                       array('occurrences' => '1', 'regex' => '"i;ascii-numeric"', 'requires' => 'comparator-i;ascii-numeric', 'name' => 'comparator-string')
+                                                               ))
+                                                       )
+                                               )
+                                       )),
+                                       array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => '".*"', 'name' => 'envelope-part')
+                                       )),
+                                       array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => '".*"', 'name' => 'key')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'exists':
+                       /* exists <header-names: string-list> */
+                       $this->s_ = array(
+                               'valid_after' => $this->testsValidAfter_,
+                               'arguments' => array(
+                                       array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => '".*"', 'name' => 'header')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'header':
+                       /* header [comparator: tag] [match-type: tag] <header-names: string-list> <key-list: string-list> */
+                       $this->s_ = array(
+                               'valid_after' => $this->testsValidAfter_,
+                               'arguments' => array(
+                                       array('class' => 'tag', 'occurrences' => '*', 'post-call' => 'checkTags_', 'values' => array(
+                                               array('occurrences' => '?', 'regex' => ':(is|contains|matches|count|value|regex)', 'call' => 'setMatchType_', 'name' => 'match-type'),
+                                               array('occurrences' => '?', 'regex' => ':comparator', 'name' => 'comparator',
+                                                       'add' => array(
+                                                               array('class' => 'string', 'occurrences' => '1', 'call' => 'setComparator_', 'values' => array(
+                                                                       array('occurrences' => '1', 'regex' => '"i;(octet|ascii-casemap)"', 'name' => 'comparator-string'),
+                                                                       array('occurrences' => '1', 'regex' => '"i;ascii-numeric"', 'requires' => 'comparator-i;ascii-numeric', 'name' => 'comparator-string')
+                                                               ))
+                                                       )
+                                               )
+                                       )),
+                                       array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => '".*"', 'name' => 'header')
+                                       )),
+                                       array('class' => 'string', 'list' => true, 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '+', 'regex' => '".*"', 'name' => 'key')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'not':
+                       /* not <test> */
+                       $this->s_ = array(
+                               'valid_after' => $this->testsValidAfter_,
+                               'arguments' => array(
+                                       array('class' => 'identifier', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => $this->testCommands_, 'name' => 'test')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'size':
+                       /* size <":over" / ":under"> <limit: number> */
+                       $this->s_ = array(
+                               'valid_after' => $this->testsValidAfter_,
+                               'arguments' => array(
+                                       array('class' => 'tag', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => ':(over|under)', 'name' => 'size-type')
+                                       )),
+                                       array('class' => 'number', 'occurrences' => '1', 'values' => array(
+                                               array('occurrences' => '1', 'regex' => '.*', 'name' => 'limit')
+                                       ))
+                               )
+                       );
+                       break;
+
+               case 'true':
+               case 'false':
+                       /* true / false */
+                       $this->s_ = array(
+                               'valid_after' => $this->testsValidAfter_
+                       );
+                       break;
+
+
+               /********************
+                * unknown commands
+                */
+               default:
+                       $this->unknown = true;
+               }
+       }
+
+       function setExtensionFuncs($setFn, $checkFn)
+       {
+               if (is_callable($setFn) && is_callable($checkFn))
+               {
+                       $this->registerExtensionFn_ = $setFn;
+                       $this->isExtensionRegisteredFn_ = $checkFn;
+               }
+       }
+
+       function setRequire_($extension)
+       {
+               call_user_func($this->registerExtensionFn_, $extension);
+               return true;
+       }
+
+       function wasRequired_($extension)
+       {
+               return call_user_func($this->isExtensionRegisteredFn_, $extension);
+       }
+
+       function setMatchType_($text)
+       {
+               // Do special processing for relational test extension
+               if ($text == ':count' || $text == ':value')
+               {
+                       if (!$this->wasRequired_('relational'))
+                       {
+                               $this->message = 'missing require for match-type '. $text;
+                               return false;
+                       }
+
+                       array_unshift($this->s_['arguments'],
+                               array('class' => 'string', 'occurrences' => '1', 'values' => array(
+                                       array('occurrences' => '1', 'regex' => '"(lt|le|eq|ge|gt|ne)"', 'name' => 'relation-string'),
+                               ))
+                       );
+               }
+               // Do special processing for regex match-type extension
+               else if ($text == ':regex' && !$this->wasRequired_('regex'))
+               {
+                       $this->message = 'missing require for match-type '. $text;
+                       return false;
+               }
+               $this->matchType_ = $text;
+               return true;
+       }
+
+       function setComparator_($text)
+       {
+               $this->comparator_ = $text;
+               return true;
+       }
+
+       function checkAddrPart_($text)
+       {
+               if ($text == ':user' || $text == ':detail')
+               {
+                       if (!$this->wasRequired_('subaddress'))
+                       {
+                               $this->message = 'missing require for tag '. $text;
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       function checkTags_()
+       {
+               if (isset($this->matchType_) &&
+                   $this->matchType_ == ':count' &&
+                   $this->comparator_ != '"i;ascii-numeric"')
+               {
+                       $this->message = 'match-type :count needs comparator i;ascii-numeric';
+                       return false;
+               }
+               return true;
+       }
+
+       function validCommand($prev, $line)
+       {
+               // Check if command is known
+               if ($this->unknown)
+               {
+                       $this->message = 'line '. $line .': unknown command "'. $this->command_ .'"';
+                       return false;
+               }
+
+               // Check if the command needs to be required
+               if (isset($this->s_['requires']) && !$this->wasRequired_($this->s_['requires']))
+               {
+                       $this->message = 'line '. $line .': missing require for command "'. $this->command_ .'"';
+                       return false;
+               }
+
+               // Check if command may appear here
+               if (!ereg($this->s_['valid_after'], $prev))
+               {
+#                      $this->message = 'line '. $line .': "'. $this->command_ .'" may not appear after "'. $prev .'"';
+#                      return false;
+               }
+
+               return true;
+       }
+
+       function validClass_($class, $id)
+       {
+               // Check if command expects any arguments
+               if (!isset($this->s_['arguments']))
+               {
+                       $this->message = $id .' where semicolon expected';
+                       return false;
+               }
+
+               foreach ($this->s_['arguments'] as $arg)
+               {
+                       if ($class == $arg['class'])
+                       {
+                               return true;
+                       }
+
+                       // Is the argument required
+                       if ($arg['occurrences'] != '?' && $arg['occurrences'] != '*')
+                       {
+                               $this->message = $id .' where '. $arg['class'] .' expected';
+                               return false;
+                       }
+
+                       if (isset($arg['post-call']) &&
+                               !call_user_func(array(&$this, $arg['post-call'])))
+                       {
+                               return false;
+                       }
+                       array_shift($this->s_['arguments']);
+               }
+
+               $this->message = 'unexpected '. $id;
+               return false;
+       }
+
+       function startStringList($line)
+       {
+               if (!$this->validClass_('string', 'string'))
+               {
+                       $this->message = 'line '. $line .': '. $this->message;
+                       return false;
+               }
+               else if (!isset($this->s_['arguments'][0]['list']))
+               {
+                       $this->message = 'line '. $line .': '. 'left bracket where '. $this->s_['arguments'][0]['class'] .' expected';
+                       return false;
+               }
+
+               $this->s_['arguments'][0]['occurrences'] = '+';
+               return true;
+       }
+
+       function endStringList()
+       {
+               array_shift($this->s_['arguments']);
+       }
+
+       function validToken($class, &$text, &$line)
+       {
+               $name = $class . ($class != $text ? " $text" : '');
+
+               // Make sure the argument has a valid class
+               if (!$this->validClass_($class, $name))
+               {
+                       $this->message = 'line '. $line .': '. $this->message;
+                       return false;
+               }
+
+               $arg = &$this->s_['arguments'][0];
+               foreach ($arg['values'] as $val)
+               {
+                       if (preg_match('/^'. $val['regex'] .'$/m', $text))
+                       {
+                               // Check if the argument value needs a 'require'
+                               if (isset($val['requires']) && !$this->wasRequired_($val['requires']))
+                               {
+                                       $this->message = 'line '. $line .': missing require for '. $val['name'] .' '. $text;
+                                       return false;
+                               }
+
+                               // Check if a possible value of this argument may occur
+                               if ($val['occurrences'] == '?' || $val['occurrences'] == '1')
+                               {
+                                       $val['occurrences'] = '0';
+                               }
+                               else if ($val['occurrences'] == '+')
+                               {
+                                       $val['occurrences'] = '*';
+                               }
+                               else if ($val['occurrences'] == '0')
+                               {
+                                       $this->message = 'line '. $line .': too many '. $val['name'] .' '. $class .'s near '. $text;
+                                       return false;
+                               }
+
+                               // Call extra processing function if defined
+                               if (isset($val['call']) && !call_user_func(array(&$this, $val['call']), $text) ||
+                                       isset($arg['call']) && !call_user_func(array(&$this, $arg['call']), $text))
+                               {
+                                       $this->message = 'line '. $line .': '. $this->message;
+                                       return false;
+                               }
+
+                               // Set occurrences appropriately
+                               if ($arg['occurrences'] == '?' || $arg['occurrences'] == '1')
+                               {
+                                       array_shift($this->s_['arguments']);
+                               }
+                               else
+                               {
+                                       $arg['occurrences'] = '*';
+                               }
+
+                               // Add argument(s) expected to follow right after this one
+                               if (isset($val['add']))
+                               {
+                                       while ($add_arg = array_pop($val['add']))
+                                       {
+                                               array_unshift($this->s_['arguments'], $add_arg);
+                                       }
+                               }
+
+                               return true;
+                       }
+               }
+
+               $this->message = 'line '. $line .': unexpected '. $name;
+               return false;
+       }
+
+       function done($class, $text, $line)
+       {
+               if (isset($this->s_['arguments']))
+               {
+                       foreach ($this->s_['arguments'] as $arg)
+                       {
+                               if ($arg['occurrences'] == '+' || $arg['occurrences'] == '1')
+                               {
+                                       $this->message = 'line '. $line .': '. $class .' '. $text .' where '. $arg['class'] .' expected';
+                                       return false;
+                               }
+                       }
+               }
+               return true;
+       }
+}
+
+?>
diff --git a/include/sieve/class_sieve.inc b/include/sieve/class_sieve.inc
new file mode 100644 (file)
index 0000000..6fec422
--- /dev/null
@@ -0,0 +1,516 @@
+<?
+
+/*
+ * $Id: class_sieve.inc,v 1.1 2005/02/21 09:33:01 cajus Exp $ 
+ *
+ * Copyright 2001 Dan Ellis <danellis@rushmore.com>
+ *
+ * See the enclosed file COPYING for license information (GPL).  If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+// TODO before next release:   remove ::status() and dependencies
+
+
+define ("F_NO", 0);            
+define ("F_OK", 1);
+define ("F_DATA", 2);
+define ("F_HEAD", 3);
+
+define ("EC_NOT_LOGGED_IN", 0);
+define ("EC_QUOTA", 10);
+define ("EC_NOSCRIPTS", 20);
+define ("EC_UNKNOWN", 255);
+/*
+
+SIEVE-PHP.LIB VERSION 0.0.8
+
+(C) 2001 Dan Ellis.
+
+PLEASE READ THE README FILE FOR MORE INFORMATION.
+
+Basically, this is the first re-release.  Things are much better than before.
+
+Notes:
+This program/libary has bugs.
+       .       This was quickly hacked out, so please let me know what is wrong and if you feel ambitious submit
+               a patch :).
+
+Todo:
+       .       Provide better error diagnostics.                       (mostly done with ver 0.0.5)
+       .       Allow other auth mechanisms besides plain               (in progress)
+       .       Have timing mechanism when port problems arise.         (not done yet)
+       .       Maybe add the NOOP function.                            (not done yet)
+       .       Other top secret stuff....                              (some done, believe me?)
+
+Dan Ellis (danellis@rushmore.com)
+
+This program is released under the GNU Public License.
+
+You should have received a copy of the GNU Public
+ License along with this package; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.        
+
+See CHANGES for updates since last release
+
+Contributers of patches:
+       Atif Ghaffar
+       Andrew Sterling Hanenkamp <sterling@hanenkamp.com>
+*/
+
+
+class sieve
+{
+  var $host;
+  var $port;
+  var $user;
+  var $pass;
+  var $auth_types;             /* a comma seperated list of allowed auth types, in order of preference */
+  var $auth_in_use;            /* type of authentication attempted */
+  
+  var $line;
+  var $fp;
+  var $retval;
+  var $tmpfile;
+  var $fh;
+  var $len;
+  var $script;
+
+  var $loggedin;
+  var $capabilities;
+  var $error;
+  var $error_raw;
+  var $responses;
+
+  //maybe we should add an errorlvl that the user will pass to new sieve = sieve(,,,,E_WARN)
+  //so we can decide how to handle certain errors?!?
+
+  //also add a connection type, like PLAIN, MD5, etc...
+
+
+  function get_response()
+  {
+    if($this->loggedin == false or feof($this->fp)){
+        $this->error = EC_NOT_LOGGED_IN;
+        $this->error_raw = "You are not logged in.";
+        return false;
+    }
+
+    unset($this->response);
+    unset($this->error);
+    unset($this->error_raw);
+
+    $this->line=fgets($this->fp,1024);
+    $this->token = split(" ", $this->line, 2);
+
+       if($this->token[0] == "NO"){
+               /* we need to try and extract the error code from here.  There are two possibilites: one, that it will take the form of:
+                  NO ("yyyyy") "zzzzzzz" or, two, NO {yyyyy} "zzzzzzzzzzz" */
+               $this->x = 0;
+               list($this->ltoken, $this->mtoken, $this->rtoken) = split(" ", $this->line." ", 3);
+               if($this->mtoken[0] == "{"){
+                       while($this->mtoken[$this->x] != "}" or $this->err_len < 1){
+                               $this->err_len = substr($this->mtoken, 1, $this->x);
+                               $this->x++;    
+                       }
+                       #print "<br>Trying to receive $this->err_len bytes for result<br>";
+                       $this->line = fgets($this->fp,$this->err_len);
+                       $this->error_raw[]=substr($this->line, 0, strlen($this->line) -2);    //we want to be nice and strip crlf's
+                       $this->err_recv = strlen($this->line);
+
+                       /* Ensure max loop of 1000, to keep the ui from freezing */
+                       $max = 1000;
+                       $cur = 0;
+
+                       while($this->err_recv < ($this->err_len) && ($cur < $max)){
+
+                               $cur ++;
+                               $this->line      = fgets($this->fp,4096);
+                               $this->err_recv += strlen($this->line);
+                               $this->error_raw[]=preg_replace("/\r\n/","",$this->line);    //we want to be nice and strip crlf'
+                       } 
+               } /* end if */
+               elseif($this->mtoken[0] == "("){
+                       switch($this->mtoken){
+                               case "(\"QUOTA\")":
+                    $this->error = EC_QUOTA;
+                    $this->error_raw=$this->rtoken;
+                    break;
+                default:
+                    $this->error = EC_UNKNOWN;
+                    $this->error_raw=$this->rtoken;
+                    break;
+            } /* end switch */
+        } /* end elseif */
+        else{
+            $this->error = EC_UNKNOWN;
+            $this->error_raw = $this->line;
+        }     
+        return false;
+
+    } /* end if */
+    elseif(substr($this->token[0],0,-2) == "OK"){
+         return true;
+    } /* end elseif */
+    elseif($this->token[0][0] == "{"){
+        
+        /* Unable wild assumption:  that the only function that gets here is the get_script(), doesn't really matter though */       
+
+        /* the first line is the len field {xx}, which we don't care about at this point */
+        $this->line = fgets($this->fp,1024);
+        while(substr($this->line,0,2) != "OK" and substr($this->line,0,2) != "NO"){
+            $this->response[]=$this->line;
+            $this->line = fgets($this->fp, 1024);
+        }
+        if(substr($this->line,0,2) == "OK")
+            return true;
+        else
+            return false;
+    } /* end elseif */
+    elseif($this->token[0][0] == "\""){
+
+        /* I'm going under the _assumption_ that the only function that will get here is the listscripts().
+           I could very well be mistaken here, if I am, this part needs some rework */
+
+        $this->found_script=false;        
+
+        while(substr($this->line,0,2) != "OK" and substr($this->line,0,2) != "NO"){
+            $this->found_script=true;
+            list($this->ltoken, $this->rtoken) = explode(" ", $this->line." ",2);
+               //hmmm, a bug in php, if there is no space on explode line, a warning is generated...
+           
+            if(strcmp(rtrim($this->rtoken), "ACTIVE")==0){
+                $this->response["ACTIVE"] = substr(rtrim($this->ltoken),1,-1);  
+            }
+            else
+                $this->response[] = substr(rtrim($this->ltoken),1,-1);
+            $this->line = fgets($this->fp, 1024);
+        } /* end while */
+        
+        return true;
+        
+    } /* end elseif */
+    else{
+            $this->error = EC_UNKNOWN;
+            $this->error_raw = $this->line;
+            print "<b><i>UNKNOWN ERROR (Please report this line to danellis@rushmore.com to include in future releases): $this->line</i></b><br>";
+            return false;
+    } /* end else */   
+  } /* end get_response() */
+
+  function sieve($host, $port, $user, $pass, $auth="", $auth_types="PLAIN DIGEST-MD5")
+  {
+    $this->host=$host;
+    $this->port=$port;
+    $this->user=$user;
+    $this->pass=$pass;
+    if(!strcmp($auth, ""))             /* If there is no auth user, we deem the user itself to be the auth'd user */
+        $this->auth = $this->user;
+    else
+        $this->auth = $auth;
+    $this->auth_types=$auth_types;     /* Allowed authentication types */
+    $this->fp=0;
+    $this->line="";
+    $this->retval="";
+    $this->tmpfile="";
+    $this->fh=0;
+    $this->len=0;
+    $this->capabilities="";
+    $this->loggedin=false;
+    $this->error= "";
+    $this->error_raw="";
+  }
+
+  function parse_for_quotes($string)
+  {
+      /* This function tokenizes a line of input by quote marks and returns them as an array */
+
+      $start = -1;
+      $index = 0;
+
+      for($ptr = 0; $ptr < strlen($string); $ptr++){
+          if($string[$ptr] == '"' and $string[$ptr] != '\\'){
+              if($start == -1){
+                  $start = $ptr;
+              } /* end if */
+              else{
+                  $token[$index++] = substr($string, $start + 1, $ptr - $start - 1);
+                  $found = true;
+                  $start = -1;
+              } /* end else */
+
+          } /* end if */  
+
+      } /* end for */
+
+      if(isset($token))
+          return $token;
+      else
+          return false;
+  } /* end function */            
+
+  function status($string)
+  {
+      //this should probably be replaced by a smarter parser.
+
+      /*  Need to remove this and all dependencies from the class */
+
+      switch (substr($string, 0,2)){
+          case "NO":
+              return F_NO;             //there should be some function to extract the error code from this line
+                                       //NO ("quota") "You are oly allowed x number of scripts"
+              break;
+          case "OK":
+              return F_OK;
+              break;
+          default:
+              switch ($string[0]){
+                  case "{":
+                      //do parse here for {}'s  maybe modify parse_for_quotes to handle any parse delimiter?
+                      return F_HEAD;
+                      break;
+                  default:
+                      return F_DATA;
+                      break;
+              } /* end switch */
+        } /* end switch */
+  } /* end status() */
+
+  function sieve_login()
+  {
+
+    $this->fp=@fsockopen($this->host,$this->port);
+    if($this->fp == false)
+        return false;
+    $this->line=fgets($this->fp,1024);
+
+    //Hack for older versions of Sieve Server.  They do not respond with the Cyrus v2. standard
+    //response.  They repsond as follows: "Cyrus timsieved v1.0.0" "SASL={PLAIN,........}"
+    //So, if we see IMLEMENTATION in the first line, then we are done.
+
+    if(ereg("IMPLEMENTATION",$this->line))
+    {
+      //we're on the Cyrus V2 sieve server
+      while(sieve::status($this->line) == F_DATA){
+
+          $this->item = sieve::parse_for_quotes($this->line);
+
+          if(strcmp($this->item[0], "IMPLEMENTATION") == 0)
+              $this->capabilities["implementation"] = $this->item[1];
+        
+          elseif(strcmp($this->item[0], "SIEVE") == 0 or strcmp($this->item[0], "SASL") == 0){
+
+              if(strcmp($this->item[0], "SIEVE") == 0)
+                  $this->cap_type="modules";
+              else
+                  $this->cap_type="auth";            
+
+              $this->modules = split(" ", $this->item[1]);
+              if(is_array($this->modules)){
+                  foreach($this->modules as $this->module)
+                      $this->capabilities[$this->cap_type][$this->module]=true;
+              } /* end if */
+              elseif(is_string($this->modules))
+                  $this->capabilites[$this->cap_type][$this->modules]=true;
+          }    
+          else{ 
+              $this->capabilities["unknown"][]=$this->line;
+          }    
+      $this->line=fgets($this->fp,1024);
+
+       }// end while
+    }
+    else
+    {
+        //we're on the older Cyrus V1. server  
+        //this version does not support module reporting.  We only have auth types.
+        $this->cap_type="auth";
+       
+        //break apart at the "Cyrus timsieve...." "SASL={......}"
+        $this->item = sieve::parse_for_quotes($this->line);
+
+        $this->capabilities["implementation"] = $this->item[0];
+
+        //we should have "SASL={..........}" now.  Break out the {xx,yyy,zzzz}
+        $this->modules = substr($this->item[1], strpos($this->item[1], "{"),strlen($this->item[1])-1);
+
+        //then split again at the ", " stuff.
+        $this->modules = split($this->modules, ", ");
+        //fill up our $this->modules property
+        if(is_array($this->modules)){
+            foreach($this->modules as $this->module)
+                $this->capabilities[$this->cap_type][$this->module]=true;
+        } /* end if */
+        elseif(is_string($this->modules))
+            $this->capabilites[$this->cap_type][$this->module]=true;
+    }
+
+
+
+
+    if(sieve::status($this->line) == F_NO){            //here we should do some returning of error codes?
+        $this->error=EC_UNKNOWN;
+        $this->error_raw = "Server not allowing connections.";
+        return false;
+    }
+
+    /* decision login to decide what type of authentication to use... */
+
+     /* Loop through each allowed authentication type and see if the server allows the type */
+     foreach(split(" ",$this->auth_types) as $auth_type)
+     {
+        if ($this->capabilities["auth"][$auth_type])
+        {
+            /* We found an auth type that is allowed. */
+            $this->auth_in_use = $auth_type;
+            break;
+        }
+     }
+    
+    /* Fill error message if no auth types are present */
+    if (!isset($this->capabilities["auth"])){
+        $this->error=EC_UNKNOWN;
+       $this->error_raw = "No authentication methods found - please check your sieve setup for missing sasl modules";
+       return false;
+    }
+
+     /* call our authentication program */  
+    return sieve::authenticate();
+
+  }
+
+  function sieve_logout()
+  {
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp,"LOGOUT\r\n");
+    fclose($this->fp);
+    $this->loggedin=false;
+    return true;
+  }
+
+  function sieve_sendscript($scriptname, $script)
+  {
+    if($this->loggedin==false)
+        return false;
+    $this->script=stripslashes($script);
+    $len=strlen($this->script);
+    fputs($this->fp, "PUTSCRIPT \"$scriptname\" {".$len."+}\r\n");
+    fputs($this->fp, "$this->script\r\n");
+  
+    return sieve::get_response();
+
+  }  
+  
+  //it appears the timsieved does not honor the NUMBER type.  see lex.c in timsieved src.
+  //don't expect this function to work yet.  I might have messed something up here, too.
+  function sieve_havespace($scriptname, $scriptsize)
+  {
+    if($this->loggedin==false)
+        return false;
+    fputs($this->fp, "HAVESPACE \"$scriptname\" $scriptsize\r\n");
+    return sieve::get_response();
+
+  }  
+
+  function sieve_setactivescript($scriptname)
+  {
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp, "SETACTIVE \"$scriptname\"\r\n");   
+    return sieve::get_response();
+
+  }
+  
+  function sieve_getscript($scriptname)
+  {
+    unset($this->script);
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp, "GETSCRIPT \"$scriptname\"\r\n");
+    return sieve::get_response();
+   
+  }
+
+
+  function sieve_deletescript($scriptname)
+  {
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp, "DELETESCRIPT \"$scriptname\"\r\n");    
+
+    return sieve::get_response();
+  }
+
+  
+  function sieve_listscripts() 
+   { 
+     fputs($this->fp, "LISTSCRIPTS\r\n"); 
+     sieve::get_response();            //should always return true, even if there are no scripts...
+     if(isset($this->found_script) and $this->found_script)
+         return true;
+     else{
+         $this->error=EC_NOSCRIPTS;    //sieve::getresponse has no way of telling wether a script was found...
+         $this->error_raw="No scripts found for this account.";
+         return false;
+     }
+   }
+
+  function sieve_alive()
+  {
+      if(!isset($this->fp) or $this->fp==0){
+          $this->error = EC_NOT_LOGGED_IN;
+          return false;
+      }
+      elseif(feof($this->fp)){                 
+          $this->error = EC_NOT_LOGGED_IN;
+          return false;
+      }
+      else
+          return true;
+  }
+
+  function authenticate()
+  {
+
+    switch ($this->auth_in_use) {
+    
+        case "PLAIN":
+            $auth=base64_encode("$this->user\0$this->auth\0$this->pass");
+   
+            $this->len=strlen($auth);                  
+            fputs($this->fp, "AUTHENTICATE \"PLAIN\" {".$this->len."+}\r\n");
+            fputs($this->fp, "$auth\r\n");
+
+            $this->line=fgets($this->fp,1024);         
+            while(sieve::status($this->line) == F_DATA)
+               $this->line=fgets($this->fp,1024);
+
+             if(sieve::status($this->line) == F_NO)
+               return false;
+             $this->loggedin=true;
+               return true;    
+             break;
+
+        default:
+            return false;
+            break;
+
+    }//end switch
+
+
+  }//end authenticate()
+
+
+}
+
+
+
+?>
diff --git a/include/sieve/class_sieveElement_Block_End.inc b/include/sieve/class_sieveElement_Block_End.inc
new file mode 100644 (file)
index 0000000..3bd0b04
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+class sieve_block_end 
+{
+  var $object_id= -1;
+  
+  function sieve_block_end($data = NULL,$object_id)
+  {
+    $this->object_id = $object_id;
+  }
+
+  function execute()
+  {
+    $smarty = get_smarty();
+    return($smarty->fetch(get_template_path("templates/element_block_end.tpl",TRUE,dirname(__FILE__))));
+  }
+  function check()
+  {
+    return(array());
+  }
+
+  function get_sieve_script_part()
+  {
+    return("}");
+  } 
+  function save_object()
+  {
+  }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Block_Start.inc b/include/sieve/class_sieveElement_Block_Start.inc
new file mode 100644 (file)
index 0000000..e001cdc
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+class sieve_block_start 
+{
+  var $object_id= -1;
+  
+  function sieve_block_start($data = NULL,$object_id)
+  {
+    $this->object_id = $object_id;
+  }
+
+  function execute()
+  {
+    $smarty = get_smarty();
+    return($smarty->fetch(get_template_path("templates/element_block_start.tpl",TRUE,dirname(__FILE__))));
+  }
+
+  function check()
+  {
+    return(array());
+  }
+
+  function save_object()
+  {
+  }
+
+  function get_sieve_script_part()
+  {
+    return("{");
+  } 
+}
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Comment.inc b/include/sieve/class_sieveElement_Comment.inc
new file mode 100644 (file)
index 0000000..c3e126c
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+
+/* Sieve comment tag */
+class sieve_comment 
+{
+  var $data = "";
+  var $object_id= -1;
+  var $small  = TRUE;
+
+  function get_sieve_script_part()
+  {
+    $str = "\n/*".$this->data."*/";
+    return($str);
+  } 
+    
+  function sieve_comment($data,$object_id)
+  {
+    $this->object_id = $object_id;
+
+    if($data == NULL){
+      $data = array('ELEMENTS' => array(array('class' => "quoted-string" ,"text" => "/*"._("Your comment here")."*/")));
+    }
+
+    foreach($data['ELEMENTS'] as $node){
+
+      $text = $node['text'];
+  
+      /* Convert \t to spaces  */ 
+      $text = preg_replace("#\t#","    ",$text);
+      
+      /* Remove comment indicator '#' but keep spaces */
+      $text = preg_replace("/^([ ]*)\#/","\\1",$text);
+     
+      /* Remove comment indicator '/ *' */ 
+      $text = preg_replace("#\/\*#","",$text);
+      
+      /* Remove comment indicator '* /' */ 
+      $text = preg_replace("#\*\/#","",$text);
+
+      $this->data .= $text."\n";
+    }
+    $this->data = rtrim($this->data)."\n";
+  }
+
+  function check()
+  {
+    return(array())  ;
+  }
+
+  function save_object()
+  {
+    if(isset($_POST['comment_'.$this->object_id])){
+      $cm = stripslashes( $_POST['comment_'.$this->object_id]);
+      $cm = preg_replace("/\*\//","* /",$cm);
+      $this->data = $cm;
+    }
+  
+    if(isset($_POST['toggle_small_'.$this->object_id])){
+      $this->small = !$this->small;
+    }
+  }
+
+  function execute()
+  {
+    $smarty = get_smarty();
+    $smarty->assign("ID", $this->object_id);
+    $smarty->assign("Small", $this->small);
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+    $Comment = $this->data;
+
+    if($this->small){
+      $Comment = nl2br(preg_replace("/ /","&nbsp;",$Comment));
+    }
+    /* Create html object */ 
+    $smarty->assign("Comment",$Comment);
+    $smarty->assign("ID",$this->object_id);
+    $object = $smarty->fetch(get_template_path("templates/element_comment.tpl",TRUE,dirname(__FILE__)));    
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+}
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Discard.inc b/include/sieve/class_sieveElement_Discard.inc
new file mode 100644 (file)
index 0000000..1ee28ad
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+
+class sieve_discard 
+{
+  var $data = array();
+  var $object_id = -1;
+
+  function sieve_discard($data,$object_id)
+  {
+    $this->object_id = $object_id;
+  }
+
+  function get_sieve_script_part()
+  {
+    return("discard;");
+  } 
+  function check()
+  {
+    return(array())  ;
+  }
+
+    
+  function save_object()
+  {
+  
+  }
+
+  function execute()
+  {
+    $smarty = get_smarty();
+    $smarty->assign("ID", $this->object_id);
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+    $object = $smarty->fetch(get_template_path("templates/element_discard.tpl",TRUE,dirname(__FILE__)));
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Else_Elsif.inc b/include/sieve/class_sieveElement_Else_Elsif.inc
new file mode 100644 (file)
index 0000000..c02e123
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+/* Sieve else tag */
+class sieve_elsif extends sieve_if
+{
+  var $TYPE = "elsif";
+}
+
+class sieve_else
+{
+  var $object_id = -1;
+
+  function check()
+  {
+    return(array());
+  }
+
+  function sieve_else($data,$object_id)
+  {
+    $this->object_id = $object_id;
+  }
+
+  function save_object()
+  {
+  }
+
+  function execute()
+  {
+    $smarty = get_smarty();
+    $smarty->assign("ID", $this->object_id);
+    $object_container = $smarty->fetch(get_template_path("templates/object_container_clear.tpl",TRUE,dirname(__FILE__)));
+    $object= $smarty->fetch(get_template_path("templates/element_else.tpl",TRUE,dirname(__FILE__)));
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+
+  function get_sieve_script_part()
+  {
+    return("else");
+  }
+}
+
+?>
diff --git a/include/sieve/class_sieveElement_Fileinto.inc b/include/sieve/class_sieveElement_Fileinto.inc
new file mode 100644 (file)
index 0000000..f357d37
--- /dev/null
@@ -0,0 +1,104 @@
+<?php
+
+class sieve_fileinto 
+{
+  var $data     = "";
+  var $object_id= -1;
+  var $options  = array();
+  var $parent   = NULL;
+  var $user_mode= FALSE;
+
+  function save_object()
+  {
+    $mbs = $this->get_mail_boxes();
+    
+    if(isset($_POST['fileinto_'.$this->object_id])){
+      $mb = stripslashes($_POST['fileinto_'.$this->object_id]);
+
+      /* Depending on the user mode we only accept 
+       *  existing mailboxes 
+       */
+      if($this->user_mode){
+        $this->data = $mb;
+      }else{
+        if(in_array_ics($mb,$mbs)){
+          $this->data = $mb; 
+        }
+      }
+
+      /* Check Mode */
+      if(isset($_POST['user_mode_'.$this->object_id])){
+        $this->user_mode = !$this->user_mode;
+      }
+    }
+  }
+
+  function sieve_fileinto($data,$object_id,$parent)
+  {
+    $this->object_id = $object_id;
+    $this->parent = $parent;
+    $this->parent->add_require("fileinto");
+
+    $mbs = $this->get_mail_boxes();
+      
+    /* Set the default mailbox */
+    if($data == NULL){
+      $data = array('ELEMENTS' => array(array('class' => "quoted-string" ,"text" => $mbs[key($mbs)])));
+    }
+
+    /* Load element contents, should normaly be only one string 
+     *  but if we found more than one, just append the following strings.
+     */
+    for($i = 0 ; $i < count($data['ELEMENTS']) ; $i++){
+      $tmp = sieve_get_strings($data['ELEMENTS'],$i);
+      $i  = $i + $tmp['OFFSET'];
+      foreach($tmp['STRINGS'] as $str){
+        $this->data .= $str;
+      }
+    }
+
+    /* Set user mode to active, so we are able to insert 
+     *  the destination mail folder manually 
+     */
+    if(!in_array_ics($this->data,$mbs)){
+      $this->user_mode = TRUE;
+    }
+  }
+
+  function get_sieve_script_part()
+  {
+    $tmp = "";
+    $tmp.= "\"".$this->data."\", ";
+    $tmp = preg_replace("/,$/","",trim($tmp));
+    $tmp = preg_replace ("/\"\"/","\"",$tmp);
+    return("fileinto ".$tmp.";");
+  } 
+    
+  function execute()
+  {
+    $smarty = get_smarty();
+    $smarty->assign("Selected",htmlentities($this->data));
+    $smarty->assign("Boxes", $this->get_mail_boxes());
+    $smarty->assign("User_Mode", $this->user_mode);
+    $smarty->assign("ID", $this->object_id);
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+    $object= $smarty->fetch(get_template_path("templates/element_fileinto.tpl",TRUE,dirname(__FILE__)));
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+
+    return($str);
+  }
+
+  function check()
+  {
+    return(array());
+  }
+
+  function get_mail_boxes()
+  {
+    $list  = $this->parent->parent->parent->parent->mailboxList;
+    return($list);
+  }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_If.inc b/include/sieve/class_sieveElement_If.inc
new file mode 100644 (file)
index 0000000..acdcb94
--- /dev/null
@@ -0,0 +1,1469 @@
+<?php
+
+
+class sieve_if 
+{
+  var $_parsed         = array();
+  var $TYPE    = "if";
+  var $object_id     = -1;
+
+  var $address_parts    = array();
+  var $comparators      = array();
+  var $match_types      = array();
+  var $operators        = array();
+  var $parent           = NULL;
+  
+  /* Initialize class 
+   *  $elements   contains all tokens that belongs to this if/else tag
+   *  $object_id  cotains an unique tag id, to be able to create uniqe html post names
+   */
+  function sieve_if($elements,$object_id,$parent)
+  {
+    $this->parent = $parent;
+    $this->object_id       = $object_id;
+  
+    /* Possible address parts we can select */
+    $this->address_parts = array( 
+        ":all"       => _("Complete address")."&nbsp;("._("Default").")",
+        ":domain"    => _("Domain part") ,
+        ":localpart" => _("Local part"));
+
+    /* comparator type */
+    $this->comparators   = array( 
+        "i;ascii-casemap" => _("Case insensitive")."&nbsp;("._("Default").")",
+        "i;octet"         => _("Case sensitive"),
+        "i;ascii-numeric" => _("Numeric"));
+
+    /* Match types */
+    $this->match_types  = array(  
+        ":is"         => _("is"),
+        ":regex"      => _("regex"),
+        ":contains"   => _("contains"),
+        ":matches"    => _("matches"),
+        ":count"      => _("count"),
+        ":value"      => _("value is"));
+
+    /* Operators */
+    $this->operators = array(     
+        "lt"  => _("less than"),
+        "le"  => _("less or equal"),
+        "eq"  => _("equals"),
+        "ge"  => _("greater or equal"),
+        "gt"  => _("greater than"),
+        "ne"  => _("not equal"));
+
+    /* Skip parsing if this element is new */
+    if($elements != NULL){
+
+      /* Remove comments from tests */  
+      $tmp = array();
+      foreach($elements['ELEMENTS'] as $ele){
+        if($ele['class'] != "comment"){
+          $tmp[] = $ele;
+        }
+      }
+      $elements['ELEMENTS'] = $tmp;
+
+      if($elements!=NULL){
+        $this->elements = $elements;
+        $this->_parsed  = $this->_parse($elements['ELEMENTS'],1);
+      }
+    }
+  }
+
+
+  /* Returns the sieve script for this 
+   *  if/else tag.
+   */
+  function get_sieve_script_part()
+  {
+    $tmp = $this->TYPE." ".$this->get_sieve_script_part_recursive($parsed = NULL,$id = 1,$obj_id=1);
+    return($tmp);
+  } 
+
+
+  /* Return error msgs */
+  function check()
+  {
+    $check = $this->check_recursive();
+    return($check);
+  }
+
+  /* Recursivly fetch all error msgs */
+  function check_recursive($parsed = NULL,$id = 1,$obj_id=1)
+  {
+    $ret = array();
+    if($parsed == NULL){
+      $parsed = $this->_parsed;
+    }
+
+    if($parsed == NULL) {
+        return(array(_("Can't save empty tests.")));
+    }
+
+    /* Walk through all elements */
+    foreach($parsed as $key => $data){
+
+      /* Create elements */
+      switch($key)
+      {
+        /*******************
+         * Allof / Anyof
+         *******************/
+        case "anyof" :
+        case "allof" :
+        { 
+          foreach($data as $key2 => $dat){
+            if(($key2 === "Inverse") && ($key2 == "Inverse")){
+              continue;
+            }
+            $msgs = $this->check_recursive($dat, ($id +1),$key2);
+
+            foreach($msgs as $msg){
+              $ret[] = $msg;
+            }
+          }
+          break;
+        }
+
+        /*******************
+         * True / False
+         *******************/
+
+        case "true" :
+        case "false" : 
+        {
+          /* Can't fail anyway */
+          break;
+        }
+    
+        /*******************
+         * Default
+         *******************/
+
+        default: 
+        {
+          if(isset($data['LastError']) && !empty($data['LastError'])){
+            $ret[] = $data['LastError'];
+          }
+        }
+      }
+    }
+    return($ret);
+  }
+
+  /* Recursivly create a sieve script out of the given 
+   *  tags and tokens provided by $parsed.
+   *  $id       specifies the depth of the current element.
+   *  $obj_id   is the current tag-id handled by this function
+   */
+  function get_sieve_script_part_recursive($parsed = NULL,$id = 1,$obj_id=1)
+  {
+    $script ="";
+    if($parsed == NULL){
+      $parsed = $this->_parsed;
+    }
+
+
+    if(!is_array($parsed)){
+      return;
+    }
+
+    /* Walk through all elements */
+    foreach($parsed as $key => $data){
+
+      /* Create Inverse Tag */
+      if(is_array($data) && isset($data['Inverse']) && $data['Inverse']){
+        $Inverse = TRUE;
+      }else{
+        $Inverse = FALSE;
+      }
+
+      /* Create elements */
+      switch($key)
+      {
+
+        /*******************
+         * True / False
+         *******************/
+
+        case "true" :
+        case "false" :
+        {
+          /* Invert this test if required */
+          if($Inverse){
+            $script .= "not ";
+          }
+          $script .= $key;
+          break;
+        }
+
+
+        /*******************
+         * Address
+         *******************/
+
+        case "address" :   
+        {
+          /* [not] address 
+                        [address-part: tag] 
+                        [comparator: tag] 
+                        [match-type: tag] 
+                        <header-list: string-list> 
+                        <key-list: string-list> 
+          */
+
+          /* Invert this test if required */
+          if($Inverse){
+            $script .= "not ";
+          }
+  
+          $script .="address ";
+          /* Add address part tag */ 
+          if(!empty($data['Address_Part']) && $data['Address_Part'] != ":all"){
+            $script .= $data['Address_Part']." ";
+          }
+
+          /* Add comparator */
+          if(!empty($data['Comparator']) && $data['Comparator'] != ""){
+            $script .= preg_replace('/\"\"/',"\"", ":comparator \"".$data['Comparator']."\" ");
+          }
+    
+          /* Add match type */
+          $script .= $data['Match_type']." ";
+
+          /* Add special match type for count and value */
+          if(in_array($data['Match_type'], array(":value",":count")) && !empty($data['Match_type_value'])) {
+            $script .= sieve_create_strings($data['Match_type_value'])." ";
+          }
+
+          $script .= sieve_create_strings($data['Key_List']);
+          $script .= " ";
+          $script .= sieve_create_strings($data['Value_List']);
+          break;
+        }
+
+
+        /*******************
+         * Header
+         *******************/
+
+        case "header" :   
+        {
+          /* [not] header   
+                [comparator: tag] 
+                [match-type: tag] 
+                <header-names: string-list> 
+                <key-list: string-list>
+          */
+
+          /* Invert ? */
+          if($Inverse){
+            $script .= "not ";
+          }
+  
+          $script .="header ";
+          /* Add address part tag */ 
+          if(!empty($data['Address_Part']) && $data['Address_Part'] != ":all"){
+            $script .= $data['Address_Part']." ";
+          }
+
+          /* Add comparator */
+          if(!empty($data['Comparator']) && $data['Comparator'] != ""){
+            $script .= preg_replace('/\"\"/',"\"", ":comparator \"".$data['Comparator']."\" ");
+          }
+    
+          /* Add match type */
+          $script .= $data['Match_type']." ";
+
+          /* Add special match type for count and value */
+          if(in_array($data['Match_type'], array(":value",":count")) && !empty($data['Match_type_value'])) {
+            $script .= sieve_create_strings($data['Match_type_value'])." ";
+          }
+
+          $script .= sieve_create_strings($data['Key_List']);
+          $script .= " ";
+          $script .= sieve_create_strings($data['Value_List']);
+          break;
+        }
+
+
+        /*******************
+         * Envelope
+         *******************/
+
+        case "envelope" :   
+        {
+          /* [not]  envelope 
+                    [address-part: tag] 
+                    [comparator: tag] 
+                    [match-type: tag] 
+                    <envelope-part: string-list> 
+                    <key-list: string-list> 
+          */
+
+          /* Invert */
+          if($Inverse){
+            $script .= "not ";
+          }
+  
+          $script .="envelope ";
+          /* Add address part tag */ 
+          if(!empty($data['Address_Part']) && $data['Address_Part'] != ":all"){
+            $script .= $data['Address_Part']." ";
+          }
+
+          /* Add comparator */
+          if(!empty($data['Comparator']) && $data['Comparator'] != ""){
+            $script .= preg_replace('/\"\"/',"\"", ":comparator \"".$data['Comparator']."\" ");
+          }
+    
+          /* Add match type */
+          $script .= $data['Match_type']." ";
+
+          /* Add special match type for count and value */
+          if(in_array($data['Match_type'], array(":value",":count")) && !empty($data['Match_type_value'])) {
+            $script .= sieve_create_strings($data['Match_type_value'])." ";
+          }
+
+          $script .= sieve_create_strings($data['Key_List']);
+          $script .= " ";
+          $script .= sieve_create_strings($data['Value_List']);
+          break;
+        }
+
+
+        /*******************
+         * Exists
+         *******************/
+        case "exists" : 
+        {
+          /* [not] exists 
+              <header-names: string-list> 
+          */
+
+          /* Invert ? */
+          if($Inverse){
+            $script .= "not ";
+          }
+
+          $script .= "exists ".sieve_create_strings($data['Values']);
+          break;
+        }
+
+
+        /*******************
+         * Size
+         *******************/
+        case "size" : 
+        {
+          /* [not] size 
+                <":over" / ":under"> 
+                <limit: number> 
+          */
+
+          /* Invert ? */
+          if($Inverse){
+            $script .= "not ";
+          }
+          /* Add size test */ 
+          $script .="size ";
+          $script .=$data['Match_type']." ";
+          foreach($data['Value_List'] as $val){
+            $script .= $val." ";
+          }
+          break;
+        }
+
+
+        /*******************
+         * Allof
+         *******************/
+        case "anyof" :
+        case "allof" :
+        {
+          /* allof <tests: test-list>
+             anyof <tests: test-list> */
+
+          /* Add spaces, to indent the code.*/ 
+          $block = "\n";
+          for($i = 0 ; $i < $id ; $i ++){
+            $block .= SIEVE_INDENT_TAB;
+          }          
+
+          /* Add allof/anyof tag */
+          if($Inverse){
+            $script .= "not ";
+          }
+          $script.= $key." ( ";
+
+          /* Add each test parameter */
+          foreach($data as $key2 => $dat){
+            if(($key2 === "Inverse") && ($key2 == "Inverse")){
+              continue;
+            }
+            $script.= $block.$this->get_sieve_script_part_recursive($dat, ($id +1),$key2).", ";
+          }
+    
+          /* Remove last _,_ and close the tag */
+          $script = preg_replace("/,$/","",trim($script));
+          $script.= $block.")";
+          break ;
+        }
+
+        default :
+        {
+          $script .= "THERE IS SOME IMPLEMENTATION MISSING FOR SIEVE SCRIPT CREATION :".$key;
+        }
+      }
+    }
+    return($script);
+  }
+
+  
+  function add_test($data,$type)
+  {
+    switch($type)
+    {
+      case "header" : 
+      case "address" : 
+      case "envelope" : 
+      {
+        /* Add to Tree */
+        $values = array(        "Inverse"         => FALSE,
+                                "Comparator"      => "",
+                                "Expert"          => FALSE,
+                                "LastError"       => "",
+                                "Match_type"      => ":contains",
+                                "Match_type_value"=> "",
+                                "Key_List"        => array(_("emtpy")),
+                                "Value_List"      => array(_("empty"))) ;
+        if($type == "address"){
+          $values["Address_Part"]    = ":all";
+        }
+        $data[$type]=$values;
+
+        $this->parent->add_require("relational");
+        if($type == "envelope"){
+          $this->parent->add_require("envelope");
+        }
+    
+
+        break;
+      }
+      case "allof" :
+      case "anyof" :
+      {
+        $data[$type] = array("Inverse" => FALSE);
+        break;
+      }
+      case "size" :
+      {
+        $tmp= array( 
+            "Inverse"    => FALSE,
+            "Match_type" => ":over",
+            "Value_List" => array("1M"));
+
+        $tmp['LastError'] = "";
+        $data[$type] = $tmp;
+        break;
+      }
+      case "true":
+      {
+        $data['true'] = "true";
+        $data['true']['LastError'] = "";
+        break;
+      }
+      case "false":
+      {
+        $data['false'] = "false";
+        $data['false']['LastError'] = "";
+        break;
+      }
+      case "exists" :
+      {
+        $data['exists'] = array('Inverse' => FALSE,
+                                'Values'  => array(_("Nothing specified right now")),
+                                'LastError' => "");
+        break;
+      }
+      default : echo "Still buggy ";exit;
+    }
+
+    return($data);
+  }
+
+
+  /* Ensure that all changes made on the ui 
+   *  will be saved. 
+   */
+  function save_object()
+  {
+  
+    if(isset($_POST['add_type']) && isset($_POST["test_type_to_add_".$this->object_id])){
+      $this->_parsed = $this->add_test($this->_parsed,$_POST["test_type_to_add_".$this->object_id]);
+    }
+
+    $tmp = $this->save_object_recursive($parsed = NULL,$id = 1,$obj_id=1);
+    $this->_parsed = $tmp;
+  }
+
+
+  /* Recursivly save all ui changes for the 
+   *  tags and tokens provided by $parsed.
+   *  $id       specifies the depth of the current element.
+   *  $obj_id   is the current tag-id handled by this function
+   */
+  function save_object_recursive($parsed = NULL,$id = 1,$obj_id=1)
+  {
+    /* Variable initialization */ 
+    $ret ="";
+    if($parsed == NULL){
+      $parsed = $this->_parsed;
+    }
+
+    if(!is_array($parsed)) {
+      return;
+    }
+
+    /* Walk through all elements */
+    foreach($parsed as $key => $data){
+
+      /* Id used to have unique html names */
+      $element_id = $this->object_id."_".$id."_".$obj_id;
+      
+      foreach($_POST as $name => $value){
+        if(preg_match("/Remove_Test_Object_".$element_id."_(x|y)/",$name)) {
+          return(false); 
+        }
+      }
+
+      
+      if(isset($_POST['add_type']) && isset($_POST["test_type_to_add_".$element_id])){
+        $parsed[$key][] = $this->add_test(array(),$_POST["test_type_to_add_".$element_id]);
+      }
+
+      /* Create elements */
+      switch($key)
+      {
+        /*******************
+         * Address 
+         *******************/
+
+        case "envelope" :
+        case "header" : 
+        case "address" : 
+        {
+          /* [not] address 
+                        [address-part: tag] 
+                        [comparator: tag] 
+                        [match-type: tag] 
+                        <header-list: string-list> 
+                        <key-list: string-list> 
+          */
+
+          /* Possible address parts we can select */
+          $address_parts = $this->address_parts;
+          $comparators   = $this->comparators;
+          $match_types   = $this->match_types; 
+          $operators     = $this->operators;
+
+          $parsed[$key]['LastError'] = "";
+
+          /* Toggle Inverse ? */
+          if(isset($_POST['toggle_inverse_'.$element_id])){
+            $parsed[$key]['Inverse'] = !$parsed[$key]['Inverse'];
+          }
+
+          /* Check if we want to toggle the expert mode */
+          if(isset($_POST['Toggle_Expert_'.$element_id])){
+            $parsed[$key]['Expert'] = !$parsed[$key]['Expert'];
+          }
+
+          /* Get address part */
+          if(isset($_POST['address_part_'.$element_id])){
+            $ap = $_POST['address_part_'.$element_id];
+
+            if(!isset($address_parts[$ap])){
+              $parsed[$key]['LastError'] = _("Invalid type of address part.") ;
+            }
+            $parsed[$key]['Address_Part'] = $ap;
+          }
+
+          /* Check if match type has changed */
+          if(isset($_POST['matchtype_'.$element_id])){
+            $mt = $_POST['matchtype_'.$element_id];
+
+            if(!isset($match_types[$mt])){
+              $parsed[$key]['LastError'] = _("Invalid match type given.");
+            }
+            if($mt == ":regex"){
+              $this->parent->add_require("regex");
+            }
+            if($mt == ":count"){
+              $this->parent->add_require("comparator-i;ascii-numeric");
+            }
+            $parsed[$key]['Match_type'] = $mt;
+          }
+
+          /* Get the comparator tag, if posted */
+          if(isset($_POST['comparator_'.$element_id])){
+            $cp = $_POST['comparator_'.$element_id];
+
+            if(!isset($comparators[$cp])){
+              $parsed[$key]['LastError'] = _("Invalid operator given.");
+            }
+            $parsed[$key]['Comparator'] = $cp;
+
+            if($cp == "i;ascii-numeric"){
+              $this->parent->add_require("comparator-i;ascii-numeric");
+            }
+          }
+
+          /* In case of :count and :value match types 
+           *  we have a special match operator we should save.
+           */
+          if(in_array($parsed[$key]['Match_type'],array(":value",":count"))){
+            if(isset($_POST['operator_'.$element_id])){
+              $op = $_POST['operator_'.$element_id];
+
+              if(!isset($operators[$op])){
+                $parsed[$key]['LastError'] = _("Please specify a valid operator.");
+              }
+              $parsed[$key]['Match_type_value'] = $op;
+            }
+          }
+
+          /* Get the address fields we should check, they are seperated by , */
+          if(isset($_POST['keys_'.$element_id])){
+            $vls = stripslashes($_POST['keys_'.$element_id]);
+            $tmp = array();
+
+            $tmp2 = split(",",$vls);
+            foreach($tmp2 as $val){
+              $tmp[] = trim($val);
+  
+              if(preg_match("/\"/",$val)){
+                $parsed[$key]['LastError'] = _("Invalid character found in address attribute. Quotes are not allowed here.");
+              }
+            }
+            $parsed[$key]['Key_List'] = $tmp;
+          }
+
+          /* Get the values should check for, they are seperated by , */
+          if(isset($_POST['values_'.$element_id])){
+            $vls = stripslashes($_POST['values_'.$element_id]);
+            $tmp = array();
+
+            $tmp2 = split(",",$vls);
+            foreach($tmp2 as $val){
+              $tmp[] = trim($val);
+              if(preg_match("/\"/",$val)){
+                $parsed[$key]['LastError'] = _("Invalid character found in value attribute. Quotes are not allowed here.");
+              }
+            }
+            $parsed[$key]['Value_List'] = $tmp;
+          }
+          break;
+        }
+        /*******************
+         * TRUE FALSE 
+         *******************/
+
+        case "true" :
+        case "false" : 
+        {
+          $name = 'boolean_'.$element_id;
+          if(isset($_POST[$name])){
+            $key2 = $_POST[$name];
+            
+            if($key != $key2) {
+              $parsed = array($key2 => $key2); 
+            }
+          }
+          break;
+        }
+
+        /*******************
+         * Exists 
+         *******************/
+
+        case "exists" :
+        {
+          /* Toggle Inverse ? */
+          if(isset($_POST['toggle_inverse_'.$element_id])){
+            $parsed[$key]['Inverse'] = !$parsed[$key]['Inverse'];
+          }
+
+          /* get list of match values */
+          if(isset($_POST['Values_'.$element_id])){
+            $vls = stripslashes($_POST['Values_'.$element_id]);
+            $tmp = array();          
+  
+            $tmp2 = split(",",$vls);
+            foreach($tmp2 as $val){
+              $tmp[] = "\"".trim(preg_replace("/\"/","",$val))."\"";
+            }
+            $parsed['exists']['Values'] = $tmp;
+          }
+          break;
+        }
+
+        /*******************
+         * Size 
+         *******************/
+
+        case "size" :
+        {
+          $Match_types = array( ":over" => _("greater than") ,
+                                ":under" => _("lower than"));
+
+          $Units       = array( "M" => _("Megabyte"),
+                                "K" => _("Kilobyte"),
+                                ""  => _("Bytes"));
+
+          /* Toggle Inverse ? */
+          if(isset($_POST['toggle_inverse_'.$element_id])){
+            $parsed[$key]['Inverse'] = !$parsed[$key]['Inverse'];
+          }
+
+          /* Reset error */
+          $parsed[$key]['LastError'] ="";
+
+          /* Get match type */
+          if(isset($_POST['Match_type_'.$element_id])){
+            $mt = $_POST['Match_type_'.$element_id];
+            if(!isset($Match_types[$mt])){
+              $parsed[$key]['LastError'] = _("Please select a valid match type in the list box below.");
+            }
+            $parsed[$key]['Match_type'] = $mt;
+          }
+
+          /* Get old values */
+          $value = preg_replace("/[^0-9]*$/","",$parsed[$key]['Value_List'][0]);
+          $unit  = preg_replace("/^[0-9]*/","",$parsed[$key]['Value_List'][0]);
+
+          /* Get value */
+          if(isset($_POST['Value_'.$element_id])){
+            $vl = $_POST['Value_'.$element_id];
+         
+            if(!(is_numeric($vl) && preg_match("/^[0-9]*$/",$vl))){
+              $parsed[$key]['LastError'] = _("Only numeric values are allowed here.");
+            }
+            $value = preg_replace("/[^0-9]/","",$vl);
+          }        
+
+          /* Get unit */
+          if(isset($_POST['Value_Unit_'.$element_id])){
+            $ut = $_POST['Value_Unit_'.$element_id];
+       
+            if(!isset($Units[$ut])){
+              $parsed[$key]['LastError'] = _("No valid unit selected");
+            }
+            $unit = $ut;
+          }       
+          $parsed[$key]['Value_List'] = array(); 
+          $parsed[$key]['Value_List'][0] = $value.$unit;
+          break;
+        }
+
+        /*******************
+         * Allof 
+         *******************/
+     
+        case "allof" : 
+        {
+          if(isset($_POST['toggle_inverse_'.$element_id])){
+            $parsed[$key]['Inverse'] = !$parsed[$key]['Inverse'];
+          }
+          foreach($data as $key2 => $dat){
+            if(($key2 === "Inverse") && ($key2 == "Inverse")){
+              continue;
+            }
+            $tmp_data = $this->save_object_recursive($dat, ($id +1),$key2."-".$obj_id);
+            if($tmp_data != false){
+              $parsed[$key][$key2] = $tmp_data;
+            }else{
+              unset( $parsed[$key][$key2]);
+            }
+          }
+          break ;
+        } 
+
+        /*******************
+         * Anyof 
+         *******************/
+     
+        case "anyof" : 
+        {
+          if(isset($_POST['toggle_inverse_'.$element_id])){
+            $parsed[$key]['Inverse'] = !$parsed[$key]['Inverse'];
+          }
+          foreach($data as $key2 => $dat){
+            if(($key2 === "Inverse") && ($key2 == "Inverse")){
+              continue;
+            }
+            $tmp_data = $this->save_object_recursive($dat, ($id +1),$key2."-".$obj_id);
+            if($tmp_data != false){
+              $parsed[$key][$key2] = $tmp_data;
+            }else{
+              unset( $parsed[$key][$key2]);
+            }
+          }
+          break ;
+        } 
+      }
+    } 
+    return($parsed);
+  }  
+
+
+  /* Return html element for IF */ 
+  function execute()
+  {
+    /* Create title */
+    $name  = "<img alt='' src='images/small_filter.png' class='center'>";
+    $name .= "<b>"._("Condition")."</b>";
+    if($this->TYPE == "if"){
+      $name .= "&nbsp;-&nbsp;"._("If");
+    }elseif($this->TYPE == "elsif"){
+      $name .= "&nbsp;-&nbsp;"._("Else If");
+    }else{
+      $name .= "&nbsp;-&nbsp;"._("Else");
+    }
+
+    $smarty = get_smarty();
+    $smarty->assign("ID", $this->object_id);
+
+    /* Get navigation element container */
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+
+    $smarty->assign("Name", $name);
+    $smarty->assign("Contents", $this->get_as_html());
+
+    if($this->TYPE == "if"){
+      $object = $smarty->fetch(get_template_path("templates/element_if.tpl",TRUE,dirname(__FILE__)));
+    }else{
+      $object = $smarty->fetch(get_template_path("templates/element_elsif.tpl",TRUE,dirname(__FILE__)));
+    }
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+
+  
+  /* Returns all elements as html */
+  function get_as_html($parsed = NULL,$id = 1,$obj_id=1)
+  {
+    $ret ="";
+    if($parsed == NULL){
+      $parsed = $this->_parsed;
+    }
+
+    if((!is_array($parsed)) || !count($parsed)) {
+      $smarty = get_smarty();
+      $smarty->assign("ID",$this->object_id);
+      $smarty->assign("DisplayAdd",TRUE);
+      $smarty->assign("DisplayDel",FALSE);
+      $str = $smarty->fetch(get_template_path("templates/object_test_container.tpl",TRUE,dirname(__FILE__)));
+      $ret .= preg_replace("/%%OBJECT_CONTENT%%/",_("Empty"),$str);
+      return($ret);
+    }
+
+    /* Walk through all elements */
+    foreach($parsed as $key => $data){
+
+      /* Create Inverse Tag */
+      if(is_array($data) && isset($data['Inverse']) && $data['Inverse']){
+        $Inverse = TRUE;
+      }else{
+        $Inverse = FALSE;
+      }
+
+      /* Id used to have unique html names */
+      $element_id = $this->object_id."_".$id."_".$obj_id;
+
+      /* Create elements */
+      switch($key)
+      {
+  
+        /*******************
+         * TRUE FALSE 
+         *******************/
+
+        case "true" :
+        case "false" : 
+        { 
+          /* Inverse element if required */
+          if($Inverse){        
+            if($key == "true"){
+              $key = "false";
+            }else{
+              $key = "true";
+            }           
+          }
+
+          /* Get template */
+          $smarty = get_smarty();
+          $smarty->assign("values"    , array("false" => _("False"), "true" => _("True")));
+          $smarty->assign("selected"  , $key); 
+          $smarty->assign("ID"  , $element_id); 
+          $ret .= $smarty->fetch(get_template_path("templates/element_boolean.tpl",TRUE,dirname(__FILE__)));
+          break;
+        }
+
+
+        /*******************
+         * Header 
+         *******************/
+
+        case "header": 
+        {
+          $address_parts = $this->address_parts;
+          $comparators   = $this->comparators;
+          $match_types   = $this->match_types; 
+          $operators     = $this->operators;
+
+          $smarty = get_smarty();
+          $smarty->assign("comparators",$comparators);
+          $smarty->assign("match_types",$match_types);
+          $smarty->assign("operators",$operators);
+          $smarty->assign("LastError",$data['LastError']);
+          $smarty->assign("match_type", $data['Match_type']);
+          $smarty->assign("operator"  , preg_replace("/\"/","",$data['Match_type_value']));
+          $smarty->assign("comparator", preg_replace("/\"/","",$data['Comparator']));
+
+          $keys = "";
+          foreach($data['Key_List'] as $key){
+            $keys .= $key.", ";
+          }
+          $keys = preg_replace("/,$/","",trim($keys));
+   
+          $values = "";
+          foreach($data['Value_List'] as $key){
+            $values .= $key.", ";
+          }
+          $values = preg_replace("/,$/","",trim($values));
+
+          $smarty->assign("keys",$keys);
+          $smarty->assign("Inverse",$Inverse);
+          $smarty->assign("values",$values);
+          $smarty->assign("Expert", $data['Expert']);
+          $smarty->assign("ID"  , $element_id); 
+          $ret .= $smarty->fetch(get_template_path("templates/element_header.tpl",TRUE,dirname(__FILE__)));
+          break;
+        }
+
+
+        /*******************
+         * Envelope 
+         *******************/
+
+        case "envelope":
+        {
+          $address_parts = $this->address_parts;
+          $comparators   = $this->comparators;
+          $match_types   = $this->match_types; 
+          $operators     = $this->operators;
+
+          $smarty = get_smarty();
+          $smarty->assign("Inverse",$Inverse);
+          $smarty->assign("comparators",$comparators);
+          $smarty->assign("Expert", $data['Expert']);
+          $smarty->assign("match_types",$match_types);
+          $smarty->assign("operators",$operators);
+          $smarty->assign("LastError",$data['LastError']);
+          $smarty->assign("match_type", $data['Match_type']);
+          $smarty->assign("operator"  , preg_replace("/\"/","",$data['Match_type_value']));
+          $smarty->assign("comparator", preg_replace("/\"/","",$data['Comparator']));
+
+          $keys = "";
+          foreach($data['Key_List'] as $key){
+            $keys .= $key.", ";
+          }
+          $keys = preg_replace("/,$/","",trim($keys));
+
+          $values = "";
+          foreach($data['Value_List'] as $key){
+            $values .= $key.", ";
+          }
+          $values = preg_replace("/,$/","",trim($values));
+          $smarty->assign("keys",$keys);
+          $smarty->assign("values",$values);
+
+          $smarty->assign("ID"  , $element_id); 
+          $ret .= $smarty->fetch(get_template_path("templates/element_envelope.tpl",TRUE,dirname(__FILE__)));
+          break;
+        }
+
+
+        /*******************
+         * Address 
+         *******************/
+
+        case "address" : 
+        {
+          $address_parts = $this->address_parts;
+          $comparators   = $this->comparators;
+          $match_types   = $this->match_types; 
+          $operators     = $this->operators;
+
+          $smarty = get_smarty();
+          $smarty->assign("Inverse",$Inverse);
+          $smarty->assign("address_parts",$address_parts);
+          $smarty->assign("comparators",$comparators);
+          $smarty->assign("match_types",$match_types);
+          $smarty->assign("LastError",$data['LastError']);
+          $smarty->assign("operators",$operators);
+          $smarty->assign("match_type", $data['Match_type']);
+          $smarty->assign("operator"  , preg_replace("/\"/","",$data['Match_type_value']));
+          $smarty->assign("comparator", preg_replace("/\"/","",$data['Comparator']));
+          $smarty->assign("address_part", $data['Address_Part']);
+          $smarty->assign("Expert", $data['Expert']);
+        
+          $keys = "";
+          foreach($data['Key_List'] as $key){
+            $keys .= $key.", ";
+          }
+          $keys = preg_replace("/,$/","",trim($keys));
+   
+          $values = "";
+          foreach($data['Value_List'] as $key){
+            $values .= $key.", ";
+          }
+          $values = preg_replace("/,$/","",trim($values));
+
+          $smarty->assign("keys",$keys);
+          $smarty->assign("values", $values);
+          $smarty->assign("ID"  , $element_id); 
+          $str = $smarty->fetch(get_template_path("templates/element_address.tpl",TRUE,dirname(__FILE__)));
+          $ret .= $str;
+          break;
+        }
+      
+
+        /*******************
+         * Size 
+         *******************/
+        
+        case "size" : 
+        {
+          $Match_types = array( ":over" => _("greater than") , 
+                                ":under" => _("lower than"));
+
+          $Units       = array( "M" => _("Megabyte"),
+                                "K" => _("Kilobyte"),
+                                ""  => _("Bytes"));
+
+          $Match_type   = $data['Match_type'];
+          $Value        = preg_replace("/[^0-9]/","",$data['Value_List'][0]);
+          $Value_Unit   = preg_replace("/[0-9]/","",$data['Value_List'][0]);
+       
+          $LastError = "";
+          if(isset($data['LastError'])){
+            $LastError = $data['LastError'];
+          }
+          $smarty = get_smarty();
+          $smarty->assign("Inverse",$Inverse);
+          $smarty->assign("LastError",$LastError);
+          $smarty->assign("Match_types",$Match_types);
+          $smarty->assign("Units",$Units);
+          $smarty->assign("Match_type",$Match_type);
+          $smarty->assign("Value",$Value);
+          $smarty->assign("Value_Unit",$Value_Unit);
+          $smarty->assign("ID"  , $element_id); 
+          $ret .= $smarty->fetch(get_template_path("templates/element_size.tpl",TRUE,dirname(__FILE__)));
+          break;
+        }
+        
+        /*******************
+         * Exists 
+         *******************/
+        
+        case "exists" : 
+        {
+          $LastError = "";
+          if(isset($data['LastError'])){
+            $LastError = $data['LastError'];
+          }
+          $Values = "";
+          foreach($data['Values'] as $val){
+            $Values .= $val.", ";
+          }
+          $Values = preg_replace("/,$/","",trim($Values));
+
+          $smarty = get_smarty();
+          $smarty->assign("LastError",$LastError);
+          $smarty->assign("Values",$Values);
+          $smarty->assign("Inverse",$Inverse);
+          $smarty->assign("ID"  , $element_id); 
+          $ret .= $smarty->fetch(get_template_path("templates/element_exists.tpl",TRUE,dirname(__FILE__)));
+          break;
+        }
+  
+
+        /*******************
+         * All of   
+         *******************/
+
+        case "allof" : 
+        {
+          $Contents = ""; 
+          foreach($data as $key => $dat){
+            if(($key === "Inverse") && ($key == "Inverse")){
+              continue;
+            }
+            $Contents .=        $this->get_as_html($dat, ($id +1),$key."-".$obj_id);
+          }
+
+          $smarty = get_smarty();
+          $smarty->assign("ID"  , $element_id); 
+          $smarty->assign("DisplayAdd",TRUE);
+          $smarty->assign("DisplayDel",FALSE);
+          $cont_tmp = $smarty->fetch(get_template_path("templates/object_test_container.tpl",TRUE,dirname(__FILE__)));
+          $cont_tmp = preg_replace("/%%OBJECT_CONTENT%%/","<b>"._("Click here to add a new test")."</b>",$cont_tmp);
+
+          $smarty->assign("Inverse",$Inverse);
+          $smarty->assign("Contents",$cont_tmp.$Contents);
+          $smarty->assign("ID"  , $element_id); 
+          $allof_tmp = $smarty->fetch(get_template_path("templates/element_allof.tpl",TRUE,dirname(__FILE__)));
+
+          $ret = $allof_tmp;
+          break ;
+        } 
+
+
+        /*******************
+         * Any of   
+         *******************/
+
+        case "anyof" : 
+        {
+          $Contents = ""; 
+          foreach($data as $key => $dat){
+            if(($key === "Inverse") && ($key == "Inverse")){
+              continue;
+            }
+            $Contents .=        $this->get_as_html($dat, ($id +1),$key."-".$obj_id);
+          }
+          $smarty = get_smarty();
+          $smarty->assign("ID"  , $element_id); 
+          $smarty->assign("DisplayAdd",TRUE);
+          $smarty->assign("DisplayDel",FALSE);
+          $cont_tmp = $smarty->fetch(get_template_path("templates/object_test_container.tpl",TRUE,dirname(__FILE__)));
+          $cont_tmp = preg_replace("/%%OBJECT_CONTENT%%/",_("Click here to add a new test"),$cont_tmp);
+
+          $smarty->assign("Inverse",$Inverse);
+          $smarty->assign("Contents",$cont_tmp.$Contents);
+          $allof_tmp = $smarty->fetch(get_template_path("templates/element_anyof.tpl",TRUE,dirname(__FILE__)));
+
+          $ret = $allof_tmp;
+
+          break ;
+        } 
+        default : 
+        {
+          trigger_error(_("Unhandled switch type"));
+        }
+      }
+    }
+    
+    if(!isset($smarty)){
+      $smarty =get_smarty();
+    }
+
+    $smarty->assign("ID",$element_id);
+    $smarty->assign("DisplayAdd",FALSE);
+    $smarty->assign("DisplayDel",TRUE);
+    $str = $smarty->fetch(get_template_path("templates/object_test_container.tpl",TRUE,dirname(__FILE__)));
+    $ret = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($ret,"\\"),$str);
+    return($ret);
+  }
+
+
+  /* Parse given token identified by $data[$id] 
+   *  and return the parsed tokens. 
+   */
+  function _parse($data,$id = 0)
+  {
+    $av_match_type = array();
+    foreach($this->match_types as $name => $description){
+      $av_match_type[] = $name;
+    }
+    $av_match_type[] = ":over";
+    $av_match_type[] = ":under";
+
+
+
+    $av_methods= array("address","allof","anyof","exists","false","header","not","size","true","envelope");
+    $type = $data[$id]['text'];
+    $tmp = array();
+
+    /* Is there an identifier named 'not' to inverse this filter ? */
+    $Inverse = FALSE;
+    if($data[$id]['class'] == "identifier" && $data[$id]['text'] == "not"){
+      $Inverse = TRUE;
+      $id ++;
+      $type = $data[$id]['text'];
+    }
+
+    switch($type)
+    {
+
+      /****************
+       * Parse - Envelope / Header / Address
+       ****************/ 
+
+      case "envelope" : 
+      case "header":
+      case "address" : 
+      {
+        /* Address matches are struckture as follows :
+           [not] 
+           address 
+                  [address-part: tag]           all|localpart|domain|user|detail
+                  [comparator: tag]             i;octet i;ascii-casemap i;ascii-numeric
+                  [match-type: tag]             is|contains|matches|count|value 
+                  <header-list: string-list> 
+                  <key-list: string-list>   
+          */ 
+   
+        
+        $part     = "(:all|:localpart|:domain)";
+        $operator = "(:regex|:contains|:is|:matches|:count|:value)";
+        $value_op = "(lt|le|eq|ge|gt|ne)";
+
+        $Address_Part     = "";
+        $Comparator       = "";        
+        $Match_type       = "";    
+        $Match_type_value = "";
+  
+        $Key_List         = array();
+        $Value_List       = array();
+  
+        for($i = 0 ; $i < count($data) ; $i ++){
+         
+          /* Get next node */ 
+          $node = $data[$i];
+  
+          /* Check address part definition */
+          if($node['class'] == "tag" && preg_match("/".$part."/i",$node['text'])){
+            $Address_Part = $node['text'];
+          }
+
+          /* Check for match type  */
+          elseif($node['class'] == "tag" && preg_match("/".$operator."/i",$node['text'])){
+            $Match_type = $node['text'];
+
+            /* Get value operator */
+            if(in_array($Match_type,array(":value",":count"))){
+              $i ++;        
+              $node = $data[$i];
+
+              if($node['class'] == "quoted-string" && preg_match("/".$value_op."/",$node['text'])){
+                $Match_type_value = $node['text'];
+              }
+            }
+          } 
+
+          /* Check for a comparator */
+          elseif($node['class'] == "tag" && preg_match("/comparator/",$node['text'])){
+            $i ++;
+            $node = $data[$i];
+            $Comparator = $node['text'];
+          }
+  
+          /* Check for Key_List */  
+          elseif(count(sieve_get_strings($data,$i))){
+            $tmp2 = sieve_get_strings($data,$i);
+            $i =  $tmp2['OFFSET'];
+
+            if(!count($Key_List)){
+              $Key_List = $tmp2['STRINGS'];
+            }else{
+              $Value_List = $tmp2['STRINGS']; 
+            }
+          } 
+      
+        }
+         
+        /* Add to Tree */ 
+        $values = array( "Inverse"         => $Inverse,
+                                "Comparator"      => $Comparator,
+                                "Expert"          => FALSE,
+                                "Match_type"      => $Match_type,
+                                "Match_type_value"=> $Match_type_value,
+                                "Key_List"        => $Key_List,
+                                "Value_List"      => $Value_List) ;
+        if($type == "address"){
+          $values["Address_Part"]    = $Address_Part;
+        }
+        $tmp[$type] = $values;
+        $tmp[$type]['LastError'] = "";
+        break;
+      }
+
+
+      /****************
+       * Parse - Size
+       ****************/ 
+
+      case "size":
+      {
+    
+        $ops = "(:over|:under)";
+
+        $Match_type = "";
+
+        for($i = $id ; $i < count($data); $i++){
+
+          /* Get current node */
+          $node = $data[$i];
+
+          /* Get tag (under / over) */
+          if($node['class'] == "tag" && preg_match("/".$ops."/",$node['text'])){
+            $Match_type = $node['text'];
+          }
+          
+          /* Get Value_List, the value that we want to match for */
+          elseif(count(sieve_get_strings($data,$i))){
+            $tmp2 = sieve_get_strings($data,$i);
+            $i =  $tmp2['OFFSET'];
+          
+            $Value_List = $tmp2['STRINGS'];
+          } 
+        }        
+    
+        $tmp[$type]= array( "Inverse"    => $Inverse,
+                            "Match_type" => $Match_type,
+                            "Value_List" => $Value_List);
+        $tmp[$type]['LastError'] = "";
+        break;
+      }
+
+
+      /****************
+       * Parse - True / False
+       ****************/ 
+
+      case "true": 
+      {
+        $tmp['true'] = "true";
+        $tmp['true']['LastError'] = "";
+        break;
+      }
+      case "false":
+      {
+        $tmp['false'] = "false";
+        $tmp['false']['LastError'] = "";
+        break;
+      }
+
+
+      /****************
+       * Parse - Exists
+       ****************/ 
+
+      case "exists":
+      {
+        
+        /* Skip first values, [if,not,exists] */
+        $node = $data[$id];
+        while(in_array($node['text'],array("if","not","exists"))){
+          $id ++;
+          $node = $data[$id];
+        }
+
+        /* Get values */
+        $tmp2 = sieve_get_strings($data,$id);
+  
+        
+        $tmp['exists'] = array('Inverse' => $Inverse,
+                               'Values'  => $tmp2['STRINGS']);
+        $tmp[$type]['LastError'] = "";
+        break;
+      }
+
+
+      /****************
+       * Parse - Allof
+       ****************/ 
+
+      case "allof" :
+      {
+        /* Get parameter and recursivly call this method 
+         *  for each parameter 
+         */
+        $id ++;
+        $tmp2 = $this->get_parameter($data,$id);
+        
+        foreach($tmp2 as $parameter){
+          $tmp['allof'][] = $this->_parse($parameter);
+        }
+        $tmp['allof']['Inverse'] = $Inverse;
+        break;
+      }
+
+
+      /****************
+       * Parse - Anyof
+       ****************/ 
+
+      case "anyof" :
+      {
+        /* Get parameter and recursivly call this method 
+         *  for each parameter 
+         */
+        $id ++;
+        $tmp2 = $this->get_parameter($data,$id);
+
+        foreach($tmp2 as $parameter){
+          $tmp['anyof'][] = $this->_parse($parameter);
+        }
+        $tmp['anyof']['Inverse'] = $Inverse;
+        break;
+      }
+      default : $tmp[$id] = $type; 
+    }
+    
+    return($tmp); 
+  }
+
+
+  function get_parameter($data,$id)
+  {
+    $par = array();
+    $open_brakets = 0;
+    $next = NULL;
+    $num = 0;
+    for($i = $id ; $i < count($data) ; $i++ ){
+      if(in_array($data[$i]['class'],array("left-parant","left-bracket"))){
+        $open_brakets ++;
+      }
+      if($data[$i]['class'] == "comma" && $open_brakets == 1){
+        $num ++;
+      }
+      if(!in_array($data[$i]['class'],array("comma","left-parant","right-parant")) || $open_brakets >1 ){
+        $par[$num][] = $data[$i];
+      }
+      if(in_array($data[$i]['class'],array("right-parant","right-bracket"))){
+        $open_brakets --;
+      }
+    }
+    return($par);
+  }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Keep.inc b/include/sieve/class_sieveElement_Keep.inc
new file mode 100644 (file)
index 0000000..3e1d58e
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+/* This class handles the keep statement */
+class sieve_keep 
+{
+  var $object_id = -1;
+
+  function sieve_keep($data,$object_id)
+  {
+    $this->object_id = $object_id;
+  }
+
+  function save_object()
+  {
+  }
+
+  function check()
+  {
+    return(array());
+  }
+
+  function execute()
+  {
+    $smarty = get_smarty();
+    $smarty->assign("ID", $this->object_id);
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+    $object = $smarty->fetch(get_template_path("templates/element_keep.tpl",TRUE,dirname(__FILE__)));
+    $str = preg_replace("/%%OBJECT_CONTENT%%/", addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+  function get_sieve_script_part()
+  {
+    return("keep;");
+  } 
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Redirect.inc b/include/sieve/class_sieveElement_Redirect.inc
new file mode 100644 (file)
index 0000000..56f55cf
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+class sieve_redirect 
+{
+  var $data = "";
+  var $object_id = -1;
+  var $LastError   ="";
+  
+  function save_object()
+  {
+    if(isset($_POST['redirect_to_'.$this->object_id])){
+      $rt = stripslashes($_POST['redirect_to_'.$this->object_id]);
+
+      $rt = trim($rt);
+      $this->data = $rt;
+    }
+  }
+
+
+  function check()
+  {
+    $msgs = array();
+    
+    if(!is_email($this->data)){
+      $msgs[] =_("Please specify a valid email address.");
+    }
+    
+    return($msgs);
+  }
+
+  function sieve_redirect($data,$object_id)
+  {
+    $this->object_id = $object_id;
+
+    if($data == NULL){
+      $data = array('ELEMENTS' => array(array('class' => "quoted-string" ,"text" => _("Put a mail address here"))));
+    }
+
+    for($i = 0 ; $i < count($data['ELEMENTS']) ; $i++){
+      $tmp = sieve_get_strings($data['ELEMENTS'],$i);
+      $i  = $i + $tmp['OFFSET'];
+      foreach($tmp['STRINGS'] as $str){
+        $this->data .= $str;
+      }
+    }
+  }
+
+
+  function get_sieve_script_part()
+  {
+    return("redirect ".sieve_create_strings($this->data).";");
+  } 
+   
+  function execute()
+  {
+    $values = htmlentities($this->data);
+    $smarty = get_smarty();
+    $smarty->assign("ID", $this->object_id);
+    $smarty->assign("Destinations" , $values);
+    $smarty->assign("LastError" , $this->check());
+    $smarty->assign("LastErrorCnt" , count($this->check()));
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+    $object= $smarty->fetch(get_template_path("templates/element_redirect.tpl",TRUE,dirname(__FILE__)));
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+}
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Reject.inc b/include/sieve/class_sieveElement_Reject.inc
new file mode 100644 (file)
index 0000000..baa1004
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+
+class sieve_reject 
+{
+  var $data = "";
+  var $object_id = -1;
+  var $parent = NULL;
+
+  function save_object()
+  {
+    if(isset($_POST['reject_message_'.$this->object_id])){
+      $msg = stripslashes($_POST['reject_message_'.$this->object_id]);
+      $this->data = $msg;
+    }
+  }
+
+  function check()
+  {
+    $msgs = array();
+    if(preg_match("/\"/",$this->data)){
+      $msgs [] = _("Invalid character found, quotes are not allowed in a reject message.");
+    }
+    return($msgs);
+  }
+
+  function sieve_reject($data,$object_id,$parent)
+  {
+    $this->object_id = $object_id;
+    $this->parent = $parent;
+    $this->parent->add_require("reject");
+
+    /* If the given data is emtpy 
+     *  (This is the case when we add new elements in the ui) 
+     * Set a default text. 
+     */
+    if($data == NULL){
+      $this->data = _("Your reject text here");
+    }else{
+
+      for($i = 0 ; $i < count($data['ELEMENTS']) ; $i++){
+        $tmp = sieve_get_strings($data['ELEMENTS'],$i);
+        $i  = $i + $tmp['OFFSET'];
+        foreach($tmp['STRINGS'] as $str){
+          $this->data .= $str;
+        }
+      }
+    }
+  }
+
+  function get_sieve_script_part()
+  {
+    return("reject ".sieve_create_strings($this->data).";");
+  } 
+
+  function execute()
+  {
+    /* check if this will be a 
+     *   - single string ""
+     *   - or a multi line text: ... ; 
+     */
+    $Multiline = preg_match("/\n/",$this->data);
+
+    $smarty = get_smarty();
+    $smarty->assign("ID", $this->object_id);
+    $smarty->assign("Message",$this->data);
+    $smarty->assign("Multiline",$Multiline);
+    $smarty->assign("LastError" , $this->check());
+    $smarty->assign("LastErrorCnt" , count($this->check()));
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+    $object= $smarty->fetch(get_template_path("templates/element_reject.tpl",TRUE,dirname(__FILE__)));
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+}
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Require.inc b/include/sieve/class_sieveElement_Require.inc
new file mode 100644 (file)
index 0000000..9ef9e29
--- /dev/null
@@ -0,0 +1,109 @@
+<?php
+
+class sieve_require 
+{
+  var $data = array();
+  var $object_id = -1;
+  var $parent = NULL;  
+  var $skip_save_object =FALSE;
+
+  function sieve_require($data,$object_id,$parent)
+  {
+    $this->parent = $parent;
+    $this->object_id = $object_id;
+    if($data != NULL){
+
+      for($i = 0 ; $i < count($data['ELEMENTS']) ; $i++){
+        $tmp = sieve_get_strings($data['ELEMENTS'],$i);
+        $i  = $i + $tmp['OFFSET'];
+        foreach($tmp['STRINGS'] as $str){
+          $this->data[]= $str;
+        }
+      }
+    }
+  }
+
+
+  /* Add a new require statement and ensure 
+   *  that it is not specified twice 
+   */
+  function Add_Require($str)
+  {
+    $current = array();
+    foreach($this->data as $dat){
+      $current[] = $dat;
+    }
+    if(!in_array($str,$current)){
+      $this->data[] = $str;
+    }
+    $this->data = array_unique($this->data);
+    $this->skip_save_object = TRUE;
+  }
+
+  function save_object()
+  {
+    if($this->skip_save_object){
+      $this->skip_save_object = FALSE;
+      return;
+    }
+
+    /* Get the values should check for, they are seperated by , */
+    if(isset($_POST['require_'.$this->object_id])){
+      $vls = stripslashes($_POST['require_'.$this->object_id]);
+      $tmp = array();
+
+      $tmp2 = split(",",$vls);
+      foreach($tmp2 as $val){
+        
+        $val = trim($val);
+    
+        if(empty($val)) continue;        
+  
+        $tmp[] = $val;
+      }
+      $this->data = $tmp;
+    }
+  }
+
+  function check()
+  {
+    $msgs = array();
+  
+    if(!count($this->data)){
+      $msgs[] = _("Please specify at least one valid requirement.");
+    }
+    return($msgs);
+  }
+
+  function get_sieve_script_part()
+  {
+    if(count($this->data)){
+    $tmp = sieve_create_strings($this->data);
+    return("require ".$tmp.";\n");
+    }else{
+      return("");
+    }
+  } 
+    
+  function execute()
+  {
+    $Require = "";
+    foreach($this->data as $key){
+      $Require .= $key.", ";
+    }
+    $Require = preg_replace("/,$/","",trim($Require));
+
+    $smarty = get_smarty();
+    $smarty->assign("Require",$Require);
+    $tmp = $this->check();
+    $smarty->assign("LastError",$tmp);
+    $smarty->assign("LastErrorCnt",count($tmp));
+    $smarty->assign("ID", $this->object_id);
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+    $object= $smarty->fetch(get_template_path("templates/element_require.tpl",TRUE,dirname(__FILE__)));
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+}
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Stop.inc b/include/sieve/class_sieveElement_Stop.inc
new file mode 100644 (file)
index 0000000..9acc72b
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+/* This class handles the stop statement */
+class sieve_stop 
+{
+  var $object_id = -1;
+
+  function sieve_stop($data,$object_id)
+  {
+    $this->object_id = $object_id;
+  }
+
+  function save_object()
+  {
+  }
+
+  function check()
+  {
+    return(array());
+  }
+
+  function execute()
+  {
+    $smarty = get_smarty();
+    $smarty->assign("ID", $this->object_id);
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+    $object= $smarty->fetch(get_template_path("templates/element_stop.tpl",TRUE,dirname(__FILE__)));
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+
+  function get_sieve_script_part()
+  {
+    return("stop; \n");
+  } 
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_sieveElement_Vacation.inc b/include/sieve/class_sieveElement_Vacation.inc
new file mode 100644 (file)
index 0000000..a6a7e07
--- /dev/null
@@ -0,0 +1,179 @@
+<?php
+
+class sieve_vacation 
+{
+  var $days     = FALSE;
+  var $subject  = FALSE;
+  var $from     = "";
+  var $mime     = "";
+  var $handle   = "";
+  var $reason   = "\"I am not available, currently.\"";
+  var $addresses= array();
+  var $object_id= -1;
+  var $Expert   = FALSE;
+  var $parent   = NULL;
+
+  function sieve_vacation($data,$object_id,$parent)
+  {
+    $this->parent = $parent;
+    $this->object_id = $object_id;
+    $this->parent->add_require("vacation");
+
+    /* Usage:   vacation [":days" number] [":subject" string]
+       [":from" string] [":addresses" string-list]
+       [":mime"] [":handle" string] <reason: string> */
+
+    /* Not all attribute types are supported by the sieve class right now */
+    $known_attrs = array(":days",":subject",":from",":mime",":handle");
+
+    /* skip if empty */
+    if(($data == NULL) || !is_array($data)) return;
+
+    /* Walk through elements */
+    $p = count($data['ELEMENTS']);
+    for($i = 0 ; $i < $p ; $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[] =  preg_replace("/\"/i","",$data['ELEMENTS'][$i]['text']);
+        }
+      }
+
+      /* Add the vacation message */
+      if(in_array($node['class'],array("quoted-string","multi-line"))){
+
+        $tmp = sieve_get_strings($data['ELEMENTS'],$i);
+        $strs= $tmp['STRINGS'];
+        $data = ""; 
+        foreach($strs as $str){
+          $data .= $str;
+        }
+        $this->reason = $data;
+      }
+    }
+  }
+
+  function get_sieve_script_part()
+  {
+    $str = "vacation ";
+    if($this->days){
+      $str.= ":days ".$this->days;
+    }
+
+    if(count($this->addresses)){
+      $str .= ":addresses ".sieve_create_strings($this->addresses);
+      if($this->subject){
+        $str.= ":subject ".sieve_create_strings($this->subject);
+      }
+    }
+    if($this->mime){
+      $str.= ":mime ".sieve_create_strings($this->mime);
+    }
+  
+    /* Append reason and ensure that this will be 
+     *  handled as multiline text element 
+     *  by adding a "\n" new line 
+     */
+    $str .= "\n ".sieve_create_strings($this->reason."\n");
+    return($str." ; \n");
+  }
+
+  function save_object()
+  {
+    /* Get release date */
+    if(isset($_POST['vacation_release_'.$this->object_id])){
+      $this->days = stripslashes($_POST['vacation_release_'.$this->object_id]);
+    }
+
+    /* Check if we want to toggle the expert mode */
+    if(isset($_POST['Toggle_Expert_'.$this->object_id])){
+      $this->Expert = !$this->Expert;
+    }
+
+    /* Get release date */
+    if(isset($_POST['vacation_receiver_'.$this->object_id])){
+      $vr = stripslashes ($_POST['vacation_receiver_'.$this->object_id]);
+      $tmp = array();
+      $tmp2 = split(",",$vr);
+      foreach($tmp2 as $val){
+        $ad = trim($val);
+        if(!empty($ad)){
+          $tmp[] = $ad;
+        }
+      }
+      $this->addresses = $tmp;
+    }
+
+    /* Get reason */
+    if(isset($_POST['vacation_reason_'.$this->object_id])){
+      $vr = stripslashes ($_POST['vacation_reason_'.$this->object_id]);
+      $this->reason = trim($vr);
+    }
+  }
+
+  function check()
+  {
+    $msgs = array();
+    $err = FALSE;
+    foreach($this->addresses as $addr){
+      if(!is_email($addr)){
+        $err = true;
+      }
+    }
+    if($err){
+      $msgs[] = _("Alternative sender addresse must be valid email addresses.");
+    }
+    return($msgs);
+  }
+
+  function execute()
+  {
+    $Addresses = "";
+    foreach($this->addresses as $key){
+      $Addresses .= $key.", ";
+    }
+    $Addresses = preg_replace("/,$/","",trim($Addresses));
+
+    $smarty = get_smarty();
+    $smarty->assign("LastError",$this->check());
+    $smarty->assign("LastErrorCnt",count($this->check()));
+    $smarty->assign("Reason",$this->reason);
+    $smarty->assign("Addresses",$Addresses);
+    $smarty->assign("Subject",$this->subject);
+    $smarty->assign("Days",$this->days);
+    $smarty->assign("ID",$this->object_id);
+    $smarty->assign("Expert",$this->Expert);
+
+    $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__)));
+    $object= $smarty->fetch(get_template_path("templates/element_vacation.tpl",TRUE,dirname(__FILE__)));
+    $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container);
+    return($str);
+  }
+}
+
+// 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 (file)
index 0000000..6ac3c6e
--- /dev/null
@@ -0,0 +1,1056 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2003-2007 - Fabian Hickert <hickert@gonicus.de>
+
+   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
+ */
+
+
+/* The sieve management class displays a list of sieve 
+ *  scripts for the given mail account. 
+ * The account is identified by the parents uid attribute. 
+ *
+ *  $config       The config object
+ *  $dn           The object edited 
+ *  $parent       The parent object that provides the uid attribute 
+ */
+class sieveManagement extends plugin
+{
+  var $parent = NULL;
+  var $scripts= array();  
+  var $uattrib = "uid";
+  var $current_script  = -1;
+  var $current_handler = NULL;
+  var $script_to_delete =-1;
+  var $sieve_handle = NULL; 
+  var $Script_Error = "";
+  var $Sieve_Error = "";
+  var $create_script = FALSE;
+
+  /* To add new elements we need to know 
+   *  Where to add the element              -> add_new_id
+   *  Whould we add above or below this id  -> add_above_below
+   *  What kind of element should we add    -> add_element_type
+   */
+  var $add_new_element    = FALSE;
+  var $add_new_id         = -1;
+  var $add_above_below    = "below";
+  var $add_element_type   = "sieve_comment";
+
+  /* If this variable is TRUE, this indicates that we have the 
+   *  import dialog opened. 
+   */
+  var $Import_Script = FALSE;
+
+  /* Initialize the class and load all sieve scripts 
+   *  try to parse them and display errors 
+   */ 
+  function sieveManagement($config,$dn,$parent,$uattrib)
+  {
+    /* Check given parameter */
+    if(!isset($parent->$uattrib)){
+      trigger_error("Sieve Management implementation error. Parameter 4 must be part of the given parent element.");
+    }
+
+    $this->uattrib = $uattrib;
+    $this->parent = $parent;
+    plugin::plugin($config,$dn);
+
+    /* Get sieve, if this fail abort class initialization */
+    if(!$this->sieve_handle = $this->get_sieve()){
+      return;
+    }
+
+
+    /* Get all sieve scripts names */
+    if($this->sieve_handle->sieve_listscripts()){
+      if (is_array($this->sieve_handle->response)){
+        foreach($this->sieve_handle->response as $key => $name){
+
+          $data = array();
+          $data['NAME'] = $name;
+
+          if($key == "ACTIVE" && $key === "ACTIVE"){
+            $data['ACTIVE'] = TRUE;
+          }else{
+            $data['ACTIVE'] = FALSE;
+          }
+          $this->scripts[] = $data;          
+        }
+      } 
+    }
+
+    /* Get script contents */
+    foreach($this->scripts as $key => $script){
+      $p = new My_Parser($this);
+      $this->sieve_handle->sieve_getscript($script['NAME']);
+
+      $script = "";
+      foreach($this->sieve_handle->response as $line){
+        $script.=$line;
+      }
+
+      $this->scripts[$key]['IS_NEW'] = FALSE;;
+      $this->scripts[$key]['SCRIPT'] = $script;
+      $this->scripts[$key]['ORIG_SCRIPT'] = $script;
+      $this->scripts[$key]['MSG']   = "";
+      $ret = $p->parse($script);
+      if(!$ret){
+        $this->scripts[$key]['STATUS']   = FALSE;
+        $this->scripts[$key]['MODE']    = "Source";
+        $this->scripts[$key]['MSG'] = _("Parse failed")."<font color='red'>".$p->status_text."</font>";
+      }else{
+        $this->scripts[$key]['STATUS']   = TRUE;
+        $this->scripts[$key]['MODE']    = "Structured";
+        $this->scripts[$key]['MSG'] = _("Parse successful");
+      }
+      $this->scripts[$key]['PARSER'] = $p;
+      $this->scripts[$key]['EDITED'] = FALSE;
+    }
+    $this->sieve_handle = $this->sieve_handle;
+  }
+
+
+  /* Return a sieve class handle,
+   *  false if login fails
+   */
+  function get_sieve()
+  {
+    
+    /* Connect to sieve class and try to get all available sieve scripts */
+    if(isset($this->config->data['SERVERS']['IMAP'][$this->parent->gosaMailServer])){
+      $cfg=  $this->config->data['SERVERS']['IMAP'][$this->parent->gosaMailServer];
+      $this->Sieve_Error = "";
+
+      $uattrib = $this->uattrib;
+
+      /* Log into the mail server */
+      $this->sieve_handle= new sieve(
+          $cfg["sieve_server"], 
+          $cfg["sieve_port"], 
+          $this->parent->$uattrib, 
+          $cfg["password"], 
+          $cfg["admin"]);
+
+      /* Try to login */
+      if (!@$this->sieve_handle->sieve_login()){
+        $this->Sieve_Error = $this->sieve_handle->error_raw;
+        return(FALSE);
+      }
+      return($this->sieve_handle);
+    }else{
+      $this->Sieve_Error = sprintf(_("The specified mail server '%s' does not exist within the GOsa configuration."),
+        $this->parent->gosaMailServer);
+      return(FALSE);
+    }
+  }
+
+
+  /* Handle sieve list 
+   */
+  function execute()
+  {
+    /***************
+     * Create a new Script 
+     ***************/
+
+    /* Force opening the add script dialog */
+    if(isset($_POST['create_new_script'])){
+      $this->create_script = TRUE;
+    }
+
+    /* Close add script dialog, without adding a new one */
+    if(isset($_POST['create_script_cancel'])){
+      $this->create_script = FALSE;
+    }
+
+    /* Display create script dialog 
+     *  handle posts, display warnings if specified 
+     *  name is not useable. 
+     * Create a new script with given name
+     */
+    if($this->create_script){
+    
+      /* Set initial name or used posted name if available */
+      $name = "";
+      if(isset($_POST['NewScriptName'])){
+        $name = trim($_POST['NewScriptName']);
+      }
+      /* Check given name */ 
+      $err = false;
+
+      /* Is given name in lower case characters ? */
+      if(isset($_POST['create_script_save'])){
+        if(!strlen($name)){
+          $err =true;
+          print_red(_("You should specify a name for your new script."));
+        }
+        /* Is given name in lower case characters ? */
+        if($name != strtolower($name)){
+          $err =true;
+          print_red(_("Only lower case names are allowed."));
+        }
+
+        /* Only chars are allowed here */
+        if(preg_match("/[^a-z]/i",$name)){
+          $err =true;
+          print_red(_("Only alphabetical characters are allowed in script names."));
+        }
+
+        $tmp = $this->get_used_script_names();
+        if(in_array_ics($name,$tmp)){
+          $err =true;
+          print_red(_("The specified name is already in use."));
+        }
+      }
+
+      /* Create script if everything is ok */
+      if($this->create_script && isset($_POST['create_script_save']) && !$err){
+
+        /* Close dialog */
+        $this->create_script = FALSE;
+
+        /* Script contents to use */
+        $script = "/*New script */".
+                  "stop;";
+
+        /* Create a new parser and initialize default values */
+        $p = new My_Parser($this);
+        $ret = $p->parse($script);
+        $sc['SCRIPT'] = $script;
+        $sc['ORIG_SCRIPT'] = $script;
+        $sc['IS_NEW'] = TRUE;
+        $sc['MSG']   = "";
+        if(!$ret){
+          $sc['STATUS']   = FALSE;
+          $sc['MODE']    = "Source";
+          $sc['MSG'] = _("Parse failed")."<font color='red'>".$p->status_text."</font>";
+        }else{
+          $sc['STATUS']   = TRUE;
+          $sc['MODE']    = "Structured";
+          $sc['MSG'] = _("Parse successful");
+        }
+        $sc['PARSER'] = $p;
+        $sc['EDITED'] = TRUE;
+        $sc['ACTIVE'] = FALSE;
+        $sc['NAME']   = $name;
+      
+        /* Add script */
+        $this->scripts[$name] = $sc;
+      }else{
+      
+        /* Display dialog to enter new script name */
+        $smarty = get_smarty();
+        $smarty->assign("NewScriptName",$name);
+        return($smarty->fetch(get_template_path("templates/create_script.tpl",TRUE,dirname(__FILE__))));
+      }
+    }
+
+
+    /*************
+     * Handle several posts 
+     *************/
+
+    $once = TRUE;
+    foreach($_POST as $name => $value){
+
+      /* Edit script requested */
+      if(preg_match("/^editscript_/",$name) && $once && !$this->current_handler){
+        $script = preg_replace("/^editscript_/","",$name);
+        $script = preg_replace("/_(x|y)/","",$script);
+        $once = FALSE;
+
+        $this->current_script = $script;
+        $this->current_handler = $this->scripts[$script]['PARSER'];
+        $this->scripts[$script]['SCRIPT_BACKUP'] = $this->scripts[$script]['SCRIPT'];
+      }
+
+      /* remove script requested */
+      if(chkacl($this->parent->acl,"sieveManagement") == "" && preg_match("/^delscript_/",$name) && $once && !$this->current_handler){
+        $script = preg_replace("/^delscript_/","",$name);
+        $script = preg_replace("/_(x|y)/","",$script);
+        $once = FALSE;
+        $this->script_to_delete = $script;  
+      }
+
+      /* Activate script */
+      if(chkacl($this->parent->acl,"sieveManagement") == "" && preg_match("/^active_script_/",$name) && $once && !$this->current_handler){
+        $script = preg_replace("/^active_script_/","",$name);
+        $script = preg_replace("/_(x|y)/","",$script);
+        $once = FALSE;
+
+        /* We can only activate existing scripts */
+        if(!$this->scripts[$script]['IS_NEW']){
+
+          /* Get sieve */
+          if(!$this->sieve_handle = $this->get_sieve()){
+            print_red(
+                sprintf(
+                  _("Can't log into SIEVE server. Server says '%s'."),
+                  to_string($this->Sieve_Error)));
+          }
+
+          /* Try to activate the given script and update 
+           *  class script array. 
+           */
+          if(!$this->sieve_handle->sieve_setactivescript($this->scripts[$script]['NAME'])){
+            print_red(sprintf(_("Can't activate sieve script on server. Server says '%s'."),to_string($this->sieve_handle->error_raw)));
+          }else{
+            foreach($this->scripts as $key => $data){
+              if($key == $script){
+                $this->scripts[$key]['ACTIVE'] = TRUE;
+              }else{
+                $this->scripts[$key]['ACTIVE'] = FALSE;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    
+    /*************
+     * Remove script handling 
+     *************/
+
+    /* Remove aborted */
+    if(isset($_POST['delete_cancel'])){
+      $this->script_to_delete = -1;
+    }
+
+    /* Remove confirmed */
+    if(chkacl($this->parent->acl,"sieveManagement") == "" && isset($_POST['delete_script_confirm'])){
+
+      $script = $this->scripts[$this->script_to_delete];
+
+      /* Just remove from array if it is a new script */
+      if($script['IS_NEW']){
+        unset($this->scripts[$this->script_to_delete]);
+      }else{
+
+        /* Get sieve */
+        if(!$this->sieve_handle = $this->get_sieve()){
+          print_red(
+              sprintf(
+                _("Can't log into SIEVE server. Server says '%s'."),
+                to_string($this->Sieve_Error)));
+        }
+
+        if(!$this->sieve_handle->sieve_deletescript($this->scripts[$this->script_to_delete]['NAME'])){
+          print_red(sprintf(_("Can't remove sieve script from server. Server says '%s'."),to_string($this->sieve_handle->error_raw)));
+        }else{
+          unset($this->scripts[$this->script_to_delete]);
+        }
+      }
+      $this->script_to_delete = -1;
+    }
+
+    /* Display confirm dialog */
+    if($this->script_to_delete != -1){
+      $smarty = get_smarty();
+      $smarty->assign("Warning",
+          sprintf(_("You are going to remove the sieve script '%s' from your mail server."),
+            $this->scripts[$this->script_to_delete]['NAME']));
+      return($smarty->fetch(get_template_path("templates/remove_script.tpl",TRUE,dirname(__FILE__))));
+    }
+
+
+    /**************
+     * Save script changes 
+     **************/
+
+    /* Abort saving */
+    if(isset($_POST['cancel_sieve_changes'])){
+      $tmp = $this->scripts[$this->current_script]['SCRIPT_BACKUP'];
+      $this->scripts[$this->current_script]['SCRIPT'] = $tmp;
+      $this->scripts[$this->current_script]['PARSER']->parse($tmp);
+      $this->current_handler = NULL;
+    }
+
+    /* Save currently edited sieve script. */
+    if(chkacl($this->parent->acl,"sieveManagement") == "" && 
+       isset($_POST['save_sieve_changes']) && 
+       is_object($this->current_handler)){
+      $chk = $this->current_handler->check();
+      if(!count($chk)){
+
+        $sc = $this->scripts[$this->current_script]['SCRIPT'];
+        $p = new My_Parser($this);
+        if($p -> parse($sc)){
+
+          if($this->scripts[$this->current_script]['MODE'] == "Source-Only"){
+            $this->scripts[$this->current_script]['MODE'] = "Source";
+          }
+  
+          $this->scripts[$this->current_script]['PARSER'] = $p;
+          $this->scripts[$this->current_script]['EDITED'] = TRUE;
+          $this->scripts[$this->current_script]['STATUS'] = TRUE;
+          $this->scripts[$this->current_script]['MSG'] = _("Edited");
+          $this->current_handler = NULL;
+        }else{
+          print_red($p->status_text);;
+        }
+      }else{
+        foreach($chk as $msgs){
+          print_red(sprintf(_("Please fix all errors before saving. Last error was : %s"),$msgs));
+        }
+      }
+    }
+
+
+    /*************
+     * Display edit dialog 
+     *************/
+
+    /* Display edit dialog, depending on Mode display different uis
+     */
+    if($this->current_handler){
+
+        if(isset($_POST['Import_Script'])){
+          $this->Import_Script = TRUE;
+        }
+
+        if(isset($_POST['Import_Script_Cancel'])){
+          $this->Import_Script = FALSE;
+        }
+
+        if(isset($_POST['Import_Script_Save']) && isset($_FILES['Script_To_Import'])){
+
+          $file     = $_FILES['Script_To_Import'];
+
+          if($file['size'] == 0){
+            print_red(_("Specified file seems to be empty."));
+          }elseif(!file_exists($file['tmp_name'])){
+            print_red(_("Upload failed, somehow nothing was uploaded or the temporary file can't be accessed."));
+          }elseif(!is_readable ($file['tmp_name'])){
+            print_red(sprintf(_("Can't open file '%s' to read uploaded file contents."),$file['tmp_name']));
+          }else{
+            
+            
+            $contents = file_get_contents($file['tmp_name']);
+           
+            $this->scripts[$this->current_script]['SCRIPT'] = $contents;
+            if(!$this->current_handler->parse($contents)){
+              $this->scripts[$this->current_script]['MODE'] = "Source";
+            }else{
+              $this->scripts[$this->current_script]['MODE'] = "Structured";
+            }
+            $this->Script_Error = "";
+            $this->Import_Script = FALSE;
+          }
+        }
+
+        if($this->Import_Script){
+          $smarty = get_smarty();
+          $str = $smarty->fetch(get_template_path("templates/import_script.tpl",TRUE,dirname(__FILE__)));
+          return($str);
+        }
+  
+
+        /* Create dump of current sieve script */
+        if(isset($_POST['Save_Copy'])){
+
+            /* force download dialog */
+            header("Content-type: application/tiff\n");
+            if (preg_match('/MSIE 5.5/', $HTTP_USER_AGENT) ||
+                    preg_match('/MSIE 6.0/', $HTTP_USER_AGENT)) {
+                header('Content-Disposition: filename="dump.script"');
+            } else {
+                header('Content-Disposition: attachment; filename="dump.script"');
+            }
+            header("Content-transfer-encoding: binary\n");
+            header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+            header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
+            header("Cache-Control: no-cache");
+            header("Pragma: no-cache");
+            header("Cache-Control: post-check=0, pre-check=0");
+            echo $this->scripts[$this->current_script]['SCRIPT'];
+            exit();
+        }
+
+
+      /****
+       * Add new element to ui
+       ****/
+
+      /* Abort add dialog */ 
+      if(isset($_POST['select_new_element_type_cancel'])){
+        $this->add_new_element = FALSE;
+      }
+
+      /* Add a new element */
+      if($this->add_new_element){
+
+        $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']]) 
+           || isset($_POST['element_type']) &&in_array($_POST['element_type'],array("sieve_else","sieve_elsif"))){
+          $this->add_element_type = $_POST['element_type'];
+        }
+
+        /* Create new element and add it to
+         *  the selected position 
+         */
+        if(isset($_POST['select_new_element_type'])){
+          if($this->add_new_element_to_current_script($this->add_element_type,$this->add_new_id,$this->add_above_below)){
+            $this->add_new_element = FALSE;
+          }else{
+            print_red(_("Failed to add new element."));
+          }
+        }
+      }
+
+      /* Only display select dialog if it is necessary */
+      if($this->add_new_element){
+        $smarty = get_smarty();
+    
+        $add_else_elsif = FALSE;
+
+        /* Check if we should add else/elsif to the select box 
+         *  or not. We can't add else twice!.
+         */
+        if($this->add_above_below == "below"){
+
+          /* Get posistion of the current element 
+           */
+          foreach($this->current_handler->tree_->pap as $key => $obj){
+        
+            if($obj->object_id == $this->add_new_id && in_array(get_class($obj),array("sieve_if","sieve_elsif"))){
+  
+              /* Get block start/end */
+              $end_id = $this->current_handler->tree_->get_block_end($key);
+              $else_found = FALSE;
+              $elsif_found = FALSE;
+          
+              /* Check if there is already an else in this block 
+               */
+              for($i =  $key ; $i < $end_id ; $i ++){
+                if(get_class($this->current_handler->tree_->pap[$i]) == "sieve_else"){
+                  $else_found = TRUE;
+                }
+                if(get_class($this->current_handler->tree_->pap[$i]) == "sieve_elsif"){
+                  $elsif_found = TRUE;
+                }
+              }
+  
+              /* Only allow adding 'else' if there is currently 
+               *  no 'else' statement. And don't allow adding 
+               *  'else' before 'elseif'
+               */ 
+              if(!$else_found && (!(get_class($obj) == "sieve_if" && $elsif_found))){
+                $element_types['sieve_else'] = _("Else");
+              }
+              $element_types['sieve_elsif'] = _("Else If");
+            }
+          }
+        }
+
+        $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);
+      }
+
+
+
+      /****************
+       * Handle test posts 
+       ****************/
+
+      /* handle some special posts from test elements 
+       */
+      foreach($_POST as $name => $value){
+        if(preg_match("/^Add_Test_Object_/",$name)) {
+          $name = preg_replace("/^Add_Test_Object_/","",$name);
+          $name = preg_replace("/_(x|y)$/","",$name);
+
+          $test_types_to_add = array(
+              "address" =>_("Address"),
+              "header"  =>_("Header"),
+              "envelope"=>_("Envelope"),
+              "size"    =>_("Size"),
+              "exists"  =>_("Exists"),
+              "allof"   =>_("All of"),
+              "anyof"   =>_("Any of"),
+              "true"    =>_("True"),
+              "false"   =>_("False"));
+
+          $smarty = get_smarty();
+          $smarty->assign("ID",$name);
+          $smarty->assign("test_types_to_add",$test_types_to_add);
+          $ret = $smarty->fetch(get_template_path("templates/select_test_type.tpl",TRUE,dirname(__FILE__)));
+          return($ret);
+        }
+      }
+
+      $current = $this->scripts[$this->current_script];
+
+      /* Create html results */
+      $smarty = get_smarty();
+      $smarty->assign("Mode",$current['MODE']);
+      if($current['MODE'] == "Structured"){
+        $smarty->assign("Contents",$this->current_handler->tree_->execute());
+      }else{
+        $smarty->assign("Contents",$current['SCRIPT']);
+      }
+      $smarty->assign("Script_Error",$this->Script_Error);
+      $ret = $smarty->fetch(get_template_path("templates/edit_frame_base.tpl",TRUE,dirname(__FILE__)));
+      return($ret);
+    }
+
+
+    /* Create list of available sieve scripts 
+     */
+    $List = new divSelectBox("sieveManagement");
+    foreach($this->scripts as $key => $script){
+  
+      $edited =  $script['EDITED'];
+      $active =  $script['ACTIVE'];
+      
+      $field1 = array("string" => "&nbsp;",
+                      "attach" => "style='width:20px;'");  
+      if($active){
+        $field1 = array("string" => "<img src='images/true.png' alt='"._("Active")."' 
+                                      title='"._("This script is marked as active")."'>",
+                        "attach" => "style='width:20px;'");  
+      }
+      $field2 = array("string" => $script['NAME']);  
+      $field3 = array("string" => $script['MSG']);
+      $field4 = array("string" => _("Script length").":&nbsp;".strlen($script['SCRIPT']));
+
+      if(chkacl($this->parent->acl,"sieveManagement") == ""){
+        $del = "<input type='image' name='delscript_".$key."' src='images/edittrash.png'
+                  title='"._("Remove script")."'>";
+      }else{
+        $del = "<img src='images/empty' alt=' '>";
+      }
+
+      if($active || $script['IS_NEW'] || chkacl($this->parent->acl,"sieveManagement") != ""){
+        $activate = "<img src='images/empty' alt=' '>";
+      }else{
+        $activate = "<input type='image' name='active_script_".$key."' src='images/true.png'
+                       title='"._("Activate script")."'>";
+      }
+
+      $field6 = array("string" => $activate."<input type='image' name='editscript_".$key."' src='images/edit.png'
+                        title='"._("Edit script")."'>".$del,
+                      "attach" => "style='border-right:0px; width:70px;'");
+      $List->AddEntry(array($field1,$field2,$field3,$field4,$field6)); 
+    }
+
+    $List->SetHeight(400);
+    /* If the uattrib is empty   (Attribute to use for authentification with sieve)
+     *  Display a message that the connection can't be established.
+     */
+    $uattrib = $this->uattrib;
+    $smarty = get_smarty();
+
+    if(!$this->get_sieve()){
+      $smarty->assign("Sieve_Error",sprintf(
+        _("Can't log into SIEVE server. Server says '%s'."),
+          to_string($this->Sieve_Error)));
+    }else{
+      $smarty->assign("Sieve_Error","");
+    }
+
+    $smarty->assign("uattrib_empty",empty($this->parent->$uattrib));
+    $smarty->assign("List",$List->DrawList());
+    return($smarty->fetch(get_template_path("templates/management.tpl",TRUE,dirname(__FILE__))));
+  }
+
+
+  /* Add a new element to the currently opened script editor.
+   * The insert position is specified by 
+   */
+  function add_new_element_to_current_script($type,$id,$position)
+  {
+    /* Test given data */
+    if(!in_array_ics($position,array("above","below"))){
+      trigger_error("Can't add new element with \$position=".$position.". Only 'above','below' are allowed here.");
+      return(FALSE);
+    }
+    if(!is_numeric($id)){
+      trigger_error("Can't add new element, given id is not numeric.");
+      return(FALSE);
+    }
+    $tmp = get_declared_classes();  
+    if(!in_array($type,$tmp)){
+      if(!empty($type)){
+        trigger_error("Can't add new element, given \$class=".$class." does not exists.");
+      }
+      return(FALSE);
+    }
+    if(!is_object($this->current_handler) || get_class($this->current_handler) != "My_Parser"){
+      trigger_error("Can't add new element, there is no valid script editor opened.");
+      return(FALSE);
+    }
+
+    /* These element types are allowed to be added here */
+    $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"));
+
+    /* Check if we should add else/elsif to the select box
+     *  or not. We can't add else twice!.
+     */
+
+    /* Get posistion of the current element
+     */
+    foreach($this->current_handler->tree_->pap as $key => $obj){
+
+      if($obj->object_id == $id && in_array(get_class($obj),array("sieve_if","sieve_elsif"))){
+
+        /* Get block start/end */
+        $end_id = $this->current_handler->tree_->get_block_end($key);
+        $else_found = FALSE;
+        $elsif_found = FALSE;
+
+        /* Check if there is already an else in this block
+         */
+        for($i =  $key ; $i < $end_id ; $i ++){
+          if(get_class($this->current_handler->tree_->pap[$i]) == "sieve_else"){
+            $else_found = TRUE;
+          }
+          if(get_class($this->current_handler->tree_->pap[$i]) == "sieve_elsif"){
+            $elsif_found = TRUE;
+          }
+        }
+
+        if($this->add_above_below == "below"){
+
+          /* Only allow adding 'else' if there is currently
+           *  no 'else' statement. And don't allow adding
+           *  'else' before 'elseif'
+           */
+          if(!$else_found && (!(get_class($obj) == "sieve_if" && $elsif_found))){
+            $element_types['sieve_else'] = _("Else");
+          }
+          $element_types['sieve_elsif'] = _("Else If");
+        }else{
+         
+          /* Allow adding elsif above elsif */ 
+          if(in_array(get_class($obj),array("sieve_elsif"))){
+            $element_types['sieve_elsif'] = _("Else If");
+          }
+        }
+      }
+    }
+
+    if(!isset($element_types[$type])){
+      print_red(sprintf(_("Can't add the specified element at the given position.")));
+      return;
+    }
+
+
+    /* Create elements we should add 
+     * -Some element require also surrounding block elements
+     */
+    $parent = $this->current_handler->tree_;
+    if($this->add_element_type == "sieve_if"){
+      $ele[] = new $this->add_element_type(NULL, preg_replace("/[^0-9]/","",microtime()),$parent);
+      $ele[] = new sieve_block_start(NULL,preg_replace("/[^0-9]/","",microtime()),$parent);
+      $ele[] = new sieve_block_end(NULL,preg_replace("/[^0-9]/","",microtime()),$parent);
+    }elseif($this->add_element_type == "sieve_else"){
+      $ele[] = new sieve_block_end(NULL,preg_replace("/[^0-9]/","",microtime()),$parent);
+      $ele[] = new $this->add_element_type(NULL, preg_replace("/[^0-9]/","",microtime()),$parent);
+      $ele[] = new sieve_block_start(NULL,preg_replace("/[^0-9]/","",microtime()),$parent);
+    }elseif($this->add_element_type == "sieve_elsif"){
+      $ele[] = new sieve_block_end(NULL,preg_replace("/[^0-9]/","",microtime()),$parent);
+      $ele[] = new $this->add_element_type(NULL, preg_replace("/[^0-9]/","",microtime()),$parent);
+      $ele[] = new sieve_block_start(NULL,preg_replace("/[^0-9]/","",microtime()),$parent);
+    }else{
+      $ele[] = new $this->add_element_type(NULL, preg_replace("/[^0-9]/","",microtime()),$parent);
+    }
+
+    /* Get index of the element identified by object_id == $id; 
+     */
+    $index = -1;
+    $data = $this->current_handler->tree_->pap;
+    foreach($data as $key => $obj){
+      if($obj->object_id == $id && $index==-1){
+        $index = $key;
+      }
+    }
+
+    /* Tell to user that we couldn't find the given object 
+     *  so we can't add an element. 
+     */
+    if($index == -1 ){
+      trigger_error("Can't add new element, specified \$id=".$id." could not be found in object tree.");
+      return(FALSE);
+    }
+
+    /* We have found the specified object_id 
+     *  and want to detect the next free position 
+     *  to insert the new element.
+     */
+    if($position == "above"){
+      $direction ="up";
+      $next_free = $this->current_handler->tree_->_get_next_free_move_slot($index,$direction,TRUE);
+    }else{
+      $direction = "down";
+      $next_free = $this->current_handler->tree_->_get_next_free_move_slot($index,$direction,TRUE);
+    }
+    /* This is extremly necessary, cause some objects 
+     *  updates the tree objects ... Somehow i should change this ... 
+     */
+    $data = $this->current_handler->tree_->pap;
+    $start = $end = array();
+
+    if($position == "above"){
+      $start = array_slice($data,0,$next_free);
+      $end   = array_slice($data,$next_free);
+    }else{
+      $start = array_slice($data,0,$next_free+1);
+      $end   = array_slice($data,$next_free+1);
+    }
+
+    $new = array();
+    foreach($start as $obj){
+      $new[] = $obj;
+    }
+    foreach($ele as $el){
+      $new[] = $el;
+    }
+    foreach($end as $obj){
+      $new[] = $obj;
+    }
+    $data= $new;
+    $this->current_handler->tree_->pap = $data;
+    return(TRUE);
+  }
+
+
+
+  function save_object()
+  {
+    if($this->current_handler){
+
+      if(isset($_GET['Add_Object_Top_ID'])){
+        $this->add_new_element    = TRUE;
+        $this->add_new_id         = $_GET['Add_Object_Top_ID'];
+        $this->add_above_below    = "above";
+      }  
+
+      if(isset($_GET['Add_Object_Bottom_ID'])){
+        $this->add_new_element    = TRUE;
+        $this->add_new_id         = $_GET['Add_Object_Bottom_ID'];
+        $this->add_above_below    = "below";
+      }  
+
+      if(isset($_GET['Remove_Object_ID'])){
+        $found_id = -1;
+        foreach($this->current_handler->tree_->pap as $key => $element){
+          if($element->object_id == $_GET['Remove_Object_ID']){
+            $found_id = $key;
+          }
+        }
+        if($found_id != -1 ){
+          $this->current_handler->tree_->remove_object($found_id);  
+        }
+      }  
+      if(isset($_GET['Move_Up_Object_ID'])){
+        $found_id = -1;
+        foreach($this->current_handler->tree_->pap as $key => $element){
+          if($element->object_id == $_GET['Move_Up_Object_ID']){
+            $found_id = $key;
+          }
+        }
+        if($found_id != -1 ){
+          $this->current_handler->tree_->move_up_down($found_id,"up");
+        }
+      }  
+      if(isset($_GET['Move_Down_Object_ID'])){
+        $found_id = -1;
+        foreach($this->current_handler->tree_->pap as $key => $element){
+          if($element->object_id == $_GET['Move_Down_Object_ID']){
+            $found_id = $key;
+          }
+        }
+        if($found_id != -1 ){
+          $this->current_handler->tree_->move_up_down($found_id,"down");
+        }
+      }  
+  
+
+      /* Check if there is an add object requested 
+       */
+      $data = $this->current_handler->tree_->pap;
+      $once = TRUE;
+      foreach($_POST as $name => $value){
+        foreach($data as $key => $obj){
+          if(isset($obj->object_id) && preg_match("/^Add_Object_Top_".$obj->object_id."_/",$name) && $once){
+            $once = FALSE;
+            $this->add_element_type   =  $_POST['element_type_'.$obj->object_id];
+            $this->add_new_element    = FALSE;
+            $this->add_new_id         = $obj->object_id;
+            $this->add_above_below    = "above";
+            $this->add_new_element_to_current_script($this->add_element_type,$this->add_new_id,$this->add_above_below);
+          }
+          if(isset($obj->object_id) && preg_match("/^Add_Object_Bottom_".$obj->object_id."_/",$name) && $once){
+            $once = FALSE;
+            $this->add_element_type   =  $_POST['element_type_'.$obj->object_id];
+            $this->add_new_element    = FALSE;
+            $this->add_new_id         = $obj->object_id;
+            $this->add_above_below    = "below";
+            $this->add_new_element_to_current_script($this->add_element_type,$this->add_new_id,$this->add_above_below);
+          }
+        
+          if(isset($obj->object_id) && preg_match("/^Remove_Object_".$obj->object_id."_/",$name) && $once){
+            $once = FALSE;
+            $this->current_handler->tree_->remove_object($key);
+          }
+          if(isset($obj->object_id) && preg_match("/^Move_Up_Object_".$obj->object_id."_/",$name) && $once){
+            $this->current_handler->tree_->move_up_down($key,"up");
+            $once = FALSE;
+          }
+          if(isset($obj->object_id) && preg_match("/^Move_Down_Object_".$obj->object_id."_/",$name) && $once){
+            $this->current_handler->tree_->move_up_down($key,"down");
+            $once = FALSE;
+          }
+        }
+      }
+
+      /* Skip Mode changes and Parse tests 
+       *  if we are currently in a subdialog 
+       */
+
+      $this->current_handler->save_object();
+      $Mode = $this->scripts[$this->current_script]['MODE'];
+      $skip_mode_change = false;
+      if(in_array($Mode,array("Source-Only","Source"))){
+        if(isset($_POST['script_contents'])){
+          $sc = stripslashes($_POST['script_contents']);
+          $this->scripts[$this->current_script]['SCRIPT'] = $sc;
+          $p = new My_Parser($this);
+          if($p -> parse($sc)){
+            $this->Script_Error = "";
+          } else {
+            $this->Script_Error = $p->status_text;
+            $skip_mode_change = TRUE;
+          }
+        }
+      }
+      if(in_array($Mode,array("Structured"))){
+        $sc = $this->current_handler->get_sieve_script();
+        $this->scripts[$this->current_script]['SCRIPT'] = $sc;
+        $p = new My_Parser($this);
+        if($p -> parse($sc)){
+          $this->Script_Error = "";
+        } else {
+          $this->Script_Error = $p->status_text;
+          $skip_mode_change = TRUE;
+        }
+      }
+      if(!$skip_mode_change){
+        if($this->scripts[$this->current_script]['MODE'] != "Source-Only"){
+          $old_mode = $this->scripts[$this->current_script]['MODE'];
+          if(isset($_POST['View_Source'])){
+            $this->scripts[$this->current_script]['MODE'] = "Source";
+          }
+          if(isset($_POST['View_Structured'])){
+            $this->scripts[$this->current_script]['MODE'] = "Structured";
+          }
+          $new_mode = $this->scripts[$this->current_script]['MODE'];
+
+          if($old_mode != $new_mode){
+
+            $sc = $this->scripts[$this->current_script]['SCRIPT'];
+            $p = new My_Parser($this);
+
+            if($p -> parse($sc)){
+              $this->current_handler->parse($sc);
+              $this->Script_Error = "";
+            } else {
+              $this->Script_Error = $p->status_text;
+            }
+          } 
+        }
+      }
+    }
+  }
+
+  
+  function get_used_script_names()
+  {
+    $ret = array();
+    foreach($this->scripts as $script){
+      $ret[] = $script['NAME'];
+    }
+    return($ret);
+  }
+
+
+
+  function save()
+  {
+    /* Get sieve */
+    if(!$this->sieve_handle = $this->get_sieve()){
+      print_red(
+          sprintf(
+            _("Can't log into SIEVE server. Server says '%s'."),
+            to_string($this->Sieve_Error)));
+      return;
+    }
+
+    $everything_went_fine = TRUE;
+
+    foreach($this->scripts as $key => $script){
+      if($script['EDITED']){
+        $data = $this->scripts[$key]['SCRIPT'];
+        if(!$this->sieve_handle->sieve_sendscript($script['NAME'], addcslashes ($data,"\\"))){
+          gosa_log("Failed to save sieve script named '".$script['NAME']."': ".to_string($this->sieve_handle->error_raw));
+          $everything_went_fine = FALSE;
+          print_red(to_string($this->sieve_handle->error_raw));
+          $this->scripts[$key]['MSG'] = "<font color='red'>".
+                                           _("Failed to save sieve script").": ".
+                                           to_string($this->sieve_handle->error_raw).
+                                           "</font>";
+        }
+      }
+    }
+    return($everything_went_fine);
+  }
+}
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/sieve/class_tree.inc b/include/sieve/class_tree.inc
new file mode 100644 (file)
index 0000000..37198f0
--- /dev/null
@@ -0,0 +1,153 @@
+<?php
+
+class Tree
+{
+       var $childs_;
+       var $parents_;
+       var $nodes_;
+       var $maxId_;
+       var $dumpFn_;
+       var $dump_;
+
+       function Tree(&$root)
+       {
+               $this->_construct($root);
+       }
+
+       function _construct(&$root)
+       {
+               $this->childs_ = array();
+               $this->parents_ = array();
+               $this->nodes_ = array();
+               $this->maxId_ = 0;
+
+               $this->parents_[0] = null;
+               $this->nodes_[0] = $root;
+       }
+
+       function addChild(&$child)
+       {
+               return $this->addChildTo($this->maxId_, $child);
+       }
+
+       function addChildTo($parent_id, &$child)
+       {
+               if (!is_int($parent_id) ||
+                   !isset($this->nodes_[$parent_id]))
+               {
+                       return null;
+               }
+
+               if (!isset($this->childs_[$parent_id]))
+               {
+                       $this->childs_[$parent_id] = array();
+               }
+
+               $child_id = ++$this->maxId_;
+               $this->nodes_[$child_id] = $child;
+               $this->parents_[$child_id] = $parent_id;
+               array_push($this->childs_[$parent_id], $child_id);
+
+               return $child_id;
+       }
+
+       function getRoot()
+       {
+               if (!isset($this->nodes_[0]))
+               {
+                       return null;
+               }
+
+               return 0;
+       }
+
+       function getParent($node_id)
+       {
+               if (!is_int($node_id) ||
+                   !isset($this->nodes_[$node_id]))
+               {
+                       return null;
+               }
+
+               return $this->parents_[$node_id];
+       }
+
+       function getChilds($node_id)
+       {
+               if (!is_int($node_id) ||
+                   !isset($this->nodes_[$node_id]))
+               {
+                       return null;
+               }
+
+               if (!isset($this->childs_[$node_id]))
+               {
+                       return array();
+               }
+
+               return $this->childs_[$node_id];
+       }
+
+       function getNode($node_id)
+       {
+               if (!is_int($node_id) ||
+                   !isset($this->nodes_[$node_id]))
+               {
+                       return null;
+               }
+
+               return $this->nodes_[$node_id];
+       }
+
+       function setDumpFunc($callback)
+       {
+               if ($callback == NULL || is_callable($callback))
+               {
+                       $this->dumpFn_ = $callback;
+               }
+       }
+
+       function dump()
+       {
+               $this->dump_ = "tree\n";
+               $this->doDump_(0, '', true);
+               return $this->dump_;
+       }
+
+       function doDump_($node_id, $prefix, $last)
+       {
+               if ($last)
+               {
+                       $infix = '`--- ';
+                       $child_prefix = $prefix . '   ';
+               }
+               else
+               {
+                       $infix = '|--- ';
+                       $child_prefix = $prefix . '|  ';
+               }
+
+               $node = $this->nodes_[$node_id];
+               if ($this->dumpFn_ != NULL)
+               {
+                       $this->dump_ .= $prefix . $infix . call_user_func($this->dumpFn_, $node) . "\n";
+               }
+               else
+               {
+                       $this->dump_ .= "$prefix$infix$node\n";
+               }
+
+               if (isset($this->childs_[$node_id]))
+               {
+                       $childs = $this->childs_[$node_id];
+                       $last_child = count($childs);
+
+                       for ($i=1; $i <= $last_child; ++$i)
+                       {
+                               $this->doDump_($childs[$i-1], $child_prefix, ($i == $last_child ? true : false));
+                       }
+               }
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/include/sieve/libsieve.inc b/include/sieve/libsieve.inc
new file mode 100644 (file)
index 0000000..3b94e49
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+require_once 'class_parser.inc';
+require_once 'class_scanner.inc';
+require_once 'class_semantics.inc';
+require_once 'class_tree.inc';
+require_once 'class_sieve.inc';
+require_once 'class_sieveElement_If.inc';
+?>
diff --git a/include/sieve/templates/add_element.tpl b/include/sieve/templates/add_element.tpl
new file mode 100644 (file)
index 0000000..d98c529
--- /dev/null
@@ -0,0 +1,14 @@
+<h2>{t}Add a new element{/t}</h2>
+{t}Please select the type of element you want to add{/t}
+<br>
+<select name='element_type'>
+       {html_options options=$element_types selected=$element_type }
+</select>
+
+<p class='seperator'>&nbsp;</p>
+<br>
+<div class='seperator' style='text-align:right; width:100%;'>
+    <input type='submit' name='select_new_element_type' value='{t}Continue{/t}'>
+    &nbsp;
+    <input type='submit' name='select_new_element_type_cancel' value='{t}Abort{/t}'>
+</div>
diff --git a/include/sieve/templates/block_indent_start.tpl b/include/sieve/templates/block_indent_start.tpl
new file mode 100644 (file)
index 0000000..482f637
--- /dev/null
@@ -0,0 +1,12 @@
+
+<table class='object_container_container'> 
+       <tr>
+               <td class='object_container_cell_top_left'>
+                       &nbsp;  
+               </td>
+               <td style='width:3px;'>
+               </td>
+               <td>
+                       
+                       <div class=''style='height:12px;'>&nbsp;</div>
+                       <div class='container_'>
diff --git a/include/sieve/templates/block_indent_stop.tpl b/include/sieve/templates/block_indent_stop.tpl
new file mode 100644 (file)
index 0000000..857aa68
--- /dev/null
@@ -0,0 +1,5 @@
+                       </div>
+                       <div style='height:12px;'>&nbsp;</div>
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/create_script.tpl b/include/sieve/templates/create_script.tpl
new file mode 100644 (file)
index 0000000..4273716
--- /dev/null
@@ -0,0 +1,19 @@
+<h2>Create a new sieve script</h2>
+{t}Please enter the name for the new script below. Script names must consist of lower case characters only.{/t}
+
+<br>
+<br>
+<p class="seperator">&nbsp;</p>
+<br>
+<b>{t}Script name{/t}</b> <input type='text' name='NewScriptName' value='{$NewScriptName}'>
+<br>
+<br>
+
+<div class='seperator' style='border-top:1px solid #999; text-align:right; width:100%; padding-top:10px;'>
+   <input type='submit' name='create_script_save' value='{t}Apply{/t}' id='create_script_save'>
+   &nbsp;
+   <input type='submit' name='create_script_cancel' value='{t}Cancel{/t}'>
+</div>
+<script language="JavaScript" type="text/javascript">
+       document.mainform.NewScriptName.focus();
+</script>
diff --git a/include/sieve/templates/edit_frame_base.tpl b/include/sieve/templates/edit_frame_base.tpl
new file mode 100644 (file)
index 0000000..83d62a0
--- /dev/null
@@ -0,0 +1,42 @@
+
+<table class='editing_surface'>
+       <tr>
+               <td class='editing_surface_menu'>
+                       
+                       <input type='submit' name='Save_Copy' value="{t}Export{/t}">
+                       <input type='submit' name='Import_Script' value="{t}Import{/t}">
+
+                       {if $Mode != "Source-Only"}                     
+                               
+                               {if $Mode == "Source"}
+                               <input type='submit' name='View_Structured' value="{t}View structured{/t}">
+                               {else}
+                               <input type='submit' name='View_Source' value="{t}View source{/t}">
+                               {/if}
+                       {/if}
+               </td>
+       </tr>
+       <tr>
+               <td class='editing_surface_content'>
+
+                       {if $Script_Error != ""}
+                                               <div  class='sieve_error_msgs'>
+                                                       {$Script_Error}
+                                               </div>
+                       {/if}
+
+
+                       {if $Mode == "Structured"}
+                               {$Contents}
+                       {else}
+                               <textarea class='editing_source' name='script_contents'>{$Contents}</textarea>
+                       {/if}
+
+               </td>
+       </tr>
+</table>
+<div class='seperator' style='text-align:right; width:100%;'>
+       <input type='submit' name='save_sieve_changes' value='{t}Save{/t}'>
+        &nbsp;
+    <input type='submit' name='cancel_sieve_changes' value='{t}Cancel{/t}'>
+</div>
diff --git a/include/sieve/templates/element_address.tpl b/include/sieve/templates/element_address.tpl
new file mode 100755 (executable)
index 0000000..ea6580f
--- /dev/null
@@ -0,0 +1,142 @@
+{if $Expert}
+       {if $LastError != ""}
+               <table class='sieve_test_case'>
+               <tr>
+                               <td colspan=2>
+                           <font color='red'><b>{$LastError}</b></font>
+                               </td>
+                       </tr>
+               </table>
+        {/if}
+
+<table class='sieve_test_case'>
+       <tr>
+               <td >
+                       <b>{t}Address{/t}</b>
+               </td>
+        <td style='text-align:right; vertical-align:top;'>
+                       <input type='submit' name='Toggle_Expert_{$ID}' value='{t}Normal view{/t}'>
+               </td>
+       </tr>
+</table>
+<table>
+       <tr>
+               <td >
+                       {t}Match type{/t}
+               </td>
+               <td>
+                       <select name='matchtype_{$ID}' title='{t}Boolean value{/t}' onChange='document.mainform.submit();'> 
+                               {html_options options=$match_types selected=$match_type}
+                       </select>
+
+               </td>
+       </tr>
+       <tr>
+               <td>
+                       {t}Invert test{/t}?
+               </td>
+               <td>
+                       {if $Inverse}
+                               <input type='submit' name='toggle_inverse_{$ID}' value='{t}Yes{/t}'>
+                       {else}
+                               <input type='submit' name='toggle_inverse_{$ID}' value='{t}No{/t}'>
+                       {/if}
+               </td>
+       </tr>
+       <tr>
+               <td>
+                       {t}Part of address that should be used{/t}
+               </td>
+               <td>
+                       <select name='address_part_{$ID}' title='{t}Boolean value{/t}'> 
+                               {html_options options=$address_parts selected=$address_part}
+                       </select>
+               </td>
+       </tr>
+       <tr>
+               <td>
+                       {t}Comparator{/t}
+               </td>
+               <td>
+                       <select name='comparator_{$ID}' title='{t}Boolean value{/t}'> 
+                               {html_options options=$comparators selected=$comparator}
+                       </select>
+               </td>
+       </tr>
+               {if $match_type == ":count" || $match_type == ":value"}
+       <tr>
+               <td>
+                       {t}Operator{/t}
+               </td>
+               <td>
+                       <select name='operator_{$ID}' title='{t}Boolean value{/t}' onChange='document.mainform.submit();'>
+                               {html_options options=$operators selected=$operator}
+                       </select>
+               </td>
+       </tr>
+               {/if}
+       <tr>
+               <td colspan=2>&nbsp;</td>
+       </tr>
+</table>
+<table style='width:100%;'>
+    <tr>
+        <td style='width:50%;'>
+            {t}Address fields to include{/t}<br>
+            <textarea style='width:100%;height:70px;' name='keys_{$ID}'>{$keys}</textarea>
+        </td>
+        <td style='width:50%;'>
+            {t}Values to match for{/t}<br>
+            <textarea style='width:100%;height:70px;' name='values_{$ID}'>{$values}</textarea>
+        </td>
+    </tr>
+</table>
+       {else}
+
+       {if $LastError != ""}
+               <table class='sieve_test_case'>
+               <tr>
+                               <td colspan=2>
+                           <font color='red'><b>{$LastError}</b></font>
+                               </td>
+                       </tr>
+               </table>
+        {/if}
+
+<table class='sieve_test_case'>
+       <tr>
+               {if $match_type == ":count" || $match_type == ":value"}
+               <td style='vertical-align:top; width:350px;'>
+               {else}
+               <td style='vertical-align:top; width:200px;'>
+               {/if}
+                       <b>{t}Address{/t}</b>
+               
+                       {if $Inverse}
+                               <input type='submit' name='toggle_inverse_{$ID}' value='{t}Not{/t}'>
+                       {else}
+                               <input type='submit' name='toggle_inverse_{$ID}' value='{t}-{/t}'>
+                       {/if}
+                       &nbsp;
+                       <select onChange='document.mainform.submit();' name='matchtype_{$ID}' title='{t}Boolean value{/t}'> 
+                               {html_options options=$match_types selected=$match_type}
+                       </select>
+
+                       {if $match_type == ":count" || $match_type == ":value"}
+                       <select name='operator_{$ID}' title='{t}Boolean value{/t}' onChange='document.mainform.submit();'>
+                               {html_options options=$operators selected=$operator}
+                       </select>
+                       {/if}
+               </td>
+               <td>
+                       <textarea style='width:100%;height:40px;' name='keys_{$ID}'>{$keys}</textarea>
+               </td>
+               <td>
+                       <textarea style='width:100%;height:40px;' name='values_{$ID}'>{$values}</textarea>
+               </td>
+               <td style='text-align:right; vertical-align:top; width:120px;'>
+                       <input type='submit' name='Toggle_Expert_{$ID}' value='{t}Expert view{/t}'>
+               </td>
+       </tr>
+</table>
+       {/if}
diff --git a/include/sieve/templates/element_allof.tpl b/include/sieve/templates/element_allof.tpl
new file mode 100644 (file)
index 0000000..024c011
--- /dev/null
@@ -0,0 +1,16 @@
+<table class='sieve_allof_container'>
+       <tr>
+       <td class='sieve_allof_left'>
+            {if $Inverse}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}Not{/t}' title='{t}Inverse match{/t}'>
+            {else}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}-{/t}' title='{t}Inverse match{/t}'>
+            {/if}
+                       <br>
+                       <b>{t}All of{/t}</b>
+               </td>
+        <td class='sieve_allof_right'>
+                       {$Contents}
+        </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_anyof.tpl b/include/sieve/templates/element_anyof.tpl
new file mode 100644 (file)
index 0000000..f7dc929
--- /dev/null
@@ -0,0 +1,16 @@
+<table class='sieve_anyof_container'>
+       <tr>
+       <td class='sieve_anyof_left'>
+            {if $Inverse}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}Not{/t}' title='{t}Inverse match{/t}'>
+            {else}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}-{/t}' title='{t}Inverse match{/t}'>
+            {/if}
+                       <br>
+                       <b>{t}Any of{/t}</b>
+               </td>
+        <td class='sieve_anyof_right'>
+                       {$Contents}
+        </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_block_end.tpl b/include/sieve/templates/element_block_end.tpl
new file mode 100644 (file)
index 0000000..41c3a2c
--- /dev/null
@@ -0,0 +1,5 @@
+<!--
+           </td>
+    </tr>
+</table>
+-->
diff --git a/include/sieve/templates/element_block_start.tpl b/include/sieve/templates/element_block_start.tpl
new file mode 100644 (file)
index 0000000..5261624
--- /dev/null
@@ -0,0 +1,12 @@
+<!--
+<table cellspacing=0 style='width:100%;border: solid 1px #BBB;346575;'>
+       <tr>
+       <td style='width:20px; text-align:center;vertical-align:top; color: #FFFFFF; background-color:#BBBBBB;' >
+        </td>
+       <td style='width:30px; text-align:center;vertical-align:top; color: #FFFFFF; background-color:#346575;'>
+                       <b>+</b>
+        </td>
+        <td style=' background-color:#BBBBBB;
+                    border: solid 0px #DDDDDD;
+                  '>
+-->
diff --git a/include/sieve/templates/element_boolean.tpl b/include/sieve/templates/element_boolean.tpl
new file mode 100755 (executable)
index 0000000..44f5f7b
--- /dev/null
@@ -0,0 +1,12 @@
+<table class='sieve_test_case'>
+       <tr>
+               <td>
+                       <b>{t}Bool{/t}</b>
+                       <select name='boolean_{$ID}' title='{t}Boolean value{/t}'> 
+                               {html_options options=$values selected=$selected}
+                       </select>
+                       <input type='submit' value='{t}update{/t}'>
+                       <br>
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_comment.tpl b/include/sieve/templates/element_comment.tpl
new file mode 100644 (file)
index 0000000..56edf94
--- /dev/null
@@ -0,0 +1,23 @@
+<table class='sieve_comment_container'> 
+       <tr>
+               <td>
+                       <b>{t}Comment{/t}</b>
+               </td>
+               <td style='text-align: right;'>
+                       {if $Small}
+                               <input type='submit' name='toggle_small_{$ID}' value='{t}Edit{/t}'>     
+                       {else}
+                               <input type='submit' name='toggle_small_{$ID}' value='{t}Cancel{/t}'>   
+                       {/if}
+               </td>
+       </tr>
+       <tr>
+               <td style='padding-left:20px;' colspan=2>
+               {if $Small}
+                       {$Comment}
+               {else}
+                       <textarea  name='comment_{$ID}' class='sieve_comment_area'>{$Comment}</textarea>
+               {/if}
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_discard.tpl b/include/sieve/templates/element_discard.tpl
new file mode 100644 (file)
index 0000000..e26f77a
--- /dev/null
@@ -0,0 +1,12 @@
+<table class='sieve_discard_container'>
+       <tr>
+               <td>
+                       <b>{t}Discard{/t}</b>
+               </td>
+       </tr>
+       <tr>
+               <td class='sieve_discard_input'>
+                       {t}Discard message{/t}
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_else.tpl b/include/sieve/templates/element_else.tpl
new file mode 100644 (file)
index 0000000..739fd05
--- /dev/null
@@ -0,0 +1,7 @@
+<table class='sieve_default_table'>
+       <tr>
+               <td>
+                       <b>{t}Else{/t}</b>
+       </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_elsif.tpl b/include/sieve/templates/element_elsif.tpl
new file mode 100644 (file)
index 0000000..ffbbf9b
--- /dev/null
@@ -0,0 +1,8 @@
+<table class='sieve_default_table'>
+       <tr>
+               <td>
+                       <b>{t}Else if{/t}</b>
+                       {$Contents}
+       </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_envelope.tpl b/include/sieve/templates/element_envelope.tpl
new file mode 100755 (executable)
index 0000000..f0bcb67
--- /dev/null
@@ -0,0 +1,134 @@
+
+    {if $Expert}
+        {if $LastError != ""}
+               <table class='sieve_test_case'>
+            <tr>
+                <td colspan=2>
+                    <font color='red'><b>{$LastError}</b></font>
+                </td>
+            </tr>
+               </table>
+        {/if}
+
+<table class='sieve_test_case'>
+    <tr>
+               <td style='width:50%;'>
+                       <b>{t}Envelope{/t}</b>
+               </td>
+        <td style='text-align:right; vertical-align:top;'>
+            <input type='submit' name='Toggle_Expert_{$ID}' value='{t}Normal view{/t}'>
+        </td>
+    </tr>
+</table>
+<table>
+    <tr>
+        <td style='width:50%;'>
+            {t}Match type{/t}
+        </td>
+        <td>
+            <select name='matchtype_{$ID}' title='{t}Boolean value{/t}' onChange='document.mainform.submit();'>
+                {html_options options=$match_types selected=$match_type}
+            </select>
+
+        </td>
+    </tr>
+           <tr>
+        <td>
+            {t}Invert test{/t}?
+        </td>
+        <td>
+            {if $Inverse}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}Yes{/t}' title='{t}Inverse match{/t}'>
+            {else}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}No{/t}' title='{t}Inverse match{/t}'>
+            {/if}
+        </td>
+    </tr>
+    <tr>
+        <td>
+            {t}Comparator{/t}
+        </td>
+        <td>
+            <select name='comparator_{$ID}' title='{t}Boolean value{/t}'>
+                {html_options options=$comparators selected=$comparator}
+            </select>
+        </td>
+    </tr>
+        {if $match_type == ":count" || $match_type == ":value"}
+    <tr>
+        <td>
+            {t}Operator{/t}
+        </td>
+        <td>
+            <select name='operator_{$ID}' title='{t}Boolean value{/t}' onChange='document.mainform.submit();'>
+                {html_options options=$operators selected=$operator}
+            </select>
+        </td>
+    </tr>
+        {/if}
+  <tr>
+        <td colspan=2>&nbsp;</td>
+    </tr>
+</table>
+<table style='width:100%;'> 
+    <tr>
+        <td >
+            {t}Address fields to include{/t}<br>
+            <textarea style='width:100%;height:70px;' name='keys_{$ID}'>{$keys}</textarea>
+        </td>
+        <td >
+            {t}Values to match for{/t}<br>
+            <textarea style='width:100%;height:70px;' name='values_{$ID}'>{$values}</textarea>
+        </td>
+    </tr>
+</table>
+
+       {else}
+       {if $LastError != ""}
+               <table class='sieve_test_case'>
+               <tr>
+                               <td colspan=4>
+                           <font color='red'><b>{$LastError}</b></font>
+                               </td>
+                       </tr>
+               </table>
+        {/if}
+<table class='sieve_test_case'>
+       <tr>
+               {if $match_type == ":count" || $match_type == ":value"}
+               <td style='vertical-align:top; width:350px;'>
+               {else}
+               <td style='vertical-align:top; width:200px;'>
+               {/if}
+
+                       
+                       <b>{t}Envelope{/t}</b>
+               
+                       {if $Inverse}
+                               <input type='submit' name='toggle_inverse_{$ID}' value='{t}Not{/t}'>
+                       {else}
+                               <input type='submit' name='toggle_inverse_{$ID}' value='{t}-{/t}'>
+                       {/if}
+                       &nbsp;
+                       <select onChange='document.mainform.submit();' name='matchtype_{$ID}' title='{t}Boolean value{/t}'> 
+                               {html_options options=$match_types selected=$match_type}
+                       </select>
+
+                       {if $match_type == ":count" || $match_type == ":value"}
+                       <select name='operator_{$ID}' title='{t}Boolean value{/t}' onChange='document.mainform.submit();'>
+                               {html_options options=$operators selected=$operator}
+                       </select>
+                       {/if}
+               </td>
+               <td>
+                       <textarea style='width:100%;height:40px;' name='keys_{$ID}'>{$keys}</textarea>
+               </td>
+               <td>
+                       <textarea style='width:100%;height:40px;' name='values_{$ID}'>{$values}</textarea>
+               </td>
+               <td style='text-align:right; vertical-align:top; width:120px;'>
+                       <input type='submit' name='Toggle_Expert_{$ID}' value='{t}Expert view{/t}'>
+               </td>
+       </tr>
+</table>
+       {/if}
diff --git a/include/sieve/templates/element_exists.tpl b/include/sieve/templates/element_exists.tpl
new file mode 100644 (file)
index 0000000..29882d3
--- /dev/null
@@ -0,0 +1,20 @@
+<table class='sieve_test_case'>
+    <tr>
+        <td style='vertical-align:top; width:200px;'>
+            {if $LastError != ""}
+                <font color='red'>{$LastError}</font>
+                <br>
+            {/if}
+            <b>{t}Exists{/t}</b>
+            {if $Inverse}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}Not{/t}' title='{t}Inverse match{/t}'>
+            {else}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}-{/t}' title='{t}Inverse match{/t}'>
+            {/if}
+
+               </td>
+               <td>
+            <textarea style='width:99%;height:20px;' name='Values_{$ID}'>{$Values}</textarea>
+               </td>
+    </tr>
+</table>
diff --git a/include/sieve/templates/element_fileinto.tpl b/include/sieve/templates/element_fileinto.tpl
new file mode 100644 (file)
index 0000000..c6ae998
--- /dev/null
@@ -0,0 +1,30 @@
+<table class='sieve_fileinto_container'>
+       <tr>
+               <td colspan=2>
+                       <b>{t}Move mail into folder{/t}</b>
+               </td>
+               <td style='text-align:right;'>
+                       {if $User_Mode}
+                               <input type='submit' name='user_mode_{$ID}' value='{t}Select from list{/t}'>
+                       {else}
+                               <input type='submit' name='user_mode_{$ID}' value='{t}Manual selection{/t}'>
+                       {/if}
+               </td>
+       </tr>
+       <tr>
+               <td style='width:20px;'>
+               </td>
+               <td>
+                       {t}Folder{/t}
+                       {if $User_Mode}
+                               <input class='sieve_fileinto_input' type='text' value="{$Selected}" name='fileinto_{$ID}'>
+                       {else}
+                               <select name='fileinto_{$ID}' class='sieve_fileinto_input'>
+                                       {html_options values=$Boxes output=$Boxes selected=$Selected}
+                               </select>
+                       {/if}
+               </td>
+               <td >
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_header.tpl b/include/sieve/templates/element_header.tpl
new file mode 100755 (executable)
index 0000000..8dcd309
--- /dev/null
@@ -0,0 +1,136 @@
+       {if $Expert}
+       {if $LastError != ""}
+               <table class='sieve_test_case'>
+               <tr>
+                               <td colspan=4>
+                           <font color='red'><b>{$LastError}</b></font>
+                               </td>
+                       </tr>
+               </table>
+        {/if}
+
+
+<table class='sieve_test_case'>
+       <tr>
+               <td>
+                       <b>{t}Header{/t}</b>
+               </td>
+        <td style='text-align:right; vertical-align:top;'>
+            <input type='submit' name='Toggle_Expert_{$ID}' value='{t}Normal view{/t}'>
+        </td>
+    </tr>
+</table>
+<table>
+    <tr>
+               <td>
+            {t}Match type{/t}
+        </td>
+        <td>
+            <select name='matchtype_{$ID}' title='{t}Boolean value{/t}' onChange='document.mainform.submit();'>
+                {html_options options=$match_types selected=$match_type}
+            </select>
+
+        </td>
+    </tr>
+    <tr>
+        <td>
+            {t}Invert test{/t}?
+        </td>
+        <td>
+            {if $Inverse}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}Yes{/t}'>
+            {else}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}No{/t}'>
+            {/if}
+        </td>
+    </tr>
+    <tr>
+        <td>
+            {t}Comparator{/t}
+        </td>
+        <td>
+            <select name='comparator_{$ID}' title='{t}Boolean value{/t}'>
+                {html_options options=$comparators selected=$comparator}
+            </select>
+        </td>
+    </tr>
+        {if $match_type == ":count" || $match_type == ":value"}
+    <tr>
+        <td>
+            {t}operator{/t}
+        </td>
+        <td>
+            <select name='operator_{$ID}' title='{t}Boolean value{/t}' onChange='document.mainform.submit();'>
+                {html_options options=$operators selected=$operator}
+            </select>
+        </td>
+    </tr>
+        {/if}
+
+        <tr>
+        <td colspan=2>&nbsp;</td>
+    </tr>
+   </table>
+   <table class='sieve_test_case'>
+    <tr>
+        <td >
+            {t}Address fields to include{/t}<br>
+            <textarea style='width:100%;height:70px;' name='keys_{$ID}'>{$keys}</textarea>
+        </td>
+        <td >
+            {t}Values to match for{/t}<br>
+            <textarea style='width:100%;height:70px;' name='values_{$ID}'>{$values}</textarea>
+        </td>
+    </tr>
+       </table>
+
+       {else}
+       {if $LastError != ""}
+               <table class='sieve_test_case'>
+               <tr>
+                               <td colspan=4>
+                           <font color='red'><b>{$LastError}</b></font>
+                               </td>
+                       </tr>
+               </table>
+        {/if}
+
+               
+<table class='sieve_test_case'>
+    <tr>
+               {if $match_type == ":count" || $match_type == ":value"}
+               <td style='vertical-align:top; width:350px;'>
+               {else}
+               <td style='vertical-align:top; width:200px;'>
+               {/if}
+            <b>{t}Header{/t}</b>
+
+            {if $Inverse}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}Not{/t}'>
+            {else}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}-{/t}'>
+            {/if}
+            &nbsp;
+            <select onChange='document.mainform.submit();' name='matchtype_{$ID}' title='{t}Boolean value{/t}'>
+                {html_options options=$match_types selected=$match_type}
+            </select>
+
+            {if $match_type == ":count" || $match_type == ":value"}
+            <select name='operator_{$ID}' title='{t}Boolean value{/t}' onChange='document.mainform.submit();'>
+                {html_options options=$operators selected=$operator}
+            </select>
+            {/if}
+        </td>
+        <td>
+            <textarea style='width:100%;height:40px;' name='keys_{$ID}'>{$keys}</textarea>
+        </td>
+        <td>
+            <textarea style='width:100%;height:40px;' name='values_{$ID}'>{$values}</textarea>
+        </td>
+        <td style='text-align:right; vertical-align:top; width:120px;'>
+            <input type='submit' name='Toggle_Expert_{$ID}' value='{t}Expert view{/t}'>
+        </td>
+    </tr>
+
+</table>
+       {/if}
diff --git a/include/sieve/templates/element_if.tpl b/include/sieve/templates/element_if.tpl
new file mode 100644 (file)
index 0000000..98f9b4a
--- /dev/null
@@ -0,0 +1,8 @@
+<table class='sieve_default_table'>
+       <tr>
+       <td>
+                       <b>{t}Condition{/t}</b>
+                       {$Contents}
+       </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_keep.tpl b/include/sieve/templates/element_keep.tpl
new file mode 100644 (file)
index 0000000..f3c5d86
--- /dev/null
@@ -0,0 +1,12 @@
+<table class='sieve_keep_container'>
+       <tr>
+               <td>
+                       <b>{t}Keep{/t}</b>
+               </td>
+       </tr>
+       <tr>
+               <td class='sieve_keep_input'>
+                       {t}Keep message{/t}
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_redirect.tpl b/include/sieve/templates/element_redirect.tpl
new file mode 100644 (file)
index 0000000..778ff1a
--- /dev/null
@@ -0,0 +1,22 @@
+<table class='sieve_redirect_container'>
+       {foreach from=$LastError item=val key=key}
+        <tr>
+            <td colspan=4>
+                <div class='sieve_error_msgs'>{$LastError[$key]}</div>
+
+            </td>
+        </tr>
+
+    {/foreach}
+       <tr>
+               <td>
+                       <b>{t}Redirect{/t}</b>
+               </td>
+       </tr>
+       <tr>
+               <td class='sieve_redirect_input'>
+                       {t}Redirect mail to following recipients{/t}<br>
+                       <textarea name='redirect_to_{$ID}' class='sieve_redirect_input'>{$Destinations}</textarea>
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_reject.tpl b/include/sieve/templates/element_reject.tpl
new file mode 100644 (file)
index 0000000..c9de8b5
--- /dev/null
@@ -0,0 +1,28 @@
+<table class='sieve_reject_container'>
+
+{foreach from=$LastError item=val key=key}
+        <tr>
+            <td colspan=4>
+                <div class='sieve_error_msgs'>{$LastError[$key]}</div>
+
+            </td>
+        </tr>
+
+    {/foreach}
+       <tr>
+               <td>
+                       <b>{t}Reject mail{/t}</b>
+                       &nbsp;
+                       {if $Multiline}
+<!--                           {t}This will be a multiline text element{/t}-->
+                       {else}
+<!--                           {t}this will be stored as single string{/t}-->
+                       {/if}
+               </td>
+       </tr>
+       <tr>
+               <td class='sieve_reject_input'>
+                       <textarea name='reject_message_{$ID}' class='sieve_reject_input'>{$Message}</textarea>
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_require.tpl b/include/sieve/templates/element_require.tpl
new file mode 100644 (file)
index 0000000..3a3f261
--- /dev/null
@@ -0,0 +1,21 @@
+<table class='sieve_require_container'>
+       {foreach from=$LastError item=val key=key}
+               <tr>
+                       <td colspan=4>
+                               <div class='sieve_error_msgs'>{$LastError[$key]}</div>
+                       </td>
+               </tr>
+
+       {/foreach}
+       <tr>
+               <td style=''>
+                       <b>{t}Require{/t}</b>
+               </td>
+       </tr>
+       <tr>
+               <td style='padding-left:20px;;'>
+                       <input type='text'  name='require_{$ID}' class='sieve_require_input' value='{$Require}'>
+               </td>
+       </tr>
+</table>
+
diff --git a/include/sieve/templates/element_size.tpl b/include/sieve/templates/element_size.tpl
new file mode 100644 (file)
index 0000000..a8e2346
--- /dev/null
@@ -0,0 +1,25 @@
+<table class='sieve_test_case'>
+       <tr>
+               <td>
+                       <b>{t}Size{/t}</b>
+                       {if $LastError != ""}
+                               <font color='red'>{$LastError}</font>
+                               <br>
+                       {/if}                   
+
+               {if $Inverse}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}Not{/t}' title='{t}Inverse match{/t}'>
+            {else}
+                <input type='submit' name='toggle_inverse_{$ID}' value='{t}-{/t}' title='{t}Inverse match{/t}'>
+            {/if}
+
+                       <select name='Match_type_{$ID}' title='{t}Select match type{/t}'>
+                               {html_options options=$Match_types selected=$Match_type}
+                       </select>
+                       <input type='text' name='Value_{$ID}' value='{$Value}'>
+                       <select name='Value_Unit_{$ID}' title='{t}Select value unit{/t}'>
+                               {html_options options=$Units selected=$Value_Unit}
+                       </select>
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_stop.tpl b/include/sieve/templates/element_stop.tpl
new file mode 100644 (file)
index 0000000..975f10b
--- /dev/null
@@ -0,0 +1,12 @@
+<table class='sieve_stop_container'>
+       <tr>
+               <td>
+                       <b>{t}Stop{/t}</b><br>
+               </td>
+       </tr>
+       <tr>
+               <td class='sieve_stop_input'>
+                       {t}Stop execution here{/t}
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/element_vacation.tpl b/include/sieve/templates/element_vacation.tpl
new file mode 100644 (file)
index 0000000..1741487
--- /dev/null
@@ -0,0 +1,56 @@
+<table class='sieve_vacation_container'>
+
+       {foreach from=$LastError item=val key=key}
+               <tr>
+                       <td colspan=4>
+                               <div class='sieve_error_msgs'>{$LastError[$key]}</div>
+                       </td>
+               </tr>
+       {/foreach}
+       {if $Expert}
+       <tr>
+               <td style='width:20%'>  
+                       <b>{t}Vacation Message{/t}</b>
+               </td>   
+        <td style='text-align:right; vertical-align:top;'>
+            <input type='submit' name='Toggle_Expert_{$ID}' value='{t}Normal view{/t}'>
+        </td>
+       </tr>
+       <tr>
+               <td >
+                       {t}Release interval{/t}&nbsp;
+               </td>
+               <td>
+                       <input type='text' name='vacation_release_{$ID}' value='{$Days}'>
+                       &nbsp;{t}days{/t}
+               </td>
+       </tr>
+       <tr>
+               <td>
+                       {t}Alternative sender addresses{/t}
+               </td>
+               <td>
+               <textarea name='vacation_receiver_{$ID}' style='width:100%;height:20px;'>{$Addresses}</textarea>
+               </td>
+       </tr>
+       <tr>
+               <td class='sieve_vacation_input' colspan=2>
+                   <textarea name='vacation_reason_{$ID}' class='sieve_vacation_input'>{$Reason}</textarea>
+               </td>
+       </tr>
+       {else}
+       <tr>
+               <td>    
+                       <b>{t}Vacation message{/t}</b>
+               </td>   
+               <td width='10%' style='vertical-align:top;'>
+            <input type='submit' name='Toggle_Expert_{$ID}' value='{t}Expert view{/t}'>
+               </td>
+       </tr>
+       <tr>
+               <td class='sieve_vacation_input' colspan=2>
+                   <textarea name='vacation_reason_{$ID}' class='sieve_vacation_input'>{$Reason}</textarea>
+               </td>
+       </tr>
+       {/if}
+</table>
diff --git a/include/sieve/templates/import_script.tpl b/include/sieve/templates/import_script.tpl
new file mode 100644 (file)
index 0000000..22df06c
--- /dev/null
@@ -0,0 +1,15 @@
+<h2>{t}Import sieve script{/t}</h2>
+{t}Please select the sieve script you want to import. Use the import button to import the script or the cancel button to abort.{/t}
+<br>
+<br>
+<b>{t}Script to import{/t}</b>&nbsp;<input type='file' name='Script_To_Import'>
+
+<br>
+<br>
+<p class='seperator'>&nbsp;</p>
+<br>
+<div class='seperator' style='text-align:right; width:100%;'>
+    <input type='submit' name='Import_Script_Save' value='{t}Import{/t}'>
+        &nbsp;
+    <input type='submit' name='Import_Script_Cancel' value='{t}Cancel{/t}'>
+</div>
diff --git a/include/sieve/templates/management.tpl b/include/sieve/templates/management.tpl
new file mode 100644 (file)
index 0000000..315e47e
--- /dev/null
@@ -0,0 +1,27 @@
+<h2>{t}List of sieve scripts{/t}</h2>
+<!--
+{if $uattrib_empty}
+               
+       <font color='red'><b>{t}Connection to the sieve server could not be established, the authentification attribute is empty.{/t}</b></font><br>
+       {t}Please verfiy that the attributes uid and mail are not empty and try again.{/t}
+       <br>
+       <br>
+
+{elseif $Sieve_Error != ""}
+
+       <font color='red'><b>{t}Connection to the sieve server could not be established.{/t}</b></font><br>
+       {$Sieve_Error}
+       <br>
+       {t}Possibly the sieve account has not been created yet.{/t}
+       <br>
+       <br>
+{/if}
+       {t}Be careful. All your changes will be saved directly to sieve, if you use the save button below.{/t}
+-->
+       {$List}
+       <input type='submit' name='create_new_script' value='{t}Create new script{/t}'>
+       <p style="text-align:right;border-top:1px solid #999; padding-top:10px;">
+               <input type=submit name="sieve_finish" style="width:80px" value="{t}Save{/t}">
+               &nbsp;
+               <input type=submit name="sieve_cancel" value="{t}Cancel{/t}">
+       </p>
diff --git a/include/sieve/templates/object_container.tpl b/include/sieve/templates/object_container.tpl
new file mode 100644 (file)
index 0000000..3b5f51f
--- /dev/null
@@ -0,0 +1,54 @@
+<table class='object_container_container'> 
+       <tr>
+               <td class='object_container_cell_top_left'>
+                       &nbsp;  
+               </td>
+               <td class='object_container_cell_top_right'>
+                       <input type='image' src='images/sieve_move_object_up.png' name='Move_Up_Object_{$ID}' 
+                               title='{t}Move object up one position{/t}' alt='{t}Up{/t}' class='center'>
+                       <a href='{$plug}&amp;Move_Up_Object_ID={$ID}'>{t}Move up{/t}</a>
+                       &nbsp;&nbsp;&nbsp;
+                       <input type='image' src='images/sieve_move_object_down.png' name='Move_Down_Object_{$ID}' 
+                               title='{t}Move object down one position{/t}' alt='{t}Down{/t}' class='center'>
+                       <a href='{$plug}&amp;Move_Down_Object_ID={$ID}'>{t}Move down{/t}</a>
+                       &nbsp;&nbsp;&nbsp;
+                       <input type='image' src='images/sieve_del_object.png' name='Remove_Object_{$ID}' 
+                               title='{t}Remove object{/t}' alt='R' class='center'>
+                       <a href='{$plug}&amp;Remove_Object_ID={$ID}'>{t}Remove element{/t}</a>
+                       &nbsp;&nbsp;&nbsp;
+       
+                       <select name='element_type_{$ID}'>
+                               <option value=''>&lt;{t}choose element{/t}&gt;</option>
+                               <option value='sieve_keep'>{t}Keep{/t}</option>
+                               <option value='sieve_comment'>{t}Comment{/t}</option>
+                               <option value='sieve_fileinto'>{t}Fileinto{/t}</option>
+                               <option value='sieve_keep'>{t}Keep{/t}</option>
+                               <option value='sieve_discard'>{t}Discard{/t}</option>
+                               <option value='sieve_redirect'>{t}Redirect{/t}</option>
+                               <option value='sieve_reject'>{t}Reject{/t}</option>
+                               <option value='sieve_require'>{t}Require{/t}</option>
+                               <option value='sieve_stop'>{t}Stop{/t}</option>
+                               <option value='sieve_vacation'>{t}Vacationmessage{/t}</option>
+                               <option value='sieve_if'>{t}If{/t}</option>
+                               <option value='sieve_else'>{t}Else{/t}</option>
+                               <option value='sieve_elsif'>{t}Else If{/t}</option>
+                       </select>
+
+                       <input type='image' src='images/sieve_add_new_top.png' name='Add_Object_Top_{$ID}'
+                               alt='{t}Add new{/t}' title='{t}Add a new new object above this one.{/t}' class='center'>
+                       <input type='image' src='images/truly_not_available_image' name='Add_Object_Top_{$ID}'
+                               alt='{t}Add element above{/t}' title='{t}Add a new new object above this one.{/t}' class='center'>
+                       <input type='image' src='images/sieve_add_new_bottom.png' name='Add_Object_Bottom_{$ID}'
+                               alt='{t}Add new{/t}' title='{t}Add a new new object below this one.{/t}' class='center'>        
+                       <input type='image' src='images/truly_not_available_image' name='Add_Object_Bottom_{$ID}'
+                               alt='{t}Add element below{/t}' title='{t}Add a new new object below this one.{/t}' class='center'>      
+               </td>
+       </tr>
+       <tr>
+               <td class='object_container_cell_bottom_left'>
+               </td>
+               <td>
+                       %%OBJECT_CONTENT%%
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/object_container_clear.tpl b/include/sieve/templates/object_container_clear.tpl
new file mode 100644 (file)
index 0000000..4f5579f
--- /dev/null
@@ -0,0 +1,28 @@
+<table class='object_container_container'> 
+       <tr>
+               <td class='object_container_cell_top_left'>
+                       &nbsp;  
+               </td>
+               <td class='object_container_cell_top_right'>
+                   <input type='image' src='images/sieve_move_object_up.png' name='Move_Up_Object_{$ID}'
+                title='{t}Move this object up one position{/t}' alt='{t}Up{/t}' class='center'>
+            <a href='{$plug}&amp;Move_Up_Object_ID={$ID}'>{t}Move up{/t}</a>
+
+            <input type='image' src='images/sieve_move_object_down.png' name='Move_Down_Object_{$ID}'
+                title='{t}Move this object down one position{/t}' alt='{t}Down{/t}' class='center'>
+            <a href='{$plug}&amp;Move_Down_Object_ID={$ID}'>{t}Move down{/t}</a>
+
+            <input type='image' src='images/sieve_del_object.png' name='Remove_Object_{$ID}'
+                title='{t}Remove this object{/t}' alt='R' class='center'>
+            <a href='{$plug}&amp;Remove_Object_ID={$ID}'>{t}Remove element{/t}</a>
+
+               </td>
+    </tr>
+    <tr>
+               <td class='object_container_cell_bottom_left'>
+        </td>
+        <td>
+            %%OBJECT_CONTENT%%
+        </td>
+    </tr>
+</table>
diff --git a/include/sieve/templates/object_test_container.tpl b/include/sieve/templates/object_test_container.tpl
new file mode 100644 (file)
index 0000000..e157717
--- /dev/null
@@ -0,0 +1,17 @@
+<table class='sieve_test_container'>
+       <tr>
+               <td style='width:20px; ; text-align:center; vertical-align:top;'>       
+                       {if $DisplayAdd}
+                               <input type='image' src='images/sieve_add_test.png' name='Add_Test_Object_{$ID}' 
+                                       title='{t}Add object{/t}' alt='R' class='center'>
+                       {/if}
+                       {if $DisplayDel}
+                               <input type='image' src='images/sieve_del_object.png' name='Remove_Test_Object_{$ID}' 
+                                       title='{t}Remove object{/t}' alt='R' class='center'>
+                       {/if}
+               </td>
+               <td>
+                       %%OBJECT_CONTENT%%
+               </td>
+       </tr>
+</table>
diff --git a/include/sieve/templates/remove_script.tpl b/include/sieve/templates/remove_script.tpl
new file mode 100644 (file)
index 0000000..5bb5b49
--- /dev/null
@@ -0,0 +1,17 @@
+<div style="font-size:18px;">
+<img alt="" src="images/button_cancel.png" align=top>&nbsp;{t}Warning{/t}
+</div>
+<p>
+ {$Warning}<br>
+ {t}Please double check if your really want to do this since there is no way for GOsa to get your data back.{/t}
+</p>
+
+<p>
+ {t}Best thing to do before performing this action would be to save the current script in a file. So - if you've done so - press 'Delete' to continue or 'Cancel' to abort.{/t}
+</p>
+
+<p class="plugbottom">
+  <input type=submit name="delete_script_confirm" value="{t}Delete{/t}">
+  &nbsp;
+  <input type=submit name="delete_cancel" value="{t}Cancel{/t}">
+</p>
diff --git a/include/sieve/templates/select_test_type.tpl b/include/sieve/templates/select_test_type.tpl
new file mode 100644 (file)
index 0000000..dd7a8fb
--- /dev/null
@@ -0,0 +1,14 @@
+<h2>{t}Select the type of test you want to add{/t}</h2>
+
+<b>{t}Available test types{/t}</b>&nbsp;:&nbsp;
+<select name='test_type_to_add_{$ID}'>
+       {html_options options=$test_types_to_add}
+</select>
+
+<p class='seperator'>&nbsp;</p>
+<br>
+<div class='seperator' style='text-align:right; width:100%;'>
+       <input type='submit' name='add_type' value='{t}Continue{/t}'>
+       &nbsp;
+       <input type='submit' name='does_nothing' value='{t}Cancel{/t}'>
+</div>
index ac113fde2919bfa41beef75be5864f07151329d5..34dfff53a97abb14a5f2218a06ef01cf24ed142b 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 /* Load sieve support */
-require_once ("class_sieve.inc");
+require_once ("sieve/class_sieve.inc");
 
 /* Load mail methods */
 global $BASE_DIR;
@@ -59,6 +59,7 @@ class mailAccount extends plugin
       "gosaVacationMessage", "gosaMailAlternateAddress", "gosaMailForwardingAddress", "gosaVacationStart", "gosaVacationStop");
   var $objectclasses= array("gosaMailAccount");
 
+  var $sieve_management = NULL;
 
   /* constructor, if 'dn' is set, the node loads the given
      'dn' from LDAP */
@@ -182,6 +183,10 @@ class mailAccount extends plugin
       }
     }
 
+    /* Create sieve management class */
+    $method = new $this->method($this->config);
+    $id     = $method->uattrib;
+    $this->sieve_management = new sieveManagement($this->config,$this->dn,$this,$id);
 
   /* Create filter */
 
@@ -235,6 +240,33 @@ class mailAccount extends plugin
       $mailserver[]= $key;
     }
 
+
+    /*
+     * Sieve Management
+     */
+    if(isset($_POST['sieveManagement'])
+        && preg_match("/C/",$this->gosaMailDeliveryMode)
+        && chkacl($this->acl,"sieveManagement") == "") {
+      $this->dialog = $this->sieve_management;
+    }
+
+    /* Cancel sieve edit */
+    if(isset($_POST['sieve_cancel'])){
+      $this->dialog = NULL;
+    }
+
+    /* Save sieve changes */
+    if(isset($_POST['sieve_finish'])){
+      $this->sieve_management = $this->dialog;
+      $this->dialog = NULL;
+    }
+
+    if(is_object($this->dialog)){
+      $this->dialog->save_object();
+      return($this->dialog->execute());
+    }
+
+
     /* Handle account state */
 
     /* Do we need to flip is_account state? */
@@ -570,6 +602,8 @@ class mailAccount extends plugin
       $smarty->assign("$val"."ACL", chkacl($this->acl, "$val"));
     }
 
+    $smarty->assign("sieveManagementACL", chkacl($this->acl,"sieveManagement"));
+
     if (preg_match('/V/', $this->gosaMailDeliveryMode)){
       $smarty->assign('rangeEnabled', "");
     } else {
@@ -862,7 +896,7 @@ class mailAccount extends plugin
 
         /* Only talk with sieve if the mail account already exists */
         if($this->initially_was_account){
-          
+         
           /* Write sieve information only if not in C mode */
           if (!is_integer(strpos($this->gosaMailDeliveryMode, "C"))){
             $method->configureFilter($this->$id,
@@ -873,6 +907,8 @@ class mailAccount extends plugin
                 $this->gosaSpamMailbox,
                 $this->gosaSpamSortLevel,
                 $this->gosaVacationMessage);
+          }else{
+            $this->sieve_management->save();
           }
         }
       }
index c486940178f34082ca5c8c99ec5847b2e4d6d5f9..8de101aef6ec226abdd6f67a8468c281a3253869 100644 (file)
  </tr>
 </table>
 
+<!-- SIEVE -->
+<p class="seperator">&nbsp;</p>
+<h2><img class="center" alt="" align="middle" src="images/envelope.png" />&nbsp;{t}Mail options{/t}</h2>
+<table summary="" style="vertical-align:top; text-align:left;" cellpadding=4 border=0>
+ <tr>
+  <td>
+   <input type=checkbox name="own_script" value="1" {$own_script}
+               {$custom_sieveACL}
+        onClick="
+            changeState('sieveManagement');
+            changeState('drop_own_mails');
+            changeState('use_vacation');
+            changeState('use_spam_filter');
+            changeState('use_mailsize_limit');
+            changeState('import_vacation');
+            changeState('vacation_template');
+//          changeState('forward_address');
+//          changeState('add_forwarder');
+//          changeState('add_local_forwarder');
+//          changeState('delete_forwarder');
+            changeState('only_local');
+            changeState('gosaVacationMessage');
+            changeState('gosaSpamSortLevel');
+            changeState('gosaSpamMailbox');
+            changeState('gosaMailMaxSize');
+            changeStates();
+
+        "
+
+> {t}Use custom sieve script{/t} <b>({t}disables all Mail options!{/t})</b>
+  </td>
+ </tr>
+ <tr>
+  <td>
+   <input {$sieveManagementACL} {if $own_script == ""} disabled {/if} id='sieveManagement' type='submit' name='sieveManagement' value='{t}Sieve Management{/t}'>
+  </td>
+ </tr>
+</table>
+
+
 <p class="seperator">&nbsp;</p>
 
 <h2><img class="center" alt="" align="middle" src="images/envelope.png" />&nbsp;{t}Mail options{/t}</h2>
 <table summary="" style="width:100%; vertical-align:top; text-align:left;" cellpadding=4 border=0>
  <tr style="padding-bottom:0px;">
   <td style="width:50%">
-   <input type=checkbox name="drop_own_mails" value="1" {$drop_own_mails}
+   <input type=checkbox name="drop_own_mails" value="1" {$drop_own_mails} id="drop_own_mails"
        {$drop_own_mailsACL} title="{t}Select if you want to forward mails without getting own copies of them{/t}"> {t}No delivery to own mailbox{/t}
    <br>
-   <input type=checkbox name="use_vacation" value="1" {$use_vacation}
+   <input type=checkbox name="use_vacation" value="1" {$use_vacation} id="use_vacation"
        {$gosaVacationMessageACL} title="{t}Select to automatically response with the vacation message defined below{/t}"  onclick="changeState('day'); changeState('month'); changeState('year'); changeState('sday'); changeState('smonth'); changeState('syear');"> {t}Activate vacation message{/t}
    <br>
    <div style="padding-left:22px;">
    &nbsp;
   </td>
   <td style="vertical-align:top;">
-   <input type=checkbox name="use_spam_filter" value="1" {$use_spam_filter}
+   <input type=checkbox name="use_spam_filter" value="1" {$use_spam_filter} id="use_spam_filter"
        {$gosaSpamSortLevelACL} title="{t}Select if you want to filter this mails through spamassassin{/t}"> <label for="gosaSpamSortLevel">{t}Move mails tagged with spam level greater than{/t}</label>
        
    <select id="gosaSpamSortLevel" size="1" name="gosaSpamSortLevel" {$gosaSpamSortLevelACL} title="{t}Choose spam level - smaller values are more sensitive{/t}">
         {html_options values=$spamlevel output=$spamlevel selected=$gosaSpamSortLevel}
    </select>
    <label for="gosaSpamMailbox">{t}to folder{/t}</label>
-   <select size="1" id="gosaSpamMailbox" name="gosaSpamMailbox" {$gosaSpamMailboxACL}>
+   <select size="1" id="gosaSpamMailbox" name="gosaSpamMailbox" {$gosaSpamMailboxACL} id="gosaSpamMailbox">
                {html_options values=$spambox output=$spambox selected=$gosaSpamMailbox}
                        <option disabled>&nbsp;</option>
    </select>
    <br>
-   <input type=checkbox name="use_mailsize_limit" value="1" {$use_mailsize_limit}
+   <input type=checkbox name="use_mailsize_limit" value="1" {$use_mailsize_limit} id="use_mailsize_limit"
        {$gosaMailMaxSizeACL}> <label for="gosaMailMaxSize">{t}Reject mails bigger than{/t}</label> 
    <input id="gosaMailMaxSize" name="gosaMailMaxSize" size="6" align="middle" maxlength="30" {$gosaMailMaxSizeACL}
        value="{$gosaMailMaxSize}"> {t}MB{/t}
        {$gosaVacationMessageACL}>{$gosaVacationMessage}</textarea>
    <br>
    {if $show_templates eq "true"}
-   <select name="vacation_template">
+   <select name="vacation_template" id="vacation_template">
                {html_options options=$vacationtemplates selected=$template}
                <option disabled>&nbsp;</option>
    </select>
-   <input type="submit" value="{t}Import{/t}" name="import_vacation"
+   <input type="submit" value="{t}Import{/t}" name="import_vacation" id="import_vacation"
        {$gosaVacationMessageACL}>
    {/if}
    <br>
                        <option disabled>&nbsp;</option>
    </select>
    <br>
-   <input name="forward_address" size=20 align="middle" maxlength=65
+   <input name="forward_address" size=20 align="middle" maxlength=65 id="forward_address"
        {$gosaMailForwardingAddressACL} value="">
-   <input type="submit" value="{t}Add{/t}" name="add_forwarder"
+   <input type="submit" value="{t}Add{/t}" name="add_forwarder" id="add_forwarder"
        {$gosaMailForwardingAddressACL}>&nbsp;
-   <input type="submit" value="{t}Add local{/t}" name="add_local_forwarder"
+   <input type="submit" value="{t}Add local{/t}" name="add_local_forwarder" id="add_local_forwarder"
        {$gosaMailForwardingAddressACL}>&nbsp;
-   <input type="submit" value="{t}Delete{/t}" name="delete_forwarder"
+   <input type="submit" value="{t}Delete{/t}" name="delete_forwarder" id="delete_forwarder"
        {$gosaMailForwardingAddressACL}>
   </td>
  </tr>
 <table summary="" style="width:100%; vertical-align:top; text-align:left;" cellpadding="4" border="0">
  <tr>
   <td>
-   <input type=checkbox name="only_local" value="1" {$only_local} {$only_localACL} title="{t}Select if user can only send and receive inside his own domain{/t}">
+   <input id="only_local" type=checkbox name="only_local" value="1" {$only_local} {$only_localACL} title="{t}Select if user can only send and receive inside his own domain{/t}">
    {t}User is only allowed to send and receive local mails{/t}
   </td>
-  <td style="border-left:1px solid #A0A0A0">
-   &nbsp;
-  </td>
-  <td>
-   <input type=checkbox name="own_script" value="1" {$own_script} {$custom_sieveACL}>
-   {t}Use custom sieve script{/t} <b>({t}disables all Mail options!{/t})</b>
-  </td>
  </tr>
 </table>
 
 
 <!-- Place cursor -->
 <script language="JavaScript" type="text/javascript">
+
+ {literal}
+    function changeStates()
+    {
+
+        if(document.getElementById('use_vacation').checked){
+            changeState('day');
+            changeState('month');
+            changeState('year');
+            changeState('sday');
+            changeState('smonth');
+            changeState('syear');
+        }else{
+            changeSubselectState('use_vacation','day');
+            changeSubselectState('use_vacation','month');
+            changeSubselectState('use_vacation','year');
+            changeSubselectState('use_vacation','sday');
+            changeSubselectState('use_vacation','smonth');
+            changeSubselectState('use_vacation','syear');
+        }
+    }
+
+    {/literal}
+
+
+
   <!-- // First input field on page
   document.mainform.mail.focus();
   -->