summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 1249bb0)
raw | patch | inline | side by side (parent: 1249bb0)
author | hickert <hickert@594d385d-05f5-0310-b6e9-bd551577e9d8> | |
Thu, 3 May 2007 12:56:42 +0000 (12:56 +0000) | ||
committer | hickert <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:
index 37d40101bf3e5cb4f030908ef4e0181ff35b4208..b63fbcc4363610ff4f059a80eb9fac712d1ea91c 100644 (file)
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
--- a/include/class_sieve.inc
+++ /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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("/ /"," ",$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
--- /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
--- /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
--- /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
--- /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")." ("._("Default").")",
+ ":domain" => _("Domain part") ,
+ ":localpart" => _("Local part"));
+
+ /* comparator type */
+ $this->comparators = array(
+ "i;ascii-casemap" => _("Case insensitive")." ("._("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 .= " - "._("If");
+ }elseif($this->TYPE == "elsif"){
+ $name .= " - "._("Else If");
+ }else{
+ $name .= " - "._("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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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" => " ",
+ "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").": ".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
--- /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
--- /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
--- /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'> </p>
+<br>
+<div class='seperator' style='text-align:right; width:100%;'>
+ <input type='submit' name='select_new_element_type' value='{t}Continue{/t}'>
+
+ <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
--- /dev/null
@@ -0,0 +1,12 @@
+
+<table class='object_container_container'>
+ <tr>
+ <td class='object_container_cell_top_left'>
+
+ </td>
+ <td style='width:3px;'>
+ </td>
+ <td>
+
+ <div class=''style='height:12px;'> </div>
+ <div class='container_'>
diff --git a/include/sieve/templates/block_indent_stop.tpl b/include/sieve/templates/block_indent_stop.tpl
--- /dev/null
@@ -0,0 +1,5 @@
+ </div>
+ <div style='height:12px;'> </div>
+ </td>
+ </tr>
+</table>
diff --git a/include/sieve/templates/create_script.tpl b/include/sieve/templates/create_script.tpl
--- /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"> </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'>
+
+ <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
--- /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}'>
+
+ <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
--- /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> </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}
+
+ <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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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> </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}
+
+ <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
--- /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
--- /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
--- /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> </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}
+
+ <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
--- /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
--- /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
--- /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
--- /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>
+
+ {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
--- /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
--- /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
--- /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
--- /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}
+ </td>
+ <td>
+ <input type='text' name='vacation_release_{$ID}' value='{$Days}'>
+ {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
--- /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> <input type='file' name='Script_To_Import'>
+
+<br>
+<br>
+<p class='seperator'> </p>
+<br>
+<div class='seperator' style='text-align:right; width:100%;'>
+ <input type='submit' name='Import_Script_Save' value='{t}Import{/t}'>
+
+ <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
--- /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}">
+
+ <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
--- /dev/null
@@ -0,0 +1,54 @@
+<table class='object_container_container'>
+ <tr>
+ <td class='object_container_cell_top_left'>
+
+ </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}&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 object down one position{/t}' alt='{t}Down{/t}' class='center'>
+ <a href='{$plug}&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 object{/t}' alt='R' class='center'>
+ <a href='{$plug}&Remove_Object_ID={$ID}'>{t}Remove element{/t}</a>
+
+
+ <select name='element_type_{$ID}'>
+ <option value=''><{t}choose element{/t}></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
--- /dev/null
@@ -0,0 +1,28 @@
+<table class='object_container_container'>
+ <tr>
+ <td class='object_container_cell_top_left'>
+
+ </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}&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}&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}&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
--- /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
--- /dev/null
@@ -0,0 +1,17 @@
+<div style="font-size:18px;">
+<img alt="" src="images/button_cancel.png" align=top> {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}">
+
+ <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
--- /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> :
+<select name='test_type_to_add_{$ID}'>
+ {html_options options=$test_types_to_add}
+</select>
+
+<p class='seperator'> </p>
+<br>
+<div class='seperator' style='text-align:right; width:100%;'>
+ <input type='submit' name='add_type' value='{t}Continue{/t}'>
+
+ <input type='submit' name='does_nothing' value='{t}Cancel{/t}'>
+</div>
diff --git a/plugins/personal/mail/class_mailAccount.inc b/plugins/personal/mail/class_mailAccount.inc
index ac113fde2919bfa41beef75be5864f07151329d5..34dfff53a97abb14a5f2218a06ef01cf24ed142b 100644 (file)
*/
/* Load sieve support */
-require_once ("class_sieve.inc");
+require_once ("sieve/class_sieve.inc");
/* Load mail methods */
global $BASE_DIR;
"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 */
}
}
+ /* 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 */
$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? */
$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 {
/* 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,
$this->gosaSpamMailbox,
$this->gosaSpamSortLevel,
$this->gosaVacationMessage);
+ }else{
+ $this->sieve_management->save();
}
}
}
index c486940178f34082ca5c8c99ec5847b2e4d6d5f9..8de101aef6ec226abdd6f67a8468c281a3253869 100644 (file)
</tr>
</table>
+<!-- SIEVE -->
+<p class="seperator"> </p>
+<h2><img class="center" alt="" align="middle" src="images/envelope.png" /> {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"> </p>
<h2><img class="center" alt="" align="middle" src="images/envelope.png" /> {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;">
</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> </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> </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> </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}>
- <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}>
- <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">
-
- </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();
-->