1 <?php
5 /* This class is inherited from the original 'Tree'
6 * class written by Heiko Hund.
7 * It is partly rewritten to create a useable html interface
8 * for each single sieve token.
9 * This gives us the ability to edit existing sieve filters.
10 */
11 class My_Tree extends Tree
12 {
13 var $dumpFn_;
14 var $dump_;
16 var $mode_stack = array();
17 var $pap = array();
20 /* Create a html interface for the current sieve filter
21 */
22 function dump()
23 {
24 error_reporting(E_ALL);
26 /* Only parse the tokens once */
27 if(!count($this->pap)){
28 $this->dump_ = "";
29 $this->mode_stack = array();
30 $this->pap = array();
31 $this->doDump_(0, '', true);
32 }
34 /* Create html results */
35 $smarty = get_smarty();
36 $smarty->fetch(get_template_path("templates/element_stop.tpl",TRUE,dirname(__FILE__)));
38 $this -> dump_ = "";
39 foreach($this->pap as $key => $object){
40 if(is_object($object)){
41 $this->dump_ .= preg_replace("/>/",">\n",$object->execute());
42 }
43 }
46 /* Create html results */
47 $smarty = get_smarty();
48 $smarty->assign("Contents",$this->dump_);
49 $ret = $smarty->fetch(get_template_path("templates/edit_frame_base.tpl",TRUE,dirname(__FILE__)));
50 return ($ret);
51 }
54 /* This function walks through the object tree generated by the "Parse" class.
55 * All Commands will be resolved and grouped. So the Commands and their
56 * parameter are combined. Like "IF" and ":comparator"...
57 */
58 function doDump_($node_id, $prefix, $last,$num = 1)
59 {
60 /* Indicates that current comman will only be valid for a single line.
61 * this command type will be removed from mode_stack after displaying it.
62 */
63 $rewoke_last = FALSE;
65 /* Get node */
66 $node = $this->nodes_[$node_id];
68 /* This closes the last mode */
69 if($node['class'] == "block-start"){
70 $tmp = array_pop($this->mode_stack);
71 $this->handle_elements($tmp,$node_id);
72 $this->handle_elements(array("TYPE" => "block_start"),$node_id);
73 }
75 /* This closes the last mode */
76 if($node['class'] == "block-end"){
77 $tmp = array_pop($this->mode_stack);
78 $this->handle_elements($tmp,$node_id);
79 $this->handle_elements(array("TYPE" => "block_end"),$node_id);
80 }
82 /* Semicolon indicates a new command */
83 if($node['class'] == "semicolon"){
84 $tmp =array_pop($this->mode_stack);
85 $this->handle_elements($tmp,$node_id);
86 }
88 /* Handle comments */
89 if($node['class'] == "comment"){
90 $this->mode_stack[] = array("TYPE" => $node['class']);
91 $rewoke_last = TRUE;
92 }
94 /* Handle identifiers */
95 $identifiers = array("else","if","elsif","end","reject","redirect","vacation","keep","discard","comment","fileinto","require","stop");
96 if($node['class'] == "identifier" && in_array($node['text'],$identifiers)){
97 $this->mode_stack[] = array("TYPE" => $node['text']);
98 }
100 /* Add current node to current command stack */
101 end($this->mode_stack);
102 $key = key($this->mode_stack);
103 $this->mode_stack[$key]['ELEMENTS'][] = $node;
105 /* Remove last mode from mode stack, cause it was only valid for a single line */
106 if($rewoke_last){
107 $tmp =array_pop($this->mode_stack);
108 $this->handle_elements($tmp,$node_id);
109 }
111 /* If this is a sub element, just call this for all childs */
112 if(isset($this->childs_[$node_id])){
113 $childs = $this->childs_[$node_id];
114 for ($i=0; $i<count($childs); ++$i)
115 {
116 $c_last = false;
117 if ($i+1 == count($childs))
118 {
119 $c_last = true;
120 }
121 $this->doDump_($childs[$i], "", $num);
122 }
123 }
124 }
127 /* Create a class for each resolved object.
128 * And append this class to a list of objects.
129 */
130 function handle_elements($data,$id)
131 {
132 if(!isset($data['TYPE'])){
133 return;
134 }
135 $type = $data['TYPE'];
137 $class_name= "sieve_".$type ;
138 if(class_exists($class_name)){
139 $this->pap[] = new $class_name($data,$id);
140 }else{
141 echo "<font color='red'>Missing : ".$class_name."</font>"."<br>";
142 }
143 }
145 function save_object()
146 {
147 foreach($this->pap as $key => $obj){
149 if(in_array(get_class($obj),array("sieve_if","sieve_elsif","sieve_vacation","sieve_comment","sieve_reject","sieve_fileinto","sieve_require","sieve_redirect"))){
150 $this->pap[$key]->save_object();
151 }
153 $once = TRUE;
154 foreach($_POST as $name => $value){
156 if(isset($obj->object_id) && preg_match("/^Remove_Object_".$obj->object_id."_/",$name) && $once){
157 $once = FALSE;
158 $this->remove_object($key);
159 }
160 if(isset($obj->object_id) && preg_match("/^Move_Up_Object_".$obj->object_id."_/",$name) && $once){
161 $this->move_up_down($key,"up");
162 $once = FALSE;
163 }
164 if(isset($obj->object_id) && preg_match("/^Move_Down_Object_".$obj->object_id."_/",$name) && $once){
165 $this->move_up_down($key,"down");
166 $once = FALSE;
167 }
168 }
169 }
170 }
173 function remove_object($key_id){
174 unset($this->pap[$key_id]);
175 }
178 /* This function moves a given element to another position.
179 * Single elements like "keep;" will simply be moved one posisition down/up.
180 * Multiple elements like if-elsif-else will be moved as block.
181 *
182 * $key_id specified the element that should be moved.
183 * $direction specifies to move elements "up" or "down"
184 */
185 function move_up_down($key_id,$direction = "down")
186 {
188 /* Get the current element to decide what to move. */
189 $e_class = get_class($this->pap[$key_id]);
192 if(in_array($e_class,array("sieve_if"))){
193 echo "move block";
194 }
196 if(in_array($e_class,array( "sieve_stop",
197 "sieve_keep",
198 "sieve_require",
199 "sieve_stop",
200 "sieve_reject",
201 "sieve_fileinto",
202 "sieve_redirect",
203 "sieve_discard"))){
204 $this->move_single_element($key_id,$this->_get_next_free_move_slot($key_id,$direction));
205 }
206 }
209 /* This function moves the single element at
210 * position $from to position $to.
211 */
212 function move_single_element($from,$to)
213 {
214 if($from == $to) {
215 return;
216 }
218 $ret = array();
219 $tmp = $this->pap;
221 $begin = array();
222 $middle = array();
223 $end = array();
224 $element = $this->pap[$from];
226 if($from > $to ){
228 /* Get all element in fron to element to move */
229 if($from != 0){
230 $begin = array_slice($tmp,0,$to);
231 }
233 /* Get all elements between */
234 $middle = array_slice($tmp,$to , ($from - ($to) ));
236 /* Get the rest */
237 $end = array_slice($tmp,$from+1);
239 foreach($begin as $data){
240 $ret[] = $data;
241 }
242 $ret[] = $element;
243 foreach($middle as $data){
244 $ret[] = $data;
245 }
246 foreach($end as $data){
247 $ret[] = $data;
248 }
249 $this->pap = $ret;
250 }
251 if($from < $to ){
253 /* Get all element in fron to element to move */
254 if($from != 0){
255 $begin = array_slice($tmp,0,$from);
256 }
258 /* Get all elements between */
259 $middle = array_slice($tmp,$from+1 , ($to - ($from)));
261 /* Get the rest */
262 $end = array_slice($tmp,$to+1);
264 foreach($begin as $data){
265 $ret[] = $data;
266 }
267 foreach($middle as $data){
268 $ret[] = $data;
269 }
270 $ret[] = $element;
271 foreach($end as $data){
272 $ret[] = $data;
273 }
274 $this->pap = $ret;
275 }
276 }
279 /* Returns the next free position where we
280 * can add a new sinle element
281 * $key_id = Current position
282 * $direction = Forward or backward.
283 */
284 function _get_next_free_move_slot($key_id,$direction)
285 {
286 $last_class = "";
287 $current_class ="";
288 $next_class = "";
290 /* After this elements we can add new elements
291 * without having any trouble.
292 */
293 $allowed_to_add_after = array("sieve_keep",
294 "sieve_require",
295 "sieve_stop",
296 "sieve_reject",
297 "sieve_fileinto",
298 "sieve_redirect",
299 "sieve_discard",
300 "sieve_block_start"
301 );
303 /* Before this elements we can add new elements
304 * without having any trouble.
305 */
306 $allowed_to_add_before = array("sieve_keep",
307 "sieve_require",
308 "sieve_stop",
309 "sieve_reject",
310 "sieve_fileinto",
311 "sieve_redirect",
312 "sieve_discard",
313 "sieve_if",
314 "sieve_block_end"
315 );
317 if($direction == "down"){
319 /* Get free position before $key_id */
320 $test = $this->pap;
321 while($key_id < count($test)){
322 if(($key_id+1) == count($test)) {
323 return($key_id);
324 }
325 $key_id ++;
326 $current_class = get_class($test[$key_id]);
327 if(in_array($current_class, $allowed_to_add_after)){
328 return($key_id);
329 }
330 }
331 }else{
333 /* Get next free position */
334 $test = $this->pap;
335 if($key_id == 0) {
336 return($key_id);
337 }
338 $key_id --;
339 while($key_id >=0 ){
340 $current_class = get_class($test[$key_id]);
341 if(in_array($current_class, $allowed_to_add_before)){
342 return($key_id);
343 }
344 $key_id --;
345 }
346 }
347 }
350 /* Need to be reviewed */
351 function get_sieve_script()
352 {
353 $tmp ="";
354 if(count($this->pap)){
355 $buffer = "";
356 foreach($this->pap as $part) {
357 if(get_class($part) == "sieve_block_end"){
358 $buffer = substr($buffer,0,strlen($buffer)-(strlen(SIEVE_INDENT_TAB)));
359 }
360 $tmp2 = $part->get_sieve_script_part();
362 if(get_class($part) == "sieve_reject"){
363 $tmp.=$tmp2;
364 }else{
366 $tmp3 = split("\n",$tmp2);
367 foreach($tmp3 as $str){
368 $str2 = trim($str);
369 if(empty($str2)) continue;
370 $tmp.= $buffer.$str."\n";
371 }
372 }
373 if(get_class($part) == "sieve_block_start"){
374 $buffer .= SIEVE_INDENT_TAB;
375 }
376 }
377 }
378 if(!preg_match("/Generated by GOsa - Gonicus System Administrator/",$tmp)){
379 $tmp = "#Generated by GOsa - Gonicus System Administrator \n ".$tmp;
380 }
381 return($tmp);
382 }
384 function Add_Element()
385 {
386 $tmp = array("ELEMENTS" => array(array("class" => "qouted-string","text"=> "Bla bla, later more")));
387 $this->pap[] = new sieve_comment($tmp,rand(1000,100000));
388 }
389 }
392 /* Create valid sieve string/string-list
393 * out of a given array
394 */
395 function sieve_create_strings($data)
396 {
397 $ret = "";
398 if(is_array($data)){
399 if(count($data) == 1){
400 $ret = "\"";
401 foreach($data as $dat){
402 $ret .=$dat;
403 }
404 $ret.="\"";
405 }else{
406 foreach($data as $dat){
407 $ret.= "\"";
408 $ret.=$dat;
409 $ret.="\", ";
410 }
411 $ret = preg_replace("/,$/","",trim($ret));
412 $ret = "[".$ret."]";
413 }
414 }else{
416 $Multiline = preg_match("/\n/",$data);
417 $data = preg_replace("/\r/","",$data);;
419 if($Multiline){
420 $ret = "text: \r\n".$data."\r\n.\r\n";
421 }else{
422 $ret = "\"".$data."\"";
423 }
424 }
425 $ret = preg_replace("/\"\"/","\"",$ret);
426 $ret = preg_replace("/\n/","\r\n",$ret);
428 return($ret);
429 }
431 /* This checks if there is a string at the current position
432 * in the token array.
433 * If there is a string list at the current position,
434 * this function will return a complete list of all
435 * strings used in this list.
436 * It also returns an offset of the last token position
437 */
438 function sieve_get_strings($data,$id)
439 {
440 $ret = array();
441 if($data[$id]['class'] == "left-bracket"){
442 while($data[$id]['class'] != "right-bracket" && $id < count($data)){
444 if($data[$id]['class'] == "quoted-string"){
445 $ret[] = $data[$id]['text'];
446 }
447 $id ++;
448 }
449 }elseif($data[$id]['class'] == "quoted-string"){
450 $ret[] = $data[$id]['text'];
451 }elseif($data[$id]['class'] == "number"){
452 $ret[] = $data[$id]['text'];
453 }
454 return(array("OFFSET" => $id, "STRINGS" => $ret));
455 }
457 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
458 ?>