From: hickert Date: Thu, 3 May 2007 12:56:42 +0000 (+0000) Subject: Added new sieve Handling X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=fea5059ad3ce7c6d5f0b35bda1d436df65a2c8c3;p=gosa.git Added new sieve Handling git-svn-id: https://oss.gonicus.de/repositories/gosa/branches/2.5@6253 594d385d-05f5-0310-b6e9-bd551577e9d8 --- diff --git a/html/themes/default/style.css b/html/themes/default/style.css index 37d40101b..b63fbcc43 100644 --- a/html/themes/default/style.css +++ b/html/themes/default/style.css @@ -771,3 +771,368 @@ td.tbhead { td.tbrhead { border-bottom:1px solid #B0B0B0; } + +/************************ + * Sieve + * The following styles are + * used to display the sieve + * management user interface + ************************/ + +/* Editing dialog styles + */ + +table.sieve_default_table { + width:100%; + margin: 0px; + border-spacing: 0px ; + padding:0px; +} + + +/* Editing surface */ +table.editing_surface { + width:100%; + margin: 0px; + padding:0px; +} + +/* Editing surface menu */ +td.editing_surface_menu { + background-color: #EEE; + border: 1px solid #BBB; + padding:5px; +} + +/* Editing surface content */ +td.editing_surface_content { + background-color: #FFFFFF; + margin: 0px; + padding:0px; +} + +/* Error message will be displayed as follows */ +div.sieve_error_msgs { + background-color: #ff8d00; + color: #000000; + padding:5px; + background-image: url("images/warning.png"); + background-repeat: no-repeat; + font-weight: bold; +} + +/* Source editing area */ +textarea.editing_source { + width:100%; + height:330px; +} + + +/************* + * Object container + *************/ + +/* The container itself */ +table.object_container_container { + width:100%; + border-spacing: 0px ; + background-color: #F8F8F8; + border: solid 1px #AAAAAA; +} + +/* Container cell top left */ +td.object_container_cell_top_left { + background-color: #EEE; + text-align:center; +} + +/* Container cell top right */ +td.object_container_cell_top_right { + background-color: #EEE; + text-align:left; + padding:2px; + border-bottom: solid 1px #AAAAAA; +} +/* Container cell bottom left */ +td.object_container_cell_bottom_left { + width:5px; + background-color: #EEE; + text-align:center; + border-right: solid 1px #AAAAAA; +} + + +/************* + * Sieve comment + *************/ + +/* Container */ +table.sieve_comment_container { + margin:0px; + padding:0px; + border-spacing: 0px ; + width:100%; + background-color: #F8F8F8; +} + +/* Editing area */ +textarea.sieve_comment_area { + width:100%; + height:80px; +} + + +/************* + * Sieve require + *************/ + +/* Container */ +table.sieve_require_container { + margin:0px; + padding:0px; + border-spacing: 0px ; + width:100%; + background-color: #F8F8F8; +} +/* Editing area */ +input.sieve_require_input { + width:100%; + border-spacing: 0px ; +} + + +/************* + * Sieve fileinto + *************/ + +/* Container */ +table.sieve_fileinto_container { + margin:0px; + padding:0px; + border-spacing: 0px ; + width:100%; + background-color: #F8F8F8; +} + +/* Editing area */ +input.sieve_fileinto_input { + width:300px; +} +select.sieve_fileinto_input { + width:300px; +} + + +/************* + * Sieve keep + *************/ + +/* Container */ +table.sieve_keep_container { + margin:0px; + padding:0px; + border-spacing: 0px ; + width:100%; + background-color: #F8F8F8; +} +/* Editing area */ +td.sieve_keep_input { + padding-left:20px; +} + + +/************* + * Sieve discard + *************/ + +/* Container */ +table.sieve_discard_container { + margin:0px; + padding:0px; + border-spacing: 0px ; + width:100%; + background-color: #F8F8F8; +} + +/* Editing area */ +td.sieve_discard_input { + padding-left:20px; +} + + +/************* + * Sieve redirect + *************/ + +/* Container */ +table.sieve_redirect_container { + margin:0px; + padding:0px; + border-spacing: 0px ; + width:100%; + background-color: #F8F8F8; +} + +/* Editing area */ +td.sieve_redirect_input { + padding-left:20px; +} +textarea.sieve_redirect_input { + width:100%; + height:30px; +} + + +/************* + * Sieve reject + *************/ + +/* Container */ +table.sieve_reject_container { + margin:0px; + padding:0px; + border-spacing: 0px ; + width:100%; + background-color: #F8F8F8; +} + +/* Editing area */ +td.sieve_reject_input { + padding-left:20px; +} +textarea.sieve_reject_input { + width:100%; + height:55px; +} + + +/************* + * Sieve end + *************/ + +/* Container */ +table.sieve_stop_container { + margin:0px; + padding:0px; + border-spacing: 0px ; + width:100%; + background-color: #F8F8F8; +} + +/* Editing area */ +td.sieve_stop_input { + padding-left:20px; +} + + +/************* + * Sieve vacation + *************/ + +/* Container */ +table.sieve_vacation_container { + margin:0px; + padding:0px; + border-spacing: 0px ; + width:100%; + background-color: #F8F8F8; +} + +/* Editing area */ +td.sieve_vacation_input { + padding-left:20px; +} + +/* Editing area */ +textarea.sieve_vacation_input { + width:100%; + height : 55px; +} + + +/************* + * Sieve allof + *************/ + +table.sieve_allof_container { + width:100%; + border-spacing: 0px ; + margin: 0px; + padding:0px; + border: solid 1px #999999; +} + +/* Container */ +td.sieve_allof_left { + text-align:center; + vertical-align: middle; + width:35px; + background-color: #CCCCCC; + border: solid 0px #EEE; +} + +/* Container */ +td.sieve_allof_right { + background-color:#BDBDBD ; +} + +/************* + * Sieve anyof + *************/ + +table.sieve_anyof_container { + width:100%; + margin: 0px; + border-spacing: 0px ; + padding:0px; + border: solid 2px #CCCCCC; +} + +/* Container */ +td.sieve_anyof_left { + text-align:center; + vertical-align: middle; + width:35px; + background-color: #CCCCCC; + border: solid 0px #EEEEEE +} + +/* Container */ +td.sieve_anyof_right { + background-color:#BDBDBD ; + border: solid 1px #AAAAAA; +} +/************* + * Sieve Test Cases + *************/ + +table.sieve_test_container { + width:100%; + background-color:#F8F8F8; + margin: 0px; + border-spacing: 0px ; + padding:0px; + border: solid 1px #AAAAAA; +} + +table.sieve_test_case { + width:100%; + margin: 0px; + border-spacing: 0px ; + padding:0px; +} + + + +td.container_, div.container_{ + padding-left:2px; + border-left: solid 2px #F8F8F8; +} + +td.container_:hover,div.container_:hover { + border-left: solid 2px black; + display:block; +} + + + diff --git a/include/class_sieve.inc b/include/class_sieve.inc deleted file mode 100644 index 16b50f687..000000000 --- a/include/class_sieve.inc +++ /dev/null @@ -1,519 +0,0 @@ - - * - * 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 -*/ - - -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 "
Trying to receive $this->err_len bytes for result
"; - $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 "
Trying to receive ".($this->err_len-$this->err_recv)." bytes for result
"; - $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 "UNKNOWN ERROR (Please report this line to danellis@rushmore.com to include in future releases): $this->line
"; - return false; - } /* end else */ - } /* end get_response() */ - - function sieve($host, $port, $user, $pass, $auth="", $auth_types="PLAIN DIGEST-MD5") - { - $this->host=$host; - $this->port=$port; - $this->user=$user; - $this->pass=$pass; - if(!strcmp($auth, "")) /* If there is no auth user, we deem the user itself to be the auth'd user */ - $this->auth = $this->user; - else - $this->auth = $auth; - $this->auth_types=$auth_types; /* Allowed authentication types */ - $this->fp=0; - $this->line=""; - $this->retval=""; - $this->tmpfile=""; - $this->fh=0; - $this->len=0; - $this->capabilities=""; - $this->loggedin=false; - $this->error= ""; - $this->error_raw=""; - } - - function parse_for_quotes($string) - { - /* This function tokenizes a line of input by quote marks and returns them as an array */ - - $start = -1; - $index = 0; - - for($ptr = 0; $ptr < strlen($string); $ptr++){ - if($string[$ptr] == '"' and $string[$ptr] != '\\'){ - if($start == -1){ - $start = $ptr; - } /* end if */ - else{ - $token[$index++] = substr($string, $start + 1, $ptr - $start - 1); - $found = true; - $start = -1; - } /* end else */ - - } /* end if */ - - } /* end for */ - - if(isset($token)) - return $token; - else - return false; - } /* end function */ - - function status($string) - { - //this should probably be replaced by a smarter parser. - - /* Need to remove this and all dependencies from the class */ - - switch (substr($string, 0,2)){ - case "NO": - return F_NO; //there should be some function to extract the error code from this line - //NO ("quota") "You are oly allowed x number of scripts" - break; - case "OK": - return F_OK; - break; - default: - switch ($string[0]){ - case "{": - //do parse here for {}'s maybe modify parse_for_quotes to handle any parse delimiter? - return F_HEAD; - break; - default: - return F_DATA; - break; - } /* end switch */ - } /* end switch */ - } /* end status() */ - - function sieve_login() - { - - $this->fp=fsockopen($this->host,$this->port); - if($this->fp == false) - return false; - - $this->line=fgets($this->fp,1024); - - //Hack for older versions of Sieve Server. They do not respond with the Cyrus v2. standard - //response. They repsond as follows: "Cyrus timsieved v1.0.0" "SASL={PLAIN,........}" - //So, if we see IMLEMENTATION in the first line, then we are done. - - if(ereg("IMPLEMENTATION",$this->line)) - { - //we're on the Cyrus V2 sieve server - while(sieve::status($this->line) == F_DATA){ - - $this->item = sieve::parse_for_quotes($this->line); - - if(strcmp($this->item[0], "IMPLEMENTATION") == 0) - $this->capabilities["implementation"] = $this->item[1]; - - elseif(strcmp($this->item[0], "SIEVE") == 0 or strcmp($this->item[0], "SASL") == 0){ - - if(strcmp($this->item[0], "SIEVE") == 0) - $this->cap_type="modules"; - else - $this->cap_type="auth"; - - $this->modules = split(" ", $this->item[1]); - if(is_array($this->modules)){ - foreach($this->modules as $this->module) - $this->capabilities[$this->cap_type][$this->module]=true; - } /* end if */ - elseif(is_string($this->modules)) - $this->capabilites[$this->cap_type][$this->modules]=true; - } - else{ - $this->capabilities["unknown"][]=$this->line; - } - $this->line=fgets($this->fp,1024); - - }// end while - } - else - { - //we're on the older Cyrus V1. server - //this version does not support module reporting. We only have auth types. - $this->cap_type="auth"; - - //break apart at the "Cyrus timsieve...." "SASL={......}" - $this->item = sieve::parse_for_quotes($this->line); - - $this->capabilities["implementation"] = $this->item[0]; - - //we should have "SASL={..........}" now. Break out the {xx,yyy,zzzz} - $this->modules = substr($this->item[1], strpos($this->item[1], "{"),strlen($this->item[1])-1); - - //then split again at the ", " stuff. - $this->modules = split($this->modules, ", "); - - //fill up our $this->modules property - if(is_array($this->modules)){ - foreach($this->modules as $this->module) - $this->capabilities[$this->cap_type][$this->module]=true; - } /* end if */ - elseif(is_string($this->modules)) - $this->capabilites[$this->cap_type][$this->module]=true; - } - - - - - if(sieve::status($this->line) == F_NO){ //here we should do some returning of error codes? - $this->error=EC_UNKNOWN; - $this->error_raw = "Server not allowing connections."; - return false; - } - - /* decision login to decide what type of authentication to use... */ - - /* Loop through each allowed authentication type and see if the server allows the type */ - foreach(split(" ",$this->auth_types) as $auth_type) - { - if ($this->capabilities["auth"][$auth_type]) - { - /* We found an auth type that is allowed. */ - $this->auth_in_use = $auth_type; - break; - } - } - - /* Fill error message if no auth types are present */ - if (!isset($this->capabilities["auth"])){ - $this->error=EC_UNKNOWN; - $this->error_raw = "No authentication methods found - please check your sieve setup for missing sasl modules"; - return false; - } - - /* call our authentication program */ - return sieve::authenticate(); - - } - - function sieve_logout() - { - if($this->loggedin==false) - return false; - - fputs($this->fp,"LOGOUT\r\n"); - fclose($this->fp); - $this->loggedin=false; - return true; - } - - function sieve_sendscript($scriptname, $script) - { - if($this->loggedin==false) - return false; - $this->script=stripslashes($script); - $len=strlen($this->script); - fputs($this->fp, "PUTSCRIPT \"$scriptname\" {".$len."+}\r\n"); - fputs($this->fp, "$this->script\r\n"); - - return sieve::get_response(); - - } - - //it appears the timsieved does not honor the NUMBER type. see lex.c in timsieved src. - //don't expect this function to work yet. I might have messed something up here, too. - function sieve_havespace($scriptname, $scriptsize) - { - if($this->loggedin==false) - return false; - fputs($this->fp, "HAVESPACE \"$scriptname\" $scriptsize\r\n"); - return sieve::get_response(); - - } - - function sieve_setactivescript($scriptname) - { - if($this->loggedin==false) - return false; - - fputs($this->fp, "SETACTIVE \"$scriptname\"\r\n"); - return sieve::get_response(); - - } - - function sieve_getscript($scriptname) - { - unset($this->script); - if($this->loggedin==false) - return false; - - fputs($this->fp, "GETSCRIPT \"$scriptname\"\r\n"); - return sieve::get_response(); - - } - - - function sieve_deletescript($scriptname) - { - if($this->loggedin==false) - return false; - - fputs($this->fp, "DELETESCRIPT \"$scriptname\"\r\n"); - - return sieve::get_response(); - } - - - function sieve_listscripts() - { - fputs($this->fp, "LISTSCRIPTS\r\n"); - sieve::get_response(); //should always return true, even if there are no scripts... - if(isset($this->found_script) and $this->found_script) - return true; - else{ - $this->error=EC_NOSCRIPTS; //sieve::getresponse has no way of telling wether a script was found... - $this->error_raw="No scripts found for this account."; - return false; - } - } - - function sieve_alive() - { - if(!isset($this->fp) or $this->fp==0){ - $this->error = EC_NOT_LOGGED_IN; - return false; - } - elseif(feof($this->fp)){ - $this->error = EC_NOT_LOGGED_IN; - return false; - } - else - return true; - } - - function authenticate() - { - - switch ($this->auth_in_use) { - - case "PLAIN": - $auth=base64_encode("$this->user\0$this->auth\0$this->pass"); - - $this->len=strlen($auth); - fputs($this->fp, "AUTHENTICATE \"PLAIN\" {".$this->len."+}\r\n"); - fputs($this->fp, "$auth\r\n"); - - $this->line=fgets($this->fp,1024); - while(sieve::status($this->line) == F_DATA) - $this->line=fgets($this->fp,1024); - - if(sieve::status($this->line) == F_NO) - return false; - $this->loggedin=true; - return true; - break; - - default: - return false; - break; - - }//end switch - - - }//end authenticate() - - -} - - - -?> diff --git a/include/sieve/class_My_Parser.inc b/include/sieve/class_My_Parser.inc new file mode 100644 index 000000000..ac99301a6 --- /dev/null +++ b/include/sieve/class_My_Parser.inc @@ -0,0 +1,78 @@ +registeredExtensions_ = array(); + $this->parent = $parent; + } + + function execute() + { + $ret = $this->dumpParseTree(); + return($ret); + } + + + /* Check if there are errors, collect them and return them */ + function check() + { + return($this->tree_->check()); + } + + + /* Initiate parser, but use some other + * classes, that are rewritten. + */ + function parse($script) + { + $script = preg_replace("/^###GOSA/","",$script); + + $this->registeredExtensions_ = array(); + $this->status_text = "incomplete"; + $this->script_ = $script; + $this->tree_ = new My_Tree(@Scanner::scriptStart(),$this); + $this->tree_->setDumpFunc(array(&$this, 'dumpToken_')); + $this->scanner_ = new My_Scanner($this->script_); + $this->scanner_->setCommentFunc(array($this, 'comment_')); + + if ($this->commands_($this->tree_->getRoot()) && + $this->scanner_->nextTokenIs('script-end')) + { + $this->scanner_->nextToken(); + return $this->success_('success'); + } + + return $this->status_; + } + + + function get_sieve_script() + { + return("###GOSA\n".$this->tree_->get_sieve_script()); + } + + + function save_object() + { + $this->tree_->save_object(); + } + + + function dumpParseTree() + { + return $this->tree_->execute(); + } +} +?> diff --git a/include/sieve/class_My_Scanner.inc b/include/sieve/class_My_Scanner.inc new file mode 100644 index 000000000..878927a5f --- /dev/null +++ b/include/sieve/class_My_Scanner.inc @@ -0,0 +1,69 @@ +token_match_ as $class => $regex) + { + if (preg_match('/^'. $regex .'/', mb_substr($script, $pos), $match)) + { + $length = mb_strlen($match[0]); + + if ($class != 'whitespace') + { + array_push($this->tokens_, array( + 'class' => $class, + 'text' => chop(mb_substr($script, $pos, $length)), + 'line' => $line, + )); + } + if ($class == 'unknown') + { + return; + } + + $pos += $length; + $line += mb_substr_count($match[0], "\n"); + break; + } + } + } + array_push($this->tokens_, array( + 'class' => 'script-end', + 'text' => 'script-end', + 'line' => $line, + )); + } + + var $commentFn_ = null; + var $tokenPos_ = 0; + var $tokens_ = array(); + var $token_match_ = array ( + 'left-bracket' => '\[', + 'right-bracket' => '\]', + 'block-start' => '\{', + 'block-end' => '\}', + 'left-parant' => '\(', + 'right-parant' => '\)', + 'comma' => ',', + 'semicolon' => ';', + 'whitespace' => '[ \r\n\t]+', + 'tag' => ':[[:alpha:]_][[:alnum:]_]*(?=\b)', + 'quoted-string' => '"(?:\\[\\"]|[^\x00"])*"', + 'number' => '[[:digit:]]+(?:[KMG])?(?=\b)', + 'comment' => '(?:\/\*(?:[^\*]|\*(?=[^\/]))*\*\/|#[^\r\n]*\r?\n)', +# 'multi-line' => 'text:[ \t]*(?:#[^\r\n]*)?\r?\n(\.[^\r\n]+\r?\n|[^\.]*\r?\n)*\.\r?\n', + 'multi-line' => 'text:[^;]*', + 'identifier' => '[[:alpha:]_][[:alnum:]_]*(?=\b)', + 'unknown token' => '[^ \r\n\t]+' + ); +} + +?> diff --git a/include/sieve/class_My_Tree.inc b/include/sieve/class_My_Tree.inc new file mode 100644 index 000000000..99a076f3a --- /dev/null +++ b/include/sieve/class_My_Tree.inc @@ -0,0 +1,782 @@ +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_ .= "
"; + $this->dump_ .= "
"; + } + 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_ .= "
"; + $this->dump_ .= "
"; + } + } + } + + 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; $idoDump_($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 "Missing : ".$class_name.""."
"; + } + } + + function save_object() + { + reset($this->pap); + foreach($this->pap as $key => $obj){ + + if(in_array(get_class($obj),array("sieve_if", + "sieve_elsif", + "sieve_vacation", + "sieve_comment", + "sieve_reject", + "sieve_fileinto", + "sieve_require", + "sieve_redirect"))){ + + + if(isset($this->pap[$key]) && method_exists($this->pap[$key],"save_object")){ + $this->pap[$key]->save_object(); + } + } + } + } + + + /* Remove the object at the given position */ + function remove_object($key_id) + { + if(count($this->pap) == 1){ + print_red(_("Can't remove last element.")); + return; + } + + if(!isset($this->pap[$key_id])){ + trigger_error(_("Can't remove element with object_id=".$key_id.", there is no object with this identifier. Remove aborted.")); + return(false); + } + + $class = get_class($this->pap[$key_id]); + if(in_array($class,array("sieve_if","sieve_elsif","sieve_else"))){ + $block_start= $key_id; + $block_end = $this->get_block_end($key_id); + + for($i = $block_start ; $i <= $block_end ; $i ++ ){ + unset($this->pap[$i]); + } + }else{ + unset($this->pap[$key_id]); + } + $tmp = array(); + foreach($this->pap as $element){ + $tmp[] = $element; + } + $this->pap = $tmp; + } + + + /* This function moves a given element to another position. + * Single elements like "keep;" will simply be moved one posisition down/up. + * Multiple elements like if-elsif-else will be moved as block. + * + * $key_id specified the element that should be moved. + * $direction specifies to move elements "up" or "down" + */ + function move_up_down($key_id,$direction = "down") + { + + /* Get the current element to decide what to move. */ + $e_class = get_class($this->pap[$key_id]); + + if(in_array($e_class,array("sieve_if"))){ + $block_start= $key_id; + $block_end = $this->get_block_end($key_id); + + /* Depending on the direction move up down */ + if($direction == "down"){ + $next_free = $this->_get_next_free_move_slot($block_end,$direction); + }else{ + $next_free = $this->_get_next_free_move_slot($block_start,$direction); + } + + /* Move the given block */ + $this->move_multiple_elements($block_start,$block_end,$next_free); + } + + if(in_array($e_class,array( "sieve_stop", + "sieve_keep", + "sieve_require", + "sieve_comment", + "sieve_vacation", + "sieve_stop", + "sieve_reject", + "sieve_fileinto", + "sieve_redirect", + "sieve_discard"))){ + $this->move_single_element($key_id,$this->_get_next_free_move_slot($key_id,$direction)); + } + } + + + /* Move the given block to position */ + function move_multiple_elements($start,$end,$to) + { + /* Use class names for testing */ + $data = $this->pap; + + /* Get block to move */ + $block_to_move = array_slice($data,$start, ($end - $start +1)); + + /* We want do move this block up */ + if($end > $to){ + + /* Get start block */ + $start_block = array_slice($data,0,$to); + + /* Get Get all elements between the block to move + * and next free position + */ + $block_to_free = array_slice($data,$to ,$start - $to ); + $block_to_end = array_slice($data,$end+1); + $new = array(); + foreach($start_block as $block){ + $new[] = $block; + } + foreach($block_to_move as $block){ + $new[] = $block; + } + foreach($block_to_free as $block){ + $new[] = $block; + } + foreach($block_to_end as $block){ + $new[] = $block; + } + $old = $this->pap; + $this->pap = $new; + } + + + /* We want to move this block down. */ + if($to > $end){ + + /* Get start block */ + $start_block = array_slice($data,0,$start); + + /* Get Get all elements between the block to move + * and next free position + */ + $block_to_free = array_slice($data,$end +1,($to - $end )); + + /* Get the rest + */ + $block_to_end = array_slice($data,$to+1); + + $new = array(); + foreach($start_block as $block){ + $new[] = $block; + } + foreach($block_to_free as $block){ + $new[] = $block; + } + foreach($block_to_move as $block){ + $new[] = $block; + } + foreach($block_to_end as $block){ + $new[] = $block; + } + $old = $this->pap; + $this->pap = $new; + } + } + + + /* This function returns the id of the element + * where the current block ends + */ + function get_block_end($start,$complete = TRUE) + { + /* Only execute if this is a really a block element. + * Block elements is only sieve_if + */ + if(in_array(get_class($this->pap[$start]),array("sieve_if","sieve_elsif","sieve_else"))){ + + $class = get_class($this->pap[$start]); + $next_class = get_class($this->pap[$start+1]); + $block_depth = 0; + + $end = FALSE; + + while(!$end && $start < count($this->pap)){ + + if($class == "sieve_block_start"){ + $block_depth ++; + } + + if($class == "sieve_block_end"){ + $block_depth --; + } + + if($complete){ + if( $block_depth == 0 && + $class == "sieve_block_end" && + !in_array($next_class,array("sieve_else","sieve_elsif"))){ + $end = TRUE; + $start --; + } + }else{ + + if( $block_depth == 0 && + $class == "sieve_block_end" ){ + $end = TRUE; + $start --; + } + } + + $start ++; + $class = get_class($this->pap[$start]); + + if(isset($this->pap[$start+1])){ + $next_class = get_class($this->pap[$start+1]); + }else{ + $next_class =""; + } + } + } + return($start); + } + + + /* This function moves the single element at + * position $from to position $to. + */ + function move_single_element($from,$to) + { + if($from == $to) { + return; + } + + $ret = array(); + $tmp = $this->pap; + + $begin = array(); + $middle = array(); + $end = array(); + $element = $this->pap[$from]; + + if($from > $to ){ + + /* Get all element in fron to element to move */ + if($from != 0){ + $begin = array_slice($tmp,0,$to); + } + + /* Get all elements between */ + $middle = array_slice($tmp,$to , ($from - ($to) )); + + /* Get the rest */ + $end = array_slice($tmp,$from+1); + + foreach($begin as $data){ + $ret[] = $data; + } + $ret[] = $element; + foreach($middle as $data){ + $ret[] = $data; + } + foreach($end as $data){ + $ret[] = $data; + } + $this->pap = $ret; + } + if($from < $to ){ + + /* Get all element in fron to element to move */ + if($from != 0){ + $begin = array_slice($tmp,0,$from); + } + + /* Get all elements between */ + $middle = array_slice($tmp,$from+1 , ($to - ($from))); + + /* Get the rest */ + $end = array_slice($tmp,$to+1); + + foreach($begin as $data){ + $ret[] = $data; + } + foreach($middle as $data){ + $ret[] = $data; + } + $ret[] = $element; + foreach($end as $data){ + $ret[] = $data; + } + $this->pap = $ret; + } + } + + + /* Returns the next free position where we + * can add a new sinle element + * $key_id = Current position + * $direction = Forward or backward. + */ + function _get_next_free_move_slot($key_id,$direction,$include_self = FALSE) + { + $last_class = ""; + $current_class =""; + $next_class = ""; + + /* After this elements we can add new elements + * without having any trouble. + */ + $allowed_to_add_after = array("sieve_keep", + "sieve_require", + "sieve_stop", + "sieve_reject", + "sieve_fileinto", + "sieve_redirect", + "sieve_discard", + "sieve_comment", + "sieve_block_start" + ); + + /* Before this elements we can add new elements + * without having any trouble. + */ + $allowed_to_add_before = array("sieve_keep", + "sieve_require", + "sieve_stop", + "sieve_reject", + "sieve_fileinto", + "sieve_comment", + "sieve_redirect", + "sieve_discard", + "sieve_if", + "sieve_block_end" + ); + + if($direction == "down"){ + + $test = $this->pap; + while($key_id < count($test)){ + if(($key_id+1) == count($test)) { + return($key_id); + } + + if(!$include_self){ + $key_id ++; + } + $include_self = FALSE; + $current_class = get_class($test[$key_id]); + if(in_array($current_class, $allowed_to_add_after)){ + return($key_id); + } + } + }else{ + + $test = $this->pap; + if($key_id == 0) { + return($key_id); + } + if(!$include_self){ + $key_id --; + } + while($key_id >=0 ){ + $current_class = get_class($test[$key_id]); + if(in_array($current_class, $allowed_to_add_before)){ + return($key_id); + } + $key_id --; + } + return(0); + } + } + + + /* Need to be reviewed */ + function get_sieve_script() + { + $tmp =""; + if(count($this->pap)){ + $buffer = ""; + foreach($this->pap as $part) { + if(get_class($part) == "sieve_block_end"){ + $buffer = substr($buffer,0,strlen($buffer)-(strlen(SIEVE_INDENT_TAB))); + } + $tmp2 = $part->get_sieve_script_part(); + + $tmp3 = split("\n",$tmp2); + foreach($tmp3 as $str){ + $str2 = trim($str); + + /* If the current line only contains an '.' + * we must skip the line indent. + * The text: statement uses a single '.' to mark the text end. + * This '.' must be the only char in the current line, no + * whitespaces are allowed here. + */ + if($str2 == "."){ + $tmp.=$str."\n"; + }else{ + $tmp.= $buffer.$str."\n"; + } + } + if(get_class($part) == "sieve_block_start"){ + $buffer .= SIEVE_INDENT_TAB; + } + } + } + if(!preg_match("/Generated by GOsa - Gonicus System Administrator/",$tmp)){ +# $tmp = "#Generated by GOsa - Gonicus System Administrator \n ".$tmp; + } + return($tmp); + } + + function check() + { + $msgs = array(); + + /* Some logical checks. + * like : only sieve_comment can appear before require. + */ + + /* Ensure that there are no command before require + * - Get id of last require tag + * - Collect object types in from of this tag. + * - Check if there are tags collected that are not allowed + */ + $last_found_at = -1; + $objs = array(); + foreach($this->pap as $key => $obj){ + if(get_class($obj) == "sieve_require"){ + $last_found_at = $key; + } + } + foreach($this->pap as $key => $obj){ + if($key == $last_found_at) break; + if(!in_array(get_class($obj),array("sieve_comment","sieve_require"))){ + $objs[] = get_class($obj); + } + } + if(count($objs) && $last_found_at != -1){ + $str = _("Require must be the first command in the script."); + $msgs[] = $str; + print_red($str);; + } + + foreach($this->pap as $obj){ + $o_msgs = $obj->check(); + foreach($o_msgs as $o_msg){ + $msgs[] = $o_msg; + } + } + return($msgs); + } + + + /* We are forced to add a new require. + * This function is called by the + * sieveElement_Classes->parent->add_require() + */ + function add_require($str) + { + $require_id = -1; + foreach($this->pap as $key => $obj){ + if(get_class($obj) == "sieve_require"){ + $require_id = $key; + } + } + + /* No require found, add one */ + if($require_id == -1){ + $require = new sieve_require(NULL,preg_replace("/[^0-9]/","",microtime()),$this); + $require -> Add_Require($str); + $new = array(); + $new[] = $require; + foreach($this->pap as $obj){ + $new[] = $obj; + } + $this->pap = $new; + } else { + $this->pap[$require_id]->Add_Require($str); + } + } +} + + +/* Create valid sieve string/string-list + * out of a given array + */ +function sieve_create_strings($data,$force_string = FALSE) +{ + $ret = ""; + if(is_array($data)){ + if(count($data) == 1){ + $ret = "\""; + foreach($data as $dat){ + $ret .=$dat; + } + $ret.="\""; + }else{ + foreach($data as $dat){ + $ret.= "\""; + $ret.=$dat; + $ret.="\", "; + } + $ret = preg_replace("/,$/","",trim($ret)); + $ret = "[".$ret."]"; + } + $ret = preg_replace("/\"\"/","\"",$ret); + }else{ + + $Multiline = preg_match("/\n/",$data); + $data = preg_replace("/\r/","",$data);; + + if($Multiline && !$force_string){ + $ret = "text: \r\n".$data."\r\n.\r\n"; + }else{ + $ret = "\"".$data."\""; + $ret = preg_replace("/\"\"/","\"",$ret); + } + } + $ret = preg_replace("/\n/","\r\n",$ret); + + return($ret); +} + +/* This checks if there is a string at the current position + * in the token array. + * If there is a string list at the current position, + * this function will return a complete list of all + * strings used in this list. + * It also returns an offset of the last token position + */ +function sieve_get_strings($data,$id) +{ + $ret = array(); + if($data[$id]['class'] == "left-bracket"){ + while(isset($data[$id]) && $data[$id]['class'] != "right-bracket" && $id < count($data)){ + + if($data[$id]['class'] == "quoted-string"){ + $text = $data[$id]['text']; + $text= preg_replace("/^\"/","",$text); + $text= preg_replace("/\"$/","",$text); + $ret[] = $text; + } + + $id ++; + } + }elseif($data[$id]['class'] == "quoted-string"){ + $text = $data[$id]['text']; + $text= preg_replace("/^\"/","",$text); + $text= preg_replace("/\"$/","",$text); + $ret[] = $text; + }elseif($data[$id]['class'] == "number"){ + $ret[] = $data[$id]['text']; + }elseif($data[$id]['class'] == "multi-line"){ + $str = trim(preg_replace("/^text:/","",$data[$id]['text'])); + $str = trim(preg_replace("/\.$/","",$str)); + $ret[] = $str; + } + + return(array("OFFSET" => $id, "STRINGS" => $ret)); +} + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_parser.inc b/include/sieve/class_parser.inc new file mode 100644 index 000000000..345895231 --- /dev/null +++ b/include/sieve/class_parser.inc @@ -0,0 +1,365 @@ +registeredExtensions_ = array(); + $this->status_text = "incomplete"; + + $this->script_ = $script; + $this->tree_ = new Tree(Scanner::scriptStart()); + $this->tree_->setDumpFunc(array(&$this, 'dumpToken_')); + $this->scanner_ = new Scanner($this->script_); + $this->scanner_->setCommentFunc(array($this, 'comment_')); + + if ($this->commands_($this->tree_->getRoot()) && + $this->scanner_->nextTokenIs('script-end')) + { + return $this->success_('success'); + } + + return $this->status_; + } + + function dumpParseTree() + { + return $this->tree_->dump(); + } + + function dumpToken_(&$token) + { + if (is_array($token)) + { + $str = "<" . $token['text'] . "> "; + foreach ($token as $k => $v) + { + $str .= " $k:$v"; + } + return $str; + } + + return strval($token); + } + + function getPrevTokenText_($parent_id) + { + $childs = $this->tree_->getChilds($parent_id); + + for ($i=count($childs); $i>0; --$i) + { + $prev = $this->tree_->getNode($childs[$i-1]); + + if (in_array($prev['text'], array('{', '(', ','))) + { + // use command owning a block or list + $prev = $this->tree_->getNode($parent_id); + } + + if ($prev['class'] != 'comment') + { + return $prev['text']; + } + } + + $prev = $this->tree_->getNode($parent_id); + return $prev['text']; + } + + function getSemantics_($token_text) + { + $semantics = new Semantics($token_text); + $semantics->setExtensionFuncs(array(&$this, 'registerExtension_'), array(&$this, 'isExtensionRegistered_')); + return $semantics; + } + + function registerExtension_($extension) + { + array_push($this->registeredExtensions_, str_replace('"', '', $extension)); + } + + function isExtensionRegistered_($extension) + { + return (in_array($extension, $this->registeredExtensions_) ? true : false); + } + + function success_($text = null) + { + if ($text != null) + { + $this->status_text = $text; + } + + return $this->status_ = true; + } + + function error_($text, $token = null) + { + if ($token != null) + { + $text = 'line '. $token['line'] .': '. $token['class'] . " where $text expected near ". $token['text']; + } + + $this->status_text = $text; + return $this->status_ = false; + } + + function done_() + { + $this->status_ = true; + return false; + } + + /******************************************************************************* + * methods for recursive descent start below + */ + + function comment_($token) + { + $this->tree_->addChild($token); + } + + function commands_($parent_id) + { + while ($this->command_($parent_id)) + ; + + return $this->status_; + } + + function command_($parent_id) + { + if (!$this->scanner_->nextTokenIs('identifier')) + { + if ($this->scanner_->nextTokenIs(array('block-end', 'script-end'))) + { + return $this->done_(); + } + return $this->error_('identifier', $this->scanner_->peekNextToken()); + } + + // Get and check a command token + $token = $this->scanner_->nextToken(); + $semantics = $this->getSemantics_($token['text']); + if (!$semantics->validCommand($this->getPrevTokenText_($parent_id), $token['line'])) + { + return $this->error_($semantics->message); + } + + // Process eventual arguments + $this_node = $this->tree_->addChildTo($parent_id, $token); + if ($this->arguments_($this_node, $semantics) == false) + { + return false; + } + + $token = $this->scanner_->nextToken(); + if ($token['class'] != 'semicolon') + { + if (!$semantics->validToken($token['class'], $token['text'], $token['line'])) + { + return $this->error_($semantics->message); + } + + if ($token['class'] == 'block-start') + { + $this->tree_->addChildTo($this_node, $token); + $ret = $this->block_($this_node, $semantics); + return $ret; + } + + return $this->error_('semicolon', $token); + } + + $this->tree_->addChildTo($this_node, $token); + return $this->success_(); + } + + function arguments_($parent_id, &$semantics) + { + while ($this->argument_($parent_id, &$semantics)) + ; + + if ($this->status_ == true) + { + $this->testlist_($parent_id, $semantics); + } + + return $this->status_; + } + + function argument_($parent_id, &$semantics) + { + if ($this->scanner_->nextTokenIs(array('number', 'tag'))) + { + // Check if semantics allow a number or tag + $token = $this->scanner_->nextToken(); + if (!$semantics->validToken($token['class'], $token['text'], $token['line'])) + { + return $this->error_($semantics->message); + } + + $this->tree_->addChildTo($parent_id, $token); + return $this->success_(); + } + + return $this->stringlist_($parent_id, &$semantics); + } + + function stringlist_($parent_id, &$semantics) + { + if (!$this->scanner_->nextTokenIs('left-bracket')) + { + return $this->string_($parent_id, &$semantics); + } + + $token = $this->scanner_->nextToken(); + if (!$semantics->startStringList($token['line'])) + { + return $this->error_($semantics->message); + } + $this->tree_->addChildTo($parent_id, $token); + + while ($token['class'] != 'right-bracket') + { + if (!$this->string_($parent_id, &$semantics)) + { + return $this->status_; + } + + $token = $this->scanner_->nextToken(); + + if ($token['class'] != 'comma' && $token['class'] != 'right-bracket') + { + return $this->error_('comma or closing bracket', $token); + } + + $this->tree_->addChildTo($parent_id, $token); + } + + $semantics->endStringList(); + return $this->success_(); + } + + function string_($parent_id, &$semantics) + { + if (!$this->scanner_->nextTokenIs(array('quoted-string', 'multi-line'))) + { + return $this->done_(); + } + + $token = $this->scanner_->nextToken(); + if (!$semantics->validToken('string', $token['text'], $token['line'])) + { + return $this->error_($semantics->message); + } + + $this->tree_->addChildTo($parent_id, $token); + return $this->success_(); + } + + function testlist_($parent_id, &$semantics) + { + if (!$this->scanner_->nextTokenIs('left-parant')) + { + return $this->test_($parent_id, $semantics); + } + + $token = $this->scanner_->nextToken(); + if (!$semantics->validToken($token['class'], $token['text'], $token['line'])) + { + return $this->error_($semantics->message); + } + $this->tree_->addChildTo($parent_id, $token); + + while ($token['class'] != 'right-parant') + { + if (!$this->test_($parent_id, $semantics)) + { + return $this->status_; + } + + $token = $this->scanner_->nextToken(); + + if ($token['class'] != 'comma' && $token['class'] != 'right-parant') + { + return $this->error_('comma or closing paranthesis', $token); + } + + $this->tree_->addChildTo($parent_id, $token); + } + + return $this->success_(); + } + + function test_($parent_id, &$semantics) + { + if (!$this->scanner_->nextTokenIs('identifier')) + { + // There is no test + return $this->done_(); + } + + // Check if semantics allow an identifier + $token = $this->scanner_->nextToken(); + if (!$semantics->validToken($token['class'], $token['text'], $token['line'])) + { + return $this->error_($semantics->message); + } + + // Get semantics for this test command + $this_semantics = $this->getSemantics_($token['text']); + if (!$this_semantics->validCommand($this->getPrevTokenText_($parent_id), $token['line'])) + { + return $this->error_($this_semantics->message); + } + + $this_node = $this->tree_->addChildTo($parent_id, $token); + + // Consume eventual argument tokens + if (!$this->arguments_($this_node, $this_semantics)) + { + return false; + } + + // Check if arguments were all there + $token = $this->scanner_->peekNextToken(); + if (!$this_semantics->done($token['class'], $token['text'], $token['line'])) + { + return $this->error_($this_semantics->message); + } + + return true; + } + + function block_($parent_id, &$semantics) + { + if ($this->commands_($parent_id, $semantics)) + { + $token = $this->scanner_->nextToken(); + + if ($token['class'] != 'block-end') + { + return $this->error_('closing curly brace', $token); + } + + $this->tree_->addChildTo($parent_id, $token); + return $this->success_(); + } + return $this->status_; + } +} + +?> diff --git a/include/sieve/class_scanner.inc b/include/sieve/class_scanner.inc new file mode 100644 index 000000000..3e22bb1d0 --- /dev/null +++ b/include/sieve/class_scanner.inc @@ -0,0 +1,140 @@ +_construct($script); + } + + function _construct(&$script) + { + if ($script === null) + { + return; + } + + $this->tokenize($script); + } + + function setCommentFunc($callback) + { + if ($callback == null || is_callable($callback)) + { + $this->commentFn_ = $callback; + } + } + + function tokenize(&$script) + { + $pos = 0; + $line = 1; + $script_length = mb_strlen($script); + + while ($pos < $script_length) + { + foreach ($this->token_match_ as $class => $regex) + { + if (preg_match('/^'. $regex .'/', mb_substr($script, $pos), $match)) + { + $length = mb_strlen($match[0]); + + if ($class != 'whitespace') + { + array_push($this->tokens_, array( + 'class' => $class, + 'text' => chop(mb_substr($script, $pos, $length)), + 'line' => $line, + )); + } + if ($class == 'unknown') + { + return; + } + + $pos += $length; + $line += mb_substr_count($match[0], "\n"); + break; + } + } + } + + array_push($this->tokens_, array( + 'class' => 'script-end', + 'text' => 'script-end', + 'line' => $line, + )); + } + + function nextTokenIs($class) + { + $offset = 0; + do + { + $next = $this->tokens_[$this->tokenPos_ + $offset++]['class']; + } + while ($next == 'comment'); + + if (is_array($class)) + { + return in_array($next, $class); + } + else if (is_string($class)) + { + return (strcmp($next, $class) == 0); + } + return false; + } + + function peekNextToken() + { + return $this->tokens_[$this->tokenPos_]; + } + + function nextToken() + { + $token = $this->tokens_[$this->tokenPos_++]; + while ($token['class'] == 'comment') + { + if ($this->commentFn_ != null) + { + call_user_func($this->commentFn_, $token); + } + $token = $this->tokens_[$this->tokenPos_++]; + } + return $token; + } + + function scriptStart() + { + return array( + 'class' => 'script-start', + 'text' => 'script-start', + 'line' => 1, + ); + } + + var $commentFn_ = null; + var $tokenPos_ = 0; + var $tokens_ = array(); + var $token_match_ = array ( + 'left-bracket' => '\[', + 'right-bracket' => '\]', + 'block-start' => '\{', + 'block-end' => '\}', + 'left-parant' => '\(', + 'right-parant' => '\)', + 'comma' => ',', + 'semicolon' => ';', + 'whitespace' => '[ \r\n\t]+', + 'tag' => ':[[:alpha:]_][[:alnum:]_]*(?=\b)', + 'quoted-string' => '"(?:\\[\\"]|[^\x00"])*"', + 'number' => '[[:digit:]]+(?:[KMG])?(?=\b)', + 'comment' => '(?:\/\*(?:[^\*]|\*(?=[^\/]))*\*\/|#[^\r\n]*\r?\n)', + 'multi-line' => 'text:[ \t]*(?:#[^\r\n]*)?\r?\n(\.[^\r\n]+\r?\n|[^\.]*\r?\n)*\.\r?\n', + 'identifier' => '[[:alpha:]_][[:alnum:]_]*(?=\b)', + 'unknown token' => '[^ \r\n\t]+' + ); +} + +?> \ No newline at end of file diff --git a/include/sieve/class_semantics.inc b/include/sieve/class_semantics.inc new file mode 100644 index 000000000..1c00051c0 --- /dev/null +++ b/include/sieve/class_semantics.inc @@ -0,0 +1,613 @@ +command_ = $command; + $this->unknown = false; + switch ($command) + { + + /******************** + * control commands + */ + case 'require': + /* require */ + $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 */ + $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 */ + $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 */ + $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"] */ + $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"] */ + $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 */ + $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 */ + /* addflag */ + /* removeflag */ + $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"] */ + $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] */ + $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 + anyof */ + $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] */ + $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 */ + $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] */ + $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 */ + $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"> */ + $this->s_ = array( + 'valid_after' => $this->testsValidAfter_, + 'arguments' => array( + array('class' => 'tag', 'occurrences' => '1', 'values' => array( + array('occurrences' => '1', 'regex' => ':(over|under)', 'name' => 'size-type') + )), + array('class' => 'number', 'occurrences' => '1', 'values' => array( + array('occurrences' => '1', 'regex' => '.*', 'name' => 'limit') + )) + ) + ); + break; + + case 'true': + case 'false': + /* true / false */ + $this->s_ = array( + 'valid_after' => $this->testsValidAfter_ + ); + break; + + + /******************** + * unknown commands + */ + default: + $this->unknown = true; + } + } + + function setExtensionFuncs($setFn, $checkFn) + { + if (is_callable($setFn) && is_callable($checkFn)) + { + $this->registerExtensionFn_ = $setFn; + $this->isExtensionRegisteredFn_ = $checkFn; + } + } + + function setRequire_($extension) + { + call_user_func($this->registerExtensionFn_, $extension); + return true; + } + + function wasRequired_($extension) + { + return call_user_func($this->isExtensionRegisteredFn_, $extension); + } + + function setMatchType_($text) + { + // Do special processing for relational test extension + if ($text == ':count' || $text == ':value') + { + if (!$this->wasRequired_('relational')) + { + $this->message = 'missing require for match-type '. $text; + return false; + } + + array_unshift($this->s_['arguments'], + array('class' => 'string', 'occurrences' => '1', 'values' => array( + array('occurrences' => '1', 'regex' => '"(lt|le|eq|ge|gt|ne)"', 'name' => 'relation-string'), + )) + ); + } + // Do special processing for regex match-type extension + else if ($text == ':regex' && !$this->wasRequired_('regex')) + { + $this->message = 'missing require for match-type '. $text; + return false; + } + $this->matchType_ = $text; + return true; + } + + function setComparator_($text) + { + $this->comparator_ = $text; + return true; + } + + function checkAddrPart_($text) + { + if ($text == ':user' || $text == ':detail') + { + if (!$this->wasRequired_('subaddress')) + { + $this->message = 'missing require for tag '. $text; + return false; + } + } + return true; + } + + function checkTags_() + { + if (isset($this->matchType_) && + $this->matchType_ == ':count' && + $this->comparator_ != '"i;ascii-numeric"') + { + $this->message = 'match-type :count needs comparator i;ascii-numeric'; + return false; + } + return true; + } + + function validCommand($prev, $line) + { + // Check if command is known + if ($this->unknown) + { + $this->message = 'line '. $line .': unknown command "'. $this->command_ .'"'; + return false; + } + + // Check if the command needs to be required + if (isset($this->s_['requires']) && !$this->wasRequired_($this->s_['requires'])) + { + $this->message = 'line '. $line .': missing require for command "'. $this->command_ .'"'; + return false; + } + + // Check if command may appear here + if (!ereg($this->s_['valid_after'], $prev)) + { +# $this->message = 'line '. $line .': "'. $this->command_ .'" may not appear after "'. $prev .'"'; +# return false; + } + + return true; + } + + function validClass_($class, $id) + { + // Check if command expects any arguments + if (!isset($this->s_['arguments'])) + { + $this->message = $id .' where semicolon expected'; + return false; + } + + foreach ($this->s_['arguments'] as $arg) + { + if ($class == $arg['class']) + { + return true; + } + + // Is the argument required + if ($arg['occurrences'] != '?' && $arg['occurrences'] != '*') + { + $this->message = $id .' where '. $arg['class'] .' expected'; + return false; + } + + if (isset($arg['post-call']) && + !call_user_func(array(&$this, $arg['post-call']))) + { + return false; + } + array_shift($this->s_['arguments']); + } + + $this->message = 'unexpected '. $id; + return false; + } + + function startStringList($line) + { + if (!$this->validClass_('string', 'string')) + { + $this->message = 'line '. $line .': '. $this->message; + return false; + } + else if (!isset($this->s_['arguments'][0]['list'])) + { + $this->message = 'line '. $line .': '. 'left bracket where '. $this->s_['arguments'][0]['class'] .' expected'; + return false; + } + + $this->s_['arguments'][0]['occurrences'] = '+'; + return true; + } + + function endStringList() + { + array_shift($this->s_['arguments']); + } + + function validToken($class, &$text, &$line) + { + $name = $class . ($class != $text ? " $text" : ''); + + // Make sure the argument has a valid class + if (!$this->validClass_($class, $name)) + { + $this->message = 'line '. $line .': '. $this->message; + return false; + } + + $arg = &$this->s_['arguments'][0]; + foreach ($arg['values'] as $val) + { + if (preg_match('/^'. $val['regex'] .'$/m', $text)) + { + // Check if the argument value needs a 'require' + if (isset($val['requires']) && !$this->wasRequired_($val['requires'])) + { + $this->message = 'line '. $line .': missing require for '. $val['name'] .' '. $text; + return false; + } + + // Check if a possible value of this argument may occur + if ($val['occurrences'] == '?' || $val['occurrences'] == '1') + { + $val['occurrences'] = '0'; + } + else if ($val['occurrences'] == '+') + { + $val['occurrences'] = '*'; + } + else if ($val['occurrences'] == '0') + { + $this->message = 'line '. $line .': too many '. $val['name'] .' '. $class .'s near '. $text; + return false; + } + + // Call extra processing function if defined + if (isset($val['call']) && !call_user_func(array(&$this, $val['call']), $text) || + isset($arg['call']) && !call_user_func(array(&$this, $arg['call']), $text)) + { + $this->message = 'line '. $line .': '. $this->message; + return false; + } + + // Set occurrences appropriately + if ($arg['occurrences'] == '?' || $arg['occurrences'] == '1') + { + array_shift($this->s_['arguments']); + } + else + { + $arg['occurrences'] = '*'; + } + + // Add argument(s) expected to follow right after this one + if (isset($val['add'])) + { + while ($add_arg = array_pop($val['add'])) + { + array_unshift($this->s_['arguments'], $add_arg); + } + } + + return true; + } + } + + $this->message = 'line '. $line .': unexpected '. $name; + return false; + } + + function done($class, $text, $line) + { + if (isset($this->s_['arguments'])) + { + foreach ($this->s_['arguments'] as $arg) + { + if ($arg['occurrences'] == '+' || $arg['occurrences'] == '1') + { + $this->message = 'line '. $line .': '. $class .' '. $text .' where '. $arg['class'] .' expected'; + return false; + } + } + } + return true; + } +} + +?> diff --git a/include/sieve/class_sieve.inc b/include/sieve/class_sieve.inc new file mode 100644 index 000000000..6fec422fa --- /dev/null +++ b/include/sieve/class_sieve.inc @@ -0,0 +1,516 @@ + + * + * 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 +*/ + + +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 "
Trying to receive $this->err_len bytes for result
"; + $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 "UNKNOWN ERROR (Please report this line to danellis@rushmore.com to include in future releases): $this->line
"; + return false; + } /* end else */ + } /* end get_response() */ + + function sieve($host, $port, $user, $pass, $auth="", $auth_types="PLAIN DIGEST-MD5") + { + $this->host=$host; + $this->port=$port; + $this->user=$user; + $this->pass=$pass; + if(!strcmp($auth, "")) /* If there is no auth user, we deem the user itself to be the auth'd user */ + $this->auth = $this->user; + else + $this->auth = $auth; + $this->auth_types=$auth_types; /* Allowed authentication types */ + $this->fp=0; + $this->line=""; + $this->retval=""; + $this->tmpfile=""; + $this->fh=0; + $this->len=0; + $this->capabilities=""; + $this->loggedin=false; + $this->error= ""; + $this->error_raw=""; + } + + function parse_for_quotes($string) + { + /* This function tokenizes a line of input by quote marks and returns them as an array */ + + $start = -1; + $index = 0; + + for($ptr = 0; $ptr < strlen($string); $ptr++){ + if($string[$ptr] == '"' and $string[$ptr] != '\\'){ + if($start == -1){ + $start = $ptr; + } /* end if */ + else{ + $token[$index++] = substr($string, $start + 1, $ptr - $start - 1); + $found = true; + $start = -1; + } /* end else */ + + } /* end if */ + + } /* end for */ + + if(isset($token)) + return $token; + else + return false; + } /* end function */ + + function status($string) + { + //this should probably be replaced by a smarter parser. + + /* Need to remove this and all dependencies from the class */ + + switch (substr($string, 0,2)){ + case "NO": + return F_NO; //there should be some function to extract the error code from this line + //NO ("quota") "You are oly allowed x number of scripts" + break; + case "OK": + return F_OK; + break; + default: + switch ($string[0]){ + case "{": + //do parse here for {}'s maybe modify parse_for_quotes to handle any parse delimiter? + return F_HEAD; + break; + default: + return F_DATA; + break; + } /* end switch */ + } /* end switch */ + } /* end status() */ + + function sieve_login() + { + + $this->fp=@fsockopen($this->host,$this->port); + if($this->fp == false) + return false; + + $this->line=fgets($this->fp,1024); + + //Hack for older versions of Sieve Server. They do not respond with the Cyrus v2. standard + //response. They repsond as follows: "Cyrus timsieved v1.0.0" "SASL={PLAIN,........}" + //So, if we see IMLEMENTATION in the first line, then we are done. + + if(ereg("IMPLEMENTATION",$this->line)) + { + //we're on the Cyrus V2 sieve server + while(sieve::status($this->line) == F_DATA){ + + $this->item = sieve::parse_for_quotes($this->line); + + if(strcmp($this->item[0], "IMPLEMENTATION") == 0) + $this->capabilities["implementation"] = $this->item[1]; + + elseif(strcmp($this->item[0], "SIEVE") == 0 or strcmp($this->item[0], "SASL") == 0){ + + if(strcmp($this->item[0], "SIEVE") == 0) + $this->cap_type="modules"; + else + $this->cap_type="auth"; + + $this->modules = split(" ", $this->item[1]); + if(is_array($this->modules)){ + foreach($this->modules as $this->module) + $this->capabilities[$this->cap_type][$this->module]=true; + } /* end if */ + elseif(is_string($this->modules)) + $this->capabilites[$this->cap_type][$this->modules]=true; + } + else{ + $this->capabilities["unknown"][]=$this->line; + } + $this->line=fgets($this->fp,1024); + + }// end while + } + else + { + //we're on the older Cyrus V1. server + //this version does not support module reporting. We only have auth types. + $this->cap_type="auth"; + + //break apart at the "Cyrus timsieve...." "SASL={......}" + $this->item = sieve::parse_for_quotes($this->line); + + $this->capabilities["implementation"] = $this->item[0]; + + //we should have "SASL={..........}" now. Break out the {xx,yyy,zzzz} + $this->modules = substr($this->item[1], strpos($this->item[1], "{"),strlen($this->item[1])-1); + + //then split again at the ", " stuff. + $this->modules = split($this->modules, ", "); + + //fill up our $this->modules property + if(is_array($this->modules)){ + foreach($this->modules as $this->module) + $this->capabilities[$this->cap_type][$this->module]=true; + } /* end if */ + elseif(is_string($this->modules)) + $this->capabilites[$this->cap_type][$this->module]=true; + } + + + + + if(sieve::status($this->line) == F_NO){ //here we should do some returning of error codes? + $this->error=EC_UNKNOWN; + $this->error_raw = "Server not allowing connections."; + return false; + } + + /* decision login to decide what type of authentication to use... */ + + /* Loop through each allowed authentication type and see if the server allows the type */ + foreach(split(" ",$this->auth_types) as $auth_type) + { + if ($this->capabilities["auth"][$auth_type]) + { + /* We found an auth type that is allowed. */ + $this->auth_in_use = $auth_type; + break; + } + } + + /* Fill error message if no auth types are present */ + if (!isset($this->capabilities["auth"])){ + $this->error=EC_UNKNOWN; + $this->error_raw = "No authentication methods found - please check your sieve setup for missing sasl modules"; + return false; + } + + /* call our authentication program */ + return sieve::authenticate(); + + } + + function sieve_logout() + { + if($this->loggedin==false) + return false; + + fputs($this->fp,"LOGOUT\r\n"); + fclose($this->fp); + $this->loggedin=false; + return true; + } + + function sieve_sendscript($scriptname, $script) + { + if($this->loggedin==false) + return false; + $this->script=stripslashes($script); + $len=strlen($this->script); + fputs($this->fp, "PUTSCRIPT \"$scriptname\" {".$len."+}\r\n"); + fputs($this->fp, "$this->script\r\n"); + + return sieve::get_response(); + + } + + //it appears the timsieved does not honor the NUMBER type. see lex.c in timsieved src. + //don't expect this function to work yet. I might have messed something up here, too. + function sieve_havespace($scriptname, $scriptsize) + { + if($this->loggedin==false) + return false; + fputs($this->fp, "HAVESPACE \"$scriptname\" $scriptsize\r\n"); + return sieve::get_response(); + + } + + function sieve_setactivescript($scriptname) + { + if($this->loggedin==false) + return false; + + fputs($this->fp, "SETACTIVE \"$scriptname\"\r\n"); + return sieve::get_response(); + + } + + function sieve_getscript($scriptname) + { + unset($this->script); + if($this->loggedin==false) + return false; + + fputs($this->fp, "GETSCRIPT \"$scriptname\"\r\n"); + return sieve::get_response(); + + } + + + function sieve_deletescript($scriptname) + { + if($this->loggedin==false) + return false; + + fputs($this->fp, "DELETESCRIPT \"$scriptname\"\r\n"); + + return sieve::get_response(); + } + + + function sieve_listscripts() + { + fputs($this->fp, "LISTSCRIPTS\r\n"); + sieve::get_response(); //should always return true, even if there are no scripts... + if(isset($this->found_script) and $this->found_script) + return true; + else{ + $this->error=EC_NOSCRIPTS; //sieve::getresponse has no way of telling wether a script was found... + $this->error_raw="No scripts found for this account."; + return false; + } + } + + function sieve_alive() + { + if(!isset($this->fp) or $this->fp==0){ + $this->error = EC_NOT_LOGGED_IN; + return false; + } + elseif(feof($this->fp)){ + $this->error = EC_NOT_LOGGED_IN; + return false; + } + else + return true; + } + + function authenticate() + { + + switch ($this->auth_in_use) { + + case "PLAIN": + $auth=base64_encode("$this->user\0$this->auth\0$this->pass"); + + $this->len=strlen($auth); + fputs($this->fp, "AUTHENTICATE \"PLAIN\" {".$this->len."+}\r\n"); + fputs($this->fp, "$auth\r\n"); + + $this->line=fgets($this->fp,1024); + while(sieve::status($this->line) == F_DATA) + $this->line=fgets($this->fp,1024); + + if(sieve::status($this->line) == F_NO) + return false; + $this->loggedin=true; + return true; + break; + + default: + return false; + break; + + }//end switch + + + }//end authenticate() + + +} + + + +?> diff --git a/include/sieve/class_sieveElement_Block_End.inc b/include/sieve/class_sieveElement_Block_End.inc new file mode 100644 index 000000000..3bd0b0436 --- /dev/null +++ b/include/sieve/class_sieveElement_Block_End.inc @@ -0,0 +1,32 @@ +object_id = $object_id; + } + + function execute() + { + $smarty = get_smarty(); + return($smarty->fetch(get_template_path("templates/element_block_end.tpl",TRUE,dirname(__FILE__)))); + } + function check() + { + return(array()); + } + + function get_sieve_script_part() + { + return("}"); + } + function save_object() + { + } +} + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_Block_Start.inc b/include/sieve/class_sieveElement_Block_Start.inc new file mode 100644 index 000000000..e001cdc58 --- /dev/null +++ b/include/sieve/class_sieveElement_Block_Start.inc @@ -0,0 +1,33 @@ +object_id = $object_id; + } + + function execute() + { + $smarty = get_smarty(); + return($smarty->fetch(get_template_path("templates/element_block_start.tpl",TRUE,dirname(__FILE__)))); + } + + function check() + { + return(array()); + } + + function save_object() + { + } + + function get_sieve_script_part() + { + return("{"); + } +} +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_Comment.inc b/include/sieve/class_sieveElement_Comment.inc new file mode 100644 index 000000000..c3e126cec --- /dev/null +++ b/include/sieve/class_sieveElement_Comment.inc @@ -0,0 +1,84 @@ +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 new file mode 100644 index 000000000..1ee28ad43 --- /dev/null +++ b/include/sieve/class_sieveElement_Discard.inc @@ -0,0 +1,40 @@ +object_id = $object_id; + } + + function get_sieve_script_part() + { + return("discard;"); + } + function check() + { + return(array()) ; + } + + + function save_object() + { + + } + + function execute() + { + $smarty = get_smarty(); + $smarty->assign("ID", $this->object_id); + $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__))); + $object = $smarty->fetch(get_template_path("templates/element_discard.tpl",TRUE,dirname(__FILE__))); + $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container); + return($str); + } +} + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_Else_Elsif.inc b/include/sieve/class_sieveElement_Else_Elsif.inc new file mode 100644 index 000000000..c02e12360 --- /dev/null +++ b/include/sieve/class_sieveElement_Else_Elsif.inc @@ -0,0 +1,43 @@ +object_id = $object_id; + } + + function save_object() + { + } + + function execute() + { + $smarty = get_smarty(); + $smarty->assign("ID", $this->object_id); + $object_container = $smarty->fetch(get_template_path("templates/object_container_clear.tpl",TRUE,dirname(__FILE__))); + $object= $smarty->fetch(get_template_path("templates/element_else.tpl",TRUE,dirname(__FILE__))); + $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container); + return($str); + } + + function get_sieve_script_part() + { + return("else"); + } +} + +?> diff --git a/include/sieve/class_sieveElement_Fileinto.inc b/include/sieve/class_sieveElement_Fileinto.inc new file mode 100644 index 000000000..f357d37d9 --- /dev/null +++ b/include/sieve/class_sieveElement_Fileinto.inc @@ -0,0 +1,104 @@ +get_mail_boxes(); + + if(isset($_POST['fileinto_'.$this->object_id])){ + $mb = stripslashes($_POST['fileinto_'.$this->object_id]); + + /* Depending on the user mode we only accept + * existing mailboxes + */ + if($this->user_mode){ + $this->data = $mb; + }else{ + if(in_array_ics($mb,$mbs)){ + $this->data = $mb; + } + } + + /* Check Mode */ + if(isset($_POST['user_mode_'.$this->object_id])){ + $this->user_mode = !$this->user_mode; + } + } + } + + function sieve_fileinto($data,$object_id,$parent) + { + $this->object_id = $object_id; + $this->parent = $parent; + $this->parent->add_require("fileinto"); + + $mbs = $this->get_mail_boxes(); + + /* Set the default mailbox */ + if($data == NULL){ + $data = array('ELEMENTS' => array(array('class' => "quoted-string" ,"text" => $mbs[key($mbs)]))); + } + + /* Load element contents, should normaly be only one string + * but if we found more than one, just append the following strings. + */ + for($i = 0 ; $i < count($data['ELEMENTS']) ; $i++){ + $tmp = sieve_get_strings($data['ELEMENTS'],$i); + $i = $i + $tmp['OFFSET']; + foreach($tmp['STRINGS'] as $str){ + $this->data .= $str; + } + } + + /* Set user mode to active, so we are able to insert + * the destination mail folder manually + */ + if(!in_array_ics($this->data,$mbs)){ + $this->user_mode = TRUE; + } + } + + function get_sieve_script_part() + { + $tmp = ""; + $tmp.= "\"".$this->data."\", "; + $tmp = preg_replace("/,$/","",trim($tmp)); + $tmp = preg_replace ("/\"\"/","\"",$tmp); + return("fileinto ".$tmp.";"); + } + + function execute() + { + $smarty = get_smarty(); + $smarty->assign("Selected",htmlentities($this->data)); + $smarty->assign("Boxes", $this->get_mail_boxes()); + $smarty->assign("User_Mode", $this->user_mode); + $smarty->assign("ID", $this->object_id); + $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__))); + $object= $smarty->fetch(get_template_path("templates/element_fileinto.tpl",TRUE,dirname(__FILE__))); + $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container); + + return($str); + } + + function check() + { + return(array()); + } + + function get_mail_boxes() + { + $list = $this->parent->parent->parent->parent->mailboxList; + return($list); + } +} + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_If.inc b/include/sieve/class_sieveElement_If.inc new file mode 100644 index 000000000..acdcb94d5 --- /dev/null +++ b/include/sieve/class_sieveElement_If.inc @@ -0,0 +1,1469 @@ +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] + + + */ + + /* 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] + + + */ + + /* 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] + + + */ + + /* 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 + + */ + + /* Invert ? */ + if($Inverse){ + $script .= "not "; + } + + $script .= "exists ".sieve_create_strings($data['Values']); + break; + } + + + /******************* + * Size + *******************/ + case "size" : + { + /* [not] size + <":over" / ":under"> + + */ + + /* 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 + anyof */ + + + /* 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] + + + */ + + /* 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 = ""; + $name .= ""._("Condition").""; + 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%%/",""._("Click here to add a new test")."",$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 + + + */ + + + $part = "(:all|:localpart|:domain)"; + $operator = "(:regex|:contains|:is|:matches|:count|:value)"; + $value_op = "(lt|le|eq|ge|gt|ne)"; + + $Address_Part = ""; + $Comparator = ""; + $Match_type = ""; + $Match_type_value = ""; + + $Key_List = array(); + $Value_List = array(); + + for($i = 0 ; $i < count($data) ; $i ++){ + + /* Get next node */ + $node = $data[$i]; + + /* Check address part definition */ + if($node['class'] == "tag" && preg_match("/".$part."/i",$node['text'])){ + $Address_Part = $node['text']; + } + + /* Check for match type */ + elseif($node['class'] == "tag" && preg_match("/".$operator."/i",$node['text'])){ + $Match_type = $node['text']; + + /* Get value operator */ + if(in_array($Match_type,array(":value",":count"))){ + $i ++; + $node = $data[$i]; + + if($node['class'] == "quoted-string" && preg_match("/".$value_op."/",$node['text'])){ + $Match_type_value = $node['text']; + } + } + } + + /* Check for a comparator */ + elseif($node['class'] == "tag" && preg_match("/comparator/",$node['text'])){ + $i ++; + $node = $data[$i]; + $Comparator = $node['text']; + } + + /* Check for Key_List */ + elseif(count(sieve_get_strings($data,$i))){ + $tmp2 = sieve_get_strings($data,$i); + $i = $tmp2['OFFSET']; + + if(!count($Key_List)){ + $Key_List = $tmp2['STRINGS']; + }else{ + $Value_List = $tmp2['STRINGS']; + } + } + + } + + + /* Add to Tree */ + $values = array( "Inverse" => $Inverse, + "Comparator" => $Comparator, + "Expert" => FALSE, + "Match_type" => $Match_type, + "Match_type_value"=> $Match_type_value, + "Key_List" => $Key_List, + "Value_List" => $Value_List) ; + if($type == "address"){ + $values["Address_Part"] = $Address_Part; + } + $tmp[$type] = $values; + $tmp[$type]['LastError'] = ""; + break; + } + + + /**************** + * Parse - Size + ****************/ + + case "size": + { + + $ops = "(:over|:under)"; + + $Match_type = ""; + + for($i = $id ; $i < count($data); $i++){ + + /* Get current node */ + $node = $data[$i]; + + /* Get tag (under / over) */ + if($node['class'] == "tag" && preg_match("/".$ops."/",$node['text'])){ + $Match_type = $node['text']; + } + + /* Get Value_List, the value that we want to match for */ + elseif(count(sieve_get_strings($data,$i))){ + $tmp2 = sieve_get_strings($data,$i); + $i = $tmp2['OFFSET']; + + $Value_List = $tmp2['STRINGS']; + } + } + + $tmp[$type]= array( "Inverse" => $Inverse, + "Match_type" => $Match_type, + "Value_List" => $Value_List); + $tmp[$type]['LastError'] = ""; + break; + } + + + /**************** + * Parse - True / False + ****************/ + + case "true": + { + $tmp['true'] = "true"; + $tmp['true']['LastError'] = ""; + break; + } + case "false": + { + $tmp['false'] = "false"; + $tmp['false']['LastError'] = ""; + break; + } + + + /**************** + * Parse - Exists + ****************/ + + case "exists": + { + + /* Skip first values, [if,not,exists] */ + $node = $data[$id]; + while(in_array($node['text'],array("if","not","exists"))){ + $id ++; + $node = $data[$id]; + } + + /* Get values */ + $tmp2 = sieve_get_strings($data,$id); + + + $tmp['exists'] = array('Inverse' => $Inverse, + 'Values' => $tmp2['STRINGS']); + $tmp[$type]['LastError'] = ""; + break; + } + + + /**************** + * Parse - Allof + ****************/ + + case "allof" : + { + /* Get parameter and recursivly call this method + * for each parameter + */ + $id ++; + $tmp2 = $this->get_parameter($data,$id); + + foreach($tmp2 as $parameter){ + $tmp['allof'][] = $this->_parse($parameter); + } + $tmp['allof']['Inverse'] = $Inverse; + break; + } + + + /**************** + * Parse - Anyof + ****************/ + + case "anyof" : + { + /* Get parameter and recursivly call this method + * for each parameter + */ + $id ++; + $tmp2 = $this->get_parameter($data,$id); + + foreach($tmp2 as $parameter){ + $tmp['anyof'][] = $this->_parse($parameter); + } + $tmp['anyof']['Inverse'] = $Inverse; + break; + } + default : $tmp[$id] = $type; + } + + return($tmp); + } + + + function get_parameter($data,$id) + { + $par = array(); + $open_brakets = 0; + $next = NULL; + $num = 0; + for($i = $id ; $i < count($data) ; $i++ ){ + if(in_array($data[$i]['class'],array("left-parant","left-bracket"))){ + $open_brakets ++; + } + if($data[$i]['class'] == "comma" && $open_brakets == 1){ + $num ++; + } + if(!in_array($data[$i]['class'],array("comma","left-parant","right-parant")) || $open_brakets >1 ){ + $par[$num][] = $data[$i]; + } + if(in_array($data[$i]['class'],array("right-parant","right-bracket"))){ + $open_brakets --; + } + } + return($par); + } +} + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_Keep.inc b/include/sieve/class_sieveElement_Keep.inc new file mode 100644 index 000000000..3e1d58e1c --- /dev/null +++ b/include/sieve/class_sieveElement_Keep.inc @@ -0,0 +1,38 @@ +object_id = $object_id; + } + + function save_object() + { + } + + function check() + { + return(array()); + } + + function execute() + { + $smarty = get_smarty(); + $smarty->assign("ID", $this->object_id); + $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__))); + $object = $smarty->fetch(get_template_path("templates/element_keep.tpl",TRUE,dirname(__FILE__))); + $str = preg_replace("/%%OBJECT_CONTENT%%/", addcslashes($object,"\\"),$object_container); + return($str); + } + function get_sieve_script_part() + { + return("keep;"); + } +} + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_Redirect.inc b/include/sieve/class_sieveElement_Redirect.inc new file mode 100644 index 000000000..56f55cf77 --- /dev/null +++ b/include/sieve/class_sieveElement_Redirect.inc @@ -0,0 +1,69 @@ +object_id])){ + $rt = stripslashes($_POST['redirect_to_'.$this->object_id]); + + $rt = trim($rt); + $this->data = $rt; + } + } + + + function check() + { + $msgs = array(); + + if(!is_email($this->data)){ + $msgs[] =_("Please specify a valid email address."); + } + + return($msgs); + } + + function sieve_redirect($data,$object_id) + { + $this->object_id = $object_id; + + if($data == NULL){ + $data = array('ELEMENTS' => array(array('class' => "quoted-string" ,"text" => _("Put a mail address here")))); + } + + for($i = 0 ; $i < count($data['ELEMENTS']) ; $i++){ + $tmp = sieve_get_strings($data['ELEMENTS'],$i); + $i = $i + $tmp['OFFSET']; + foreach($tmp['STRINGS'] as $str){ + $this->data .= $str; + } + } + } + + + function get_sieve_script_part() + { + return("redirect ".sieve_create_strings($this->data).";"); + } + + + function execute() + { + $values = htmlentities($this->data); + $smarty = get_smarty(); + $smarty->assign("ID", $this->object_id); + $smarty->assign("Destinations" , $values); + $smarty->assign("LastError" , $this->check()); + $smarty->assign("LastErrorCnt" , count($this->check())); + $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__))); + $object= $smarty->fetch(get_template_path("templates/element_redirect.tpl",TRUE,dirname(__FILE__))); + $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container); + return($str); + } +} +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_Reject.inc b/include/sieve/class_sieveElement_Reject.inc new file mode 100644 index 000000000..baa100449 --- /dev/null +++ b/include/sieve/class_sieveElement_Reject.inc @@ -0,0 +1,76 @@ +object_id])){ + $msg = stripslashes($_POST['reject_message_'.$this->object_id]); + $this->data = $msg; + } + } + + function check() + { + $msgs = array(); + if(preg_match("/\"/",$this->data)){ + $msgs [] = _("Invalid character found, quotes are not allowed in a reject message."); + } + return($msgs); + } + + function sieve_reject($data,$object_id,$parent) + { + $this->object_id = $object_id; + $this->parent = $parent; + $this->parent->add_require("reject"); + + /* If the given data is emtpy + * (This is the case when we add new elements in the ui) + * Set a default text. + */ + if($data == NULL){ + $this->data = _("Your reject text here"); + }else{ + + for($i = 0 ; $i < count($data['ELEMENTS']) ; $i++){ + $tmp = sieve_get_strings($data['ELEMENTS'],$i); + $i = $i + $tmp['OFFSET']; + foreach($tmp['STRINGS'] as $str){ + $this->data .= $str; + } + } + } + } + + function get_sieve_script_part() + { + return("reject ".sieve_create_strings($this->data).";"); + } + + function execute() + { + /* check if this will be a + * - single string "" + * - or a multi line text: ... ; + */ + $Multiline = preg_match("/\n/",$this->data); + + $smarty = get_smarty(); + $smarty->assign("ID", $this->object_id); + $smarty->assign("Message",$this->data); + $smarty->assign("Multiline",$Multiline); + $smarty->assign("LastError" , $this->check()); + $smarty->assign("LastErrorCnt" , count($this->check())); + $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__))); + $object= $smarty->fetch(get_template_path("templates/element_reject.tpl",TRUE,dirname(__FILE__))); + $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container); + return($str); + } +} +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_Require.inc b/include/sieve/class_sieveElement_Require.inc new file mode 100644 index 000000000..9ef9e2985 --- /dev/null +++ b/include/sieve/class_sieveElement_Require.inc @@ -0,0 +1,109 @@ +parent = $parent; + $this->object_id = $object_id; + if($data != NULL){ + + for($i = 0 ; $i < count($data['ELEMENTS']) ; $i++){ + $tmp = sieve_get_strings($data['ELEMENTS'],$i); + $i = $i + $tmp['OFFSET']; + foreach($tmp['STRINGS'] as $str){ + $this->data[]= $str; + } + } + } + } + + + /* Add a new require statement and ensure + * that it is not specified twice + */ + function Add_Require($str) + { + $current = array(); + foreach($this->data as $dat){ + $current[] = $dat; + } + if(!in_array($str,$current)){ + $this->data[] = $str; + } + $this->data = array_unique($this->data); + $this->skip_save_object = TRUE; + } + + function save_object() + { + if($this->skip_save_object){ + $this->skip_save_object = FALSE; + return; + } + + /* Get the values should check for, they are seperated by , */ + if(isset($_POST['require_'.$this->object_id])){ + $vls = stripslashes($_POST['require_'.$this->object_id]); + $tmp = array(); + + $tmp2 = split(",",$vls); + foreach($tmp2 as $val){ + + $val = trim($val); + + if(empty($val)) continue; + + $tmp[] = $val; + } + $this->data = $tmp; + } + } + + function check() + { + $msgs = array(); + + if(!count($this->data)){ + $msgs[] = _("Please specify at least one valid requirement."); + } + return($msgs); + } + + function get_sieve_script_part() + { + if(count($this->data)){ + $tmp = sieve_create_strings($this->data); + return("require ".$tmp.";\n"); + }else{ + return(""); + } + } + + function execute() + { + $Require = ""; + foreach($this->data as $key){ + $Require .= $key.", "; + } + $Require = preg_replace("/,$/","",trim($Require)); + + $smarty = get_smarty(); + $smarty->assign("Require",$Require); + $tmp = $this->check(); + $smarty->assign("LastError",$tmp); + $smarty->assign("LastErrorCnt",count($tmp)); + $smarty->assign("ID", $this->object_id); + $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__))); + $object= $smarty->fetch(get_template_path("templates/element_require.tpl",TRUE,dirname(__FILE__))); + $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container); + return($str); + } +} +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_Stop.inc b/include/sieve/class_sieveElement_Stop.inc new file mode 100644 index 000000000..9acc72bd9 --- /dev/null +++ b/include/sieve/class_sieveElement_Stop.inc @@ -0,0 +1,39 @@ +object_id = $object_id; + } + + function save_object() + { + } + + function check() + { + return(array()); + } + + function execute() + { + $smarty = get_smarty(); + $smarty->assign("ID", $this->object_id); + $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__))); + $object= $smarty->fetch(get_template_path("templates/element_stop.tpl",TRUE,dirname(__FILE__))); + $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container); + return($str); + } + + function get_sieve_script_part() + { + return("stop; \n"); + } +} + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveElement_Vacation.inc b/include/sieve/class_sieveElement_Vacation.inc new file mode 100644 index 000000000..a6a7e07a0 --- /dev/null +++ b/include/sieve/class_sieveElement_Vacation.inc @@ -0,0 +1,179 @@ +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] */ + + /* Not all attribute types are supported by the sieve class right now */ + $known_attrs = array(":days",":subject",":from",":mime",":handle"); + + /* skip if empty */ + if(($data == NULL) || !is_array($data)) return; + + /* Walk through elements */ + $p = count($data['ELEMENTS']); + for($i = 0 ; $i < $p ; $i ++){ + + /* get current element */ + $node = $data['ELEMENTS'][$i]; + + /* Check if tag is in the specified list of attributes */ + if($node['class'] == "tag" && in_array($node['text'],$known_attrs)){ + + $var = preg_replace("/\:/","",$node['text']); + $this->$var = $data['ELEMENTS'][$i+1]['text']; + $i ++; + } + + /* Check for addresses */ + if($node['class'] == "tag" && $node['text'] == ":addresses") { + $this->addresses = array(); + $i ++; + + /* Multiple or single address given */ + if($data['ELEMENTS'][$i]['class'] == "left-bracket"){ + while($data['ELEMENTS'][$i]['class'] != "right-bracket" && ($i < count($data['ELEMENTS']))){ + $i ++; + if($data['ELEMENTS'][$i]['class'] == "quoted-string"){ + $this->addresses[] = preg_replace("/\"/i","",$data['ELEMENTS'][$i]['text']); + } + } + }else{ + $this->addresses[] = preg_replace("/\"/i","",$data['ELEMENTS'][$i]['text']); + } + } + + /* Add the vacation message */ + if(in_array($node['class'],array("quoted-string","multi-line"))){ + + $tmp = sieve_get_strings($data['ELEMENTS'],$i); + $strs= $tmp['STRINGS']; + + $data = ""; + foreach($strs as $str){ + $data .= $str; + } + $this->reason = $data; + } + } + } + + function get_sieve_script_part() + { + $str = "vacation "; + if($this->days){ + $str.= ":days ".$this->days; + } + + if(count($this->addresses)){ + $str .= ":addresses ".sieve_create_strings($this->addresses); + if($this->subject){ + $str.= ":subject ".sieve_create_strings($this->subject); + } + } + if($this->mime){ + $str.= ":mime ".sieve_create_strings($this->mime); + } + + /* Append reason and ensure that this will be + * handled as multiline text element + * by adding a "\n" new line + */ + $str .= "\n ".sieve_create_strings($this->reason."\n"); + return($str." ; \n"); + } + + function save_object() + { + /* Get release date */ + if(isset($_POST['vacation_release_'.$this->object_id])){ + $this->days = stripslashes($_POST['vacation_release_'.$this->object_id]); + } + + /* Check if we want to toggle the expert mode */ + if(isset($_POST['Toggle_Expert_'.$this->object_id])){ + $this->Expert = !$this->Expert; + } + + /* Get release date */ + if(isset($_POST['vacation_receiver_'.$this->object_id])){ + $vr = stripslashes ($_POST['vacation_receiver_'.$this->object_id]); + $tmp = array(); + $tmp2 = split(",",$vr); + foreach($tmp2 as $val){ + $ad = trim($val); + if(!empty($ad)){ + $tmp[] = $ad; + } + } + $this->addresses = $tmp; + } + + /* Get reason */ + if(isset($_POST['vacation_reason_'.$this->object_id])){ + $vr = stripslashes ($_POST['vacation_reason_'.$this->object_id]); + $this->reason = trim($vr); + } + } + + function check() + { + $msgs = array(); + $err = FALSE; + foreach($this->addresses as $addr){ + if(!is_email($addr)){ + $err = true; + } + } + if($err){ + $msgs[] = _("Alternative sender addresse must be valid email addresses."); + } + return($msgs); + } + + function execute() + { + $Addresses = ""; + foreach($this->addresses as $key){ + $Addresses .= $key.", "; + } + $Addresses = preg_replace("/,$/","",trim($Addresses)); + + $smarty = get_smarty(); + $smarty->assign("LastError",$this->check()); + $smarty->assign("LastErrorCnt",count($this->check())); + $smarty->assign("Reason",$this->reason); + $smarty->assign("Addresses",$Addresses); + $smarty->assign("Subject",$this->subject); + $smarty->assign("Days",$this->days); + $smarty->assign("ID",$this->object_id); + $smarty->assign("Expert",$this->Expert); + + $object_container = $smarty->fetch(get_template_path("templates/object_container.tpl",TRUE,dirname(__FILE__))); + $object= $smarty->fetch(get_template_path("templates/element_vacation.tpl",TRUE,dirname(__FILE__))); + $str = preg_replace("/%%OBJECT_CONTENT%%/",addcslashes($object,"\\"),$object_container); + return($str); + } +} + +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_sieveManagement.inc b/include/sieve/class_sieveManagement.inc new file mode 100644 index 000000000..6ac3c6ee5 --- /dev/null +++ b/include/sieve/class_sieveManagement.inc @@ -0,0 +1,1056 @@ + + + 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")."".$p->status_text.""; + }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")."".$p->status_text.""; + }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" => ""._("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 = ""; + }else{ + $del = " "; + } + + if($active || $script['IS_NEW'] || chkacl($this->parent->acl,"sieveManagement") != ""){ + $activate = " "; + }else{ + $activate = ""; + } + + $field6 = array("string" => $activate."".$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'] = "". + _("Failed to save sieve script").": ". + to_string($this->sieve_handle->error_raw). + ""; + } + } + } + return($everything_went_fine); + } +} +// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: +?> diff --git a/include/sieve/class_tree.inc b/include/sieve/class_tree.inc new file mode 100644 index 000000000..37198f0cd --- /dev/null +++ b/include/sieve/class_tree.inc @@ -0,0 +1,153 @@ +_construct($root); + } + + function _construct(&$root) + { + $this->childs_ = array(); + $this->parents_ = array(); + $this->nodes_ = array(); + $this->maxId_ = 0; + + $this->parents_[0] = null; + $this->nodes_[0] = $root; + } + + function addChild(&$child) + { + return $this->addChildTo($this->maxId_, $child); + } + + function addChildTo($parent_id, &$child) + { + if (!is_int($parent_id) || + !isset($this->nodes_[$parent_id])) + { + return null; + } + + if (!isset($this->childs_[$parent_id])) + { + $this->childs_[$parent_id] = array(); + } + + $child_id = ++$this->maxId_; + $this->nodes_[$child_id] = $child; + $this->parents_[$child_id] = $parent_id; + array_push($this->childs_[$parent_id], $child_id); + + return $child_id; + } + + function getRoot() + { + if (!isset($this->nodes_[0])) + { + return null; + } + + return 0; + } + + function getParent($node_id) + { + if (!is_int($node_id) || + !isset($this->nodes_[$node_id])) + { + return null; + } + + return $this->parents_[$node_id]; + } + + function getChilds($node_id) + { + if (!is_int($node_id) || + !isset($this->nodes_[$node_id])) + { + return null; + } + + if (!isset($this->childs_[$node_id])) + { + return array(); + } + + return $this->childs_[$node_id]; + } + + function getNode($node_id) + { + if (!is_int($node_id) || + !isset($this->nodes_[$node_id])) + { + return null; + } + + return $this->nodes_[$node_id]; + } + + function setDumpFunc($callback) + { + if ($callback == NULL || is_callable($callback)) + { + $this->dumpFn_ = $callback; + } + } + + function dump() + { + $this->dump_ = "tree\n"; + $this->doDump_(0, '', true); + return $this->dump_; + } + + function doDump_($node_id, $prefix, $last) + { + if ($last) + { + $infix = '`--- '; + $child_prefix = $prefix . ' '; + } + else + { + $infix = '|--- '; + $child_prefix = $prefix . '| '; + } + + $node = $this->nodes_[$node_id]; + if ($this->dumpFn_ != NULL) + { + $this->dump_ .= $prefix . $infix . call_user_func($this->dumpFn_, $node) . "\n"; + } + else + { + $this->dump_ .= "$prefix$infix$node\n"; + } + + if (isset($this->childs_[$node_id])) + { + $childs = $this->childs_[$node_id]; + $last_child = count($childs); + + for ($i=1; $i <= $last_child; ++$i) + { + $this->doDump_($childs[$i-1], $child_prefix, ($i == $last_child ? true : false)); + } + } + } +} + +?> \ No newline at end of file diff --git a/include/sieve/libsieve.inc b/include/sieve/libsieve.inc new file mode 100644 index 000000000..3b94e4975 --- /dev/null +++ b/include/sieve/libsieve.inc @@ -0,0 +1,8 @@ + diff --git a/include/sieve/templates/add_element.tpl b/include/sieve/templates/add_element.tpl new file mode 100644 index 000000000..d98c52986 --- /dev/null +++ b/include/sieve/templates/add_element.tpl @@ -0,0 +1,14 @@ +

{t}Add a new element{/t}

+{t}Please select the type of element you want to add{/t} +
+ + +

 

+
+
+ +   + +
diff --git a/include/sieve/templates/block_indent_start.tpl b/include/sieve/templates/block_indent_start.tpl new file mode 100644 index 000000000..482f637d7 --- /dev/null +++ b/include/sieve/templates/block_indent_start.tpl @@ -0,0 +1,12 @@ + + + + + + + +
+   + + + +
 
+
diff --git a/include/sieve/templates/block_indent_stop.tpl b/include/sieve/templates/block_indent_stop.tpl new file mode 100644 index 000000000..857aa6893 --- /dev/null +++ b/include/sieve/templates/block_indent_stop.tpl @@ -0,0 +1,5 @@ +
+
 
+
diff --git a/include/sieve/templates/create_script.tpl b/include/sieve/templates/create_script.tpl new file mode 100644 index 000000000..42737169e --- /dev/null +++ b/include/sieve/templates/create_script.tpl @@ -0,0 +1,19 @@ +

Create a new sieve script

+{t}Please enter the name for the new script below. Script names must consist of lower case characters only.{/t} + +
+
+

 

+
+{t}Script name{/t} +
+
+ +
+ +   + +
+ diff --git a/include/sieve/templates/edit_frame_base.tpl b/include/sieve/templates/edit_frame_base.tpl new file mode 100644 index 000000000..83d62a026 --- /dev/null +++ b/include/sieve/templates/edit_frame_base.tpl @@ -0,0 +1,42 @@ + + + + + + + + +
+ + + + + {if $Mode != "Source-Only"} + + {if $Mode == "Source"} + + {else} + + {/if} + {/if} +
+ + {if $Script_Error != ""} +
+ {$Script_Error} +
+ {/if} + + + {if $Mode == "Structured"} + {$Contents} + {else} + + {/if} + +
+
+ +   + +
diff --git a/include/sieve/templates/element_address.tpl b/include/sieve/templates/element_address.tpl new file mode 100755 index 000000000..ea6580f35 --- /dev/null +++ b/include/sieve/templates/element_address.tpl @@ -0,0 +1,142 @@ +{if $Expert} + {if $LastError != ""} + + + + +
+ {$LastError} +
+ {/if} + + + + + + +
+ {t}Address{/t} + + +
+ + + + + + + + + + + + + + + + + + {if $match_type == ":count" || $match_type == ":value"} + + + + + {/if} + + + +
+ {t}Match type{/t} + + + +
+ {t}Invert test{/t}? + + {if $Inverse} + + {else} + + {/if} +
+ {t}Part of address that should be used{/t} + + +
+ {t}Comparator{/t} + + +
+ {t}Operator{/t} + + +
 
+ + + + + +
+ {t}Address fields to include{/t}
+ +
+ {t}Values to match for{/t}
+ +
+ {else} + + {if $LastError != ""} + + + + +
+ {$LastError} +
+ {/if} + + + + {if $match_type == ":count" || $match_type == ":value"} + + + + + +
+ {else} + + {/if} + {t}Address{/t} + + {if $Inverse} + + {else} + + {/if} +   + + + {if $match_type == ":count" || $match_type == ":value"} + + {/if} + + + + + + +
+ {/if} diff --git a/include/sieve/templates/element_allof.tpl b/include/sieve/templates/element_allof.tpl new file mode 100644 index 000000000..024c011e7 --- /dev/null +++ b/include/sieve/templates/element_allof.tpl @@ -0,0 +1,16 @@ + + + + + +
+ {if $Inverse} + + {else} + + {/if} +
+ {t}All of{/t} +
+ {$Contents} +
diff --git a/include/sieve/templates/element_anyof.tpl b/include/sieve/templates/element_anyof.tpl new file mode 100644 index 000000000..f7dc9298c --- /dev/null +++ b/include/sieve/templates/element_anyof.tpl @@ -0,0 +1,16 @@ + + + + + +
+ {if $Inverse} + + {else} + + {/if} +
+ {t}Any of{/t} +
+ {$Contents} +
diff --git a/include/sieve/templates/element_block_end.tpl b/include/sieve/templates/element_block_end.tpl new file mode 100644 index 000000000..41c3a2c0b --- /dev/null +++ b/include/sieve/templates/element_block_end.tpl @@ -0,0 +1,5 @@ + diff --git a/include/sieve/templates/element_block_start.tpl b/include/sieve/templates/element_block_start.tpl new file mode 100644 index 000000000..526162453 --- /dev/null +++ b/include/sieve/templates/element_block_start.tpl @@ -0,0 +1,12 @@ + diff --git a/include/sieve/templates/element_boolean.tpl b/include/sieve/templates/element_boolean.tpl new file mode 100755 index 000000000..44f5f7b52 --- /dev/null +++ b/include/sieve/templates/element_boolean.tpl @@ -0,0 +1,12 @@ + + + + +
+ {t}Bool{/t} + + +
+
diff --git a/include/sieve/templates/element_comment.tpl b/include/sieve/templates/element_comment.tpl new file mode 100644 index 000000000..56edf9455 --- /dev/null +++ b/include/sieve/templates/element_comment.tpl @@ -0,0 +1,23 @@ + + + + + + + + +
+ {t}Comment{/t} + + {if $Small} + + {else} + + {/if} +
+ {if $Small} + {$Comment} + {else} + + {/if} +
diff --git a/include/sieve/templates/element_discard.tpl b/include/sieve/templates/element_discard.tpl new file mode 100644 index 000000000..e26f77a3a --- /dev/null +++ b/include/sieve/templates/element_discard.tpl @@ -0,0 +1,12 @@ + + + + + + + +
+ {t}Discard{/t} +
+ {t}Discard message{/t} +
diff --git a/include/sieve/templates/element_else.tpl b/include/sieve/templates/element_else.tpl new file mode 100644 index 000000000..739fd0550 --- /dev/null +++ b/include/sieve/templates/element_else.tpl @@ -0,0 +1,7 @@ + + + + +
+ {t}Else{/t} +
diff --git a/include/sieve/templates/element_elsif.tpl b/include/sieve/templates/element_elsif.tpl new file mode 100644 index 000000000..ffbbf9bbe --- /dev/null +++ b/include/sieve/templates/element_elsif.tpl @@ -0,0 +1,8 @@ + + + + +
+ {t}Else if{/t} + {$Contents} +
diff --git a/include/sieve/templates/element_envelope.tpl b/include/sieve/templates/element_envelope.tpl new file mode 100755 index 000000000..f0bcb67f0 --- /dev/null +++ b/include/sieve/templates/element_envelope.tpl @@ -0,0 +1,134 @@ + + {if $Expert} + {if $LastError != ""} + + + + +
+ {$LastError} +
+ {/if} + + + + + + +
+ {t}Envelope{/t} + + +
+ + + + + + + + + + + + + + {if $match_type == ":count" || $match_type == ":value"} + + + + + {/if} + + + +
+ {t}Match type{/t} + + + +
+ {t}Invert test{/t}? + + {if $Inverse} + + {else} + + {/if} +
+ {t}Comparator{/t} + + +
+ {t}Operator{/t} + + +
 
+ + + + + +
+ {t}Address fields to include{/t}
+ +
+ {t}Values to match for{/t}
+ +
+ + {else} + {if $LastError != ""} + + + + +
+ {$LastError} +
+ {/if} + + + {if $match_type == ":count" || $match_type == ":value"} + + + + + +
+ {else} + + {/if} + + + {t}Envelope{/t} + + {if $Inverse} + + {else} + + {/if} +   + + + {if $match_type == ":count" || $match_type == ":value"} + + {/if} + + + + + + +
+ {/if} diff --git a/include/sieve/templates/element_exists.tpl b/include/sieve/templates/element_exists.tpl new file mode 100644 index 000000000..29882d3f4 --- /dev/null +++ b/include/sieve/templates/element_exists.tpl @@ -0,0 +1,20 @@ + + + + + +
+ {if $LastError != ""} + {$LastError} +
+ {/if} + {t}Exists{/t} + {if $Inverse} + + {else} + + {/if} + +
+ +
diff --git a/include/sieve/templates/element_fileinto.tpl b/include/sieve/templates/element_fileinto.tpl new file mode 100644 index 000000000..c6ae998e0 --- /dev/null +++ b/include/sieve/templates/element_fileinto.tpl @@ -0,0 +1,30 @@ + + + + + + + + + + +
+ {t}Move mail into folder{/t} + + {if $User_Mode} + + {else} + + {/if} +
+ + {t}Folder{/t} + {if $User_Mode} + + {else} + + {/if} + +
diff --git a/include/sieve/templates/element_header.tpl b/include/sieve/templates/element_header.tpl new file mode 100755 index 000000000..8dcd30989 --- /dev/null +++ b/include/sieve/templates/element_header.tpl @@ -0,0 +1,136 @@ + {if $Expert} + {if $LastError != ""} + + + + +
+ {$LastError} +
+ {/if} + + + + + + + +
+ {t}Header{/t} + + +
+ + + + + + + + + + + + + + {if $match_type == ":count" || $match_type == ":value"} + + + + + {/if} + + + + +
+ {t}Match type{/t} + + + +
+ {t}Invert test{/t}? + + {if $Inverse} + + {else} + + {/if} +
+ {t}Comparator{/t} + + +
+ {t}operator{/t} + + +
 
+ + + + + +
+ {t}Address fields to include{/t}
+ +
+ {t}Values to match for{/t}
+ +
+ + {else} + {if $LastError != ""} + + + + +
+ {$LastError} +
+ {/if} + + + + + {if $match_type == ":count" || $match_type == ":value"} + + + + + + +
+ {else} + + {/if} + {t}Header{/t} + + {if $Inverse} + + {else} + + {/if} +   + + + {if $match_type == ":count" || $match_type == ":value"} + + {/if} + + + + + + +
+ {/if} diff --git a/include/sieve/templates/element_if.tpl b/include/sieve/templates/element_if.tpl new file mode 100644 index 000000000..98f9b4a5d --- /dev/null +++ b/include/sieve/templates/element_if.tpl @@ -0,0 +1,8 @@ + + + + +
+ {t}Condition{/t} + {$Contents} +
diff --git a/include/sieve/templates/element_keep.tpl b/include/sieve/templates/element_keep.tpl new file mode 100644 index 000000000..f3c5d8608 --- /dev/null +++ b/include/sieve/templates/element_keep.tpl @@ -0,0 +1,12 @@ + + + + + + + +
+ {t}Keep{/t} +
+ {t}Keep message{/t} +
diff --git a/include/sieve/templates/element_redirect.tpl b/include/sieve/templates/element_redirect.tpl new file mode 100644 index 000000000..778ff1a50 --- /dev/null +++ b/include/sieve/templates/element_redirect.tpl @@ -0,0 +1,22 @@ + + {foreach from=$LastError item=val key=key} + + + + + {/foreach} + + + + + + +
+
{$LastError[$key]}
+ +
+ {t}Redirect{/t} +
+ {t}Redirect mail to following recipients{/t}
+ +
diff --git a/include/sieve/templates/element_reject.tpl b/include/sieve/templates/element_reject.tpl new file mode 100644 index 000000000..c9de8b50e --- /dev/null +++ b/include/sieve/templates/element_reject.tpl @@ -0,0 +1,28 @@ + + +{foreach from=$LastError item=val key=key} + + + + + {/foreach} + + + + + + +
+
{$LastError[$key]}
+ +
+ {t}Reject mail{/t} +   + {if $Multiline} + + {else} + + {/if} +
+ +
diff --git a/include/sieve/templates/element_require.tpl b/include/sieve/templates/element_require.tpl new file mode 100644 index 000000000..3a3f261f3 --- /dev/null +++ b/include/sieve/templates/element_require.tpl @@ -0,0 +1,21 @@ + + {foreach from=$LastError item=val key=key} + + + + + {/foreach} + + + + + + +
+
{$LastError[$key]}
+
+ {t}Require{/t} +
+ +
+ diff --git a/include/sieve/templates/element_size.tpl b/include/sieve/templates/element_size.tpl new file mode 100644 index 000000000..a8e234693 --- /dev/null +++ b/include/sieve/templates/element_size.tpl @@ -0,0 +1,25 @@ + + + + +
+ {t}Size{/t} + {if $LastError != ""} + {$LastError} +
+ {/if} + + {if $Inverse} + + {else} + + {/if} + + + + +
diff --git a/include/sieve/templates/element_stop.tpl b/include/sieve/templates/element_stop.tpl new file mode 100644 index 000000000..975f10bda --- /dev/null +++ b/include/sieve/templates/element_stop.tpl @@ -0,0 +1,12 @@ + + + + + + + +
+ {t}Stop{/t}
+
+ {t}Stop execution here{/t} +
diff --git a/include/sieve/templates/element_vacation.tpl b/include/sieve/templates/element_vacation.tpl new file mode 100644 index 000000000..174148790 --- /dev/null +++ b/include/sieve/templates/element_vacation.tpl @@ -0,0 +1,56 @@ + + + {foreach from=$LastError item=val key=key} + + + + {/foreach} + {if $Expert} + + + + + + + + + + + + + + + + {else} + + + + + + + + {/if} +
+
{$LastError[$key]}
+
+ {t}Vacation Message{/t} + + +
+ {t}Release interval{/t}  + + +  {t}days{/t} +
+ {t}Alternative sender addresses{/t} + + +
+ +
+ {t}Vacation message{/t} + + +
+ +
diff --git a/include/sieve/templates/import_script.tpl b/include/sieve/templates/import_script.tpl new file mode 100644 index 000000000..22df06caa --- /dev/null +++ b/include/sieve/templates/import_script.tpl @@ -0,0 +1,15 @@ +

{t}Import sieve script{/t}

+{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} +
+
+{t}Script to import{/t}  + +
+
+

 

+
+
+ +   + +
diff --git a/include/sieve/templates/management.tpl b/include/sieve/templates/management.tpl new file mode 100644 index 000000000..315e47e08 --- /dev/null +++ b/include/sieve/templates/management.tpl @@ -0,0 +1,27 @@ +

{t}List of sieve scripts{/t}

+ + {$List} + +

+ +   + +

diff --git a/include/sieve/templates/object_container.tpl b/include/sieve/templates/object_container.tpl new file mode 100644 index 000000000..3b5f51fa1 --- /dev/null +++ b/include/sieve/templates/object_container.tpl @@ -0,0 +1,54 @@ + + + + + + + + + +
+   + + + {t}Move up{/t} +     + + {t}Move down{/t} +     + + {t}Remove element{/t} +     + + + + + + + +
+ + %%OBJECT_CONTENT%% +
diff --git a/include/sieve/templates/object_container_clear.tpl b/include/sieve/templates/object_container_clear.tpl new file mode 100644 index 000000000..4f5579fe5 --- /dev/null +++ b/include/sieve/templates/object_container_clear.tpl @@ -0,0 +1,28 @@ + + + + + + + + + +
+   + + + {t}Move up{/t} + + + {t}Move down{/t} + + + {t}Remove element{/t} + +
+ + %%OBJECT_CONTENT%% +
diff --git a/include/sieve/templates/object_test_container.tpl b/include/sieve/templates/object_test_container.tpl new file mode 100644 index 000000000..e1577177a --- /dev/null +++ b/include/sieve/templates/object_test_container.tpl @@ -0,0 +1,17 @@ + + + + + +
+ {if $DisplayAdd} + + {/if} + {if $DisplayDel} + + {/if} + + %%OBJECT_CONTENT%% +
diff --git a/include/sieve/templates/remove_script.tpl b/include/sieve/templates/remove_script.tpl new file mode 100644 index 000000000..5bb5b49ae --- /dev/null +++ b/include/sieve/templates/remove_script.tpl @@ -0,0 +1,17 @@ +
+ {t}Warning{/t} +
+

+ {$Warning}
+ {t}Please double check if your really want to do this since there is no way for GOsa to get your data back.{/t} +

+ +

+ {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} +

+ +

+ +   + +

diff --git a/include/sieve/templates/select_test_type.tpl b/include/sieve/templates/select_test_type.tpl new file mode 100644 index 000000000..dd7a8fb2e --- /dev/null +++ b/include/sieve/templates/select_test_type.tpl @@ -0,0 +1,14 @@ +

{t}Select the type of test you want to add{/t}

+ +{t}Available test types{/t} :  + + +

 

+
+
+ +   + +
diff --git a/plugins/personal/mail/class_mailAccount.inc b/plugins/personal/mail/class_mailAccount.inc index ac113fde2..34dfff53a 100644 --- a/plugins/personal/mail/class_mailAccount.inc +++ b/plugins/personal/mail/class_mailAccount.inc @@ -10,7 +10,7 @@ */ /* Load sieve support */ -require_once ("class_sieve.inc"); +require_once ("sieve/class_sieve.inc"); /* Load mail methods */ global $BASE_DIR; @@ -59,6 +59,7 @@ class mailAccount extends plugin "gosaVacationMessage", "gosaMailAlternateAddress", "gosaMailForwardingAddress", "gosaVacationStart", "gosaVacationStop"); var $objectclasses= array("gosaMailAccount"); + var $sieve_management = NULL; /* constructor, if 'dn' is set, the node loads the given 'dn' from LDAP */ @@ -182,6 +183,10 @@ class mailAccount extends plugin } } + /* Create sieve management class */ + $method = new $this->method($this->config); + $id = $method->uattrib; + $this->sieve_management = new sieveManagement($this->config,$this->dn,$this,$id); /* Create filter */ @@ -235,6 +240,33 @@ class mailAccount extends plugin $mailserver[]= $key; } + + /* + * Sieve Management + */ + if(isset($_POST['sieveManagement']) + && preg_match("/C/",$this->gosaMailDeliveryMode) + && chkacl($this->acl,"sieveManagement") == "") { + $this->dialog = $this->sieve_management; + } + + /* Cancel sieve edit */ + if(isset($_POST['sieve_cancel'])){ + $this->dialog = NULL; + } + + /* Save sieve changes */ + if(isset($_POST['sieve_finish'])){ + $this->sieve_management = $this->dialog; + $this->dialog = NULL; + } + + if(is_object($this->dialog)){ + $this->dialog->save_object(); + return($this->dialog->execute()); + } + + /* Handle account state */ /* Do we need to flip is_account state? */ @@ -570,6 +602,8 @@ class mailAccount extends plugin $smarty->assign("$val"."ACL", chkacl($this->acl, "$val")); } + $smarty->assign("sieveManagementACL", chkacl($this->acl,"sieveManagement")); + if (preg_match('/V/', $this->gosaMailDeliveryMode)){ $smarty->assign('rangeEnabled', ""); } else { @@ -862,7 +896,7 @@ class mailAccount extends plugin /* Only talk with sieve if the mail account already exists */ if($this->initially_was_account){ - + /* Write sieve information only if not in C mode */ if (!is_integer(strpos($this->gosaMailDeliveryMode, "C"))){ $method->configureFilter($this->$id, @@ -873,6 +907,8 @@ class mailAccount extends plugin $this->gosaSpamMailbox, $this->gosaSpamSortLevel, $this->gosaVacationMessage); + }else{ + $this->sieve_management->save(); } } } diff --git a/plugins/personal/mail/generic.tpl b/plugins/personal/mail/generic.tpl index c48694017..8de101aef 100644 --- a/plugins/personal/mail/generic.tpl +++ b/plugins/personal/mail/generic.tpl @@ -62,16 +62,56 @@ + +

 

+

 {t}Mail options{/t}

+ + + + + + + +
+ {t}Use custom sieve script{/t} ({t}disables all Mail options!{/t}) +
+ +
+ +

 

 {t}Mail options{/t}

@@ -182,16 +222,9 @@
- {t}No delivery to own mailbox{/t}
- {t}Activate vacation message{/t}
@@ -118,19 +158,19 @@  
- - {html_options values=$spambox output=$spambox selected=$gosaSpamMailbox}
- {t}MB{/t} @@ -145,11 +185,11 @@ {$gosaVacationMessageACL}>{$gosaVacationMessage}
{if $show_templates eq "true"} - {html_options options=$vacationtemplates selected=$template} - {/if}
@@ -163,13 +203,13 @@
- -   -   -
- -
- + {t}User is only allowed to send and receive local mails{/t} -   - - - {t}Use custom sieve script{/t} ({t}disables all Mail options!{/t}) -
@@ -199,6 +232,32 @@