1 <?php
2 /*
3 This code is part of GOsa (https://gosa.gonicus.de)
4 Copyright (C) 2003-2007 - Fabian Hickert <hickert@gonicus.de>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
22 /* The sieve management class displays a list of sieve
23 * scripts for the given mail account.
24 * The account is identified by the parents uid attribute.
25 *
26 * $config The config object
27 * $dn The object edited
28 * $parent The parent object that provides the uid attribute
29 */
30 class sieveManagement extends plugin
31 {
32 var $parent = NULL;
33 var $scripts= array();
35 var $current_script = -1;
36 var $current_handler = NULL;
37 var $script_to_delete =-1;
38 var $sieve_handle = NULL;
39 var $Script_Error = "";
40 var $Sieve_Error = "";
41 var $create_script = FALSE;
43 /* To add new elements we need to know
44 * Where to the element -> add_new_id
45 * Whould we add above or below this id -> add_above_below
46 * What kind of element should we add -> add_element_type
47 */
48 var $add_new_element = FALSE;
49 var $add_new_id = -1;
50 var $add_above_below = "below";
51 var $add_element_type = "sieve_comment";
54 function get_sieve()
55 {
56 /* Connect to sieve class and try to get all available sieve scripts */
57 $cfg= $this->config->data['SERVERS']['IMAP'][$this->parent->gosaMailServer];
58 $this->Sieve_Error = "";
60 /* Log into the mail server */
61 $sieve= new sieve(
62 $cfg["sieve_server"],
63 $cfg["sieve_port"],
64 $this->parent->uid,
65 $cfg["password"],
66 $cfg["admin"]);
68 /* Try to login */
69 if (!$sieve->sieve_login()){
70 $this->Sieve_Error = $sieve->error_raw;
71 return(FALSE);
72 }
73 return($sieve);
74 }
76 /* Initialize the class and load all sieve scripts
77 * try to parse them and display errors
78 */
79 function sieveManagement($config,$dn,$parent)
80 {
81 $this->parent = $parent;
82 plugin::plugin($config,$dn);
84 /* Get sieve */
85 if(!$sieve = $this->get_sieve()){
86 print_red(
87 sprintf(
88 _("Can't log into SIEVE server. Server says '%s'."),
89 to_string($this->Sieve_Error)));
90 return;
91 }
94 /* Get all sieve scripts names */
95 if($sieve->sieve_listscripts()){
96 if (is_array($sieve->response)){
97 foreach($sieve->response as $key => $name){
99 $data = array();
100 $data['NAME'] = $name;
102 if($key == "ACTIVE" && $key === "ACTIVE"){
103 $data['ACTIVE'] = TRUE;
104 }else{
105 $data['ACTIVE'] = FALSE;
106 }
107 $this->scripts[] = $data;
108 }
109 }
110 }
112 /* Get script contents */
113 foreach($this->scripts as $key => $script){
114 $p = new My_Parser;
115 $sieve->sieve_getscript($script['NAME']);
117 $script = "";
118 foreach($sieve->response as $line){
119 $script.=$line;
120 }
122 $this->scripts[$key]['IS_NEW'] = FALSE;;
123 $this->scripts[$key]['SCRIPT'] = $script;
124 $this->scripts[$key]['ORIG_SCRIPT'] = $script;
125 $this->scripts[$key]['MSG'] = "";
126 $ret = $p->parse($script);
127 if(!$ret){
128 $this->scripts[$key]['STATUS'] = FALSE;
129 $this->scripts[$key]['MODE'] = "Source-Only";
130 $this->scripts[$key]['MSG'] = _("Parse failed")."<font color='red'>".$p->status_text."</font>";
131 }else{
132 $this->scripts[$key]['STATUS'] = TRUE;
133 $this->scripts[$key]['MODE'] = "Structured";
134 $this->scripts[$key]['MSG'] = _("Parse successful");
135 }
136 $this->scripts[$key]['PARSER'] = $p;
137 $this->scripts[$key]['EDITED'] = FALSE;
138 }
139 $this->sieve_handle = $sieve;
140 }
143 /* Handle sieve list
144 */
145 function execute()
146 {
147 /***************
148 * Create a new Script
149 ***************/
151 /* Force opening the add script dialog */
152 if(isset($_POST['create_new_script'])){
153 $this->create_script = TRUE;
154 }
156 /* Close add script dialog, without adding a new one */
157 if(isset($_POST['create_script_cancel'])){
158 $this->create_script = FALSE;
159 }
161 /* Display create script dialog
162 * handle posts, display warnings if specified
163 * name is not useable.
164 * Create a new script with given name
165 */
166 if($this->create_script){
168 /* Set initial name or used posted name if available */
169 $name = "";
170 if(isset($_POST['NewScriptName'])){
171 $name = trim($_POST['NewScriptName']);
172 }
174 /* Check given name */
175 $err = "";
177 /* Is given name in lower case characters ? */
178 if(isset($_POST['create_script_save'])){
179 if(!strlen($name)){
180 $err = _("You should specify a name for your new script.");
181 }
182 /* Is given name in lower case characters ? */
183 if($name != strtolower($name)){
184 $err = _("Only lower case names are allowed here.");
185 }
187 /* Only chars are allowed here */
188 if(preg_match("/[^a-z]/i",$name)){
189 $err = _("Only a-z are allowed in script names.");
190 }
191 }
193 /* Create script if everything is ok */
194 if($this->create_script && isset($_POST['create_script_save']) && $err == "" ){
196 /* Close dialog */
197 $this->create_script = FALSE;
199 /* Script contents to use */
200 $script = "/*New script */".
201 "stop;";
203 /* Create a new parser and initialize default values */
204 $p = new My_Parser;
205 $ret = $p->parse($script);
206 $sc['SCRIPT'] = $script;
207 $sc['ORIG_SCRIPT'] = $script;
208 $sc['IS_NEW'] = TRUE;
209 $sc['MSG'] = "";
210 if(!$ret){
211 $sc['STATUS'] = FALSE;
212 $sc['MODE'] = "Source-Only";
213 $sc['MSG'] = _("Parse failed")."<font color='red'>".$p->status_text."</font>";
214 }else{
215 $sc['STATUS'] = TRUE;
216 $sc['MODE'] = "Strucktured";
217 $sc['MSG'] = _("Parse successful");
218 }
219 $sc['PARSER'] = $p;
220 $sc['EDITED'] = TRUE;
221 $sc['ACTIVE'] = FALSE;
222 $sc['NAME'] = $name;
224 /* Add script */
225 $this->scripts[$name] = $sc;
226 }else{
228 /* Display dialog to enter new script name */
229 $smarty = get_smarty();
230 $smarty->assign("NewScriptName",$name);
231 $smarty->assign("Error",$err);
232 return($smarty->fetch(get_template_path("templates/create_script.tpl",TRUE,dirname(__FILE__))));
233 }
234 }
237 /*************
238 * Handle several posts
239 *************/
241 $once = TRUE;
242 foreach($_POST as $name => $value){
244 /* Edit script requested */
245 if(preg_match("/^editscript_/",$name) && $once && !$this->current_handler){
246 $script = preg_replace("/^editscript_/","",$name);
247 $script = preg_replace("/_(x|y)/","",$script);
248 $once = FALSE;
250 $this->current_script = $script;
251 $this->current_handler = $this->scripts[$script]['PARSER'];
252 }
254 /* remove script requested */
255 if(preg_match("/^delscript_/",$name) && $once && !$this->current_handler){
256 $script = preg_replace("/^delscript_/","",$name);
257 $script = preg_replace("/_(x|y)/","",$script);
258 $once = FALSE;
260 $this->script_to_delete = $script;
261 }
263 /* Activate script */
264 if(preg_match("/^active_script_/",$name) && $once && !$this->current_handler){
265 $script = preg_replace("/^active_script_/","",$name);
266 $script = preg_replace("/_(x|y)/","",$script);
267 $once = FALSE;
269 /* Get sieve */
270 if(!$sieve = $this->get_sieve()){
271 print_red(
272 sprintf(
273 _("Can't log into SIEVE server. Server says '%s'."),
274 to_string($this->Sieve_Error)));
275 }
277 /* Try to activate the given script and update
278 * class script array.
279 */
280 if(!$this->sieve_handle->sieve_setactivescript($this->scripts[$script]['NAME'])){
281 print_red(sprintf(_("Can't activate sieve script on server. Server says '%s'."),to_string($this->sieve_handle->error_raw)));
282 }else{
283 foreach($this->scripts as $key => $data){
284 if($key == $script){
285 $this->scripts[$key]['ACTIVE'] = TRUE;
286 }else{
287 $this->scripts[$key]['ACTIVE'] = FALSE;
288 }
289 }
290 }
291 }
292 }
295 /*************
296 * Remove script handling
297 *************/
299 /* Remove aborted */
300 if(isset($_POST['delete_cancel'])){
301 $this->script_to_delete = -1;
302 }
304 /* Remove confirmed */
305 if(isset($_POST['delete_script_confirm'])){
307 $script = $this->scripts[$this->script_to_delete];
309 /* Just remove from array if it is a new script */
310 if($script['IS_NEW']){
311 unset($this->scripts[$this->script_to_delete]);
312 }else{
314 /* Get sieve */
315 if(!$sieve = $this->get_sieve()){
316 print_red(
317 sprintf(
318 _("Can't log into SIEVE server. Server says '%s'."),
319 to_string($this->Sieve_Error)));
320 }
322 if(!$this->sieve_handle->sieve_deletescript($this->scripts[$this->script_to_delete]['NAME'])){
323 print_red(sprintf(_("Can't remove sieve script from server. Server says '%s'."),to_string($this->sieve_handle->error_raw)));
324 }else{
325 unset($this->scripts[$this->script_to_delete]);
326 }
327 }
328 $this->script_to_delete = -1;
329 }
331 /* Display confirm dialog */
332 if($this->script_to_delete != -1){
333 $smarty = get_smarty();
334 $smarty->assign("Warning",
335 sprintf(_("You are going to remove the sieve script '%s' from your mail server."),
336 $this->scripts[$this->script_to_delete]['NAME']));
337 return($smarty->fetch(get_template_path("templates/remove_script.tpl",TRUE,dirname(__FILE__))));
338 }
341 /**************
342 * Save script changes
343 **************/
345 /* Abort saving */
346 if(isset($_POST['cancel_sieve_changes'])){
347 $this->current_handler = NULL;
348 }
350 /* Save currently edited sieve script. */
351 if(isset($_POST['save_sieve_changes'])){
352 $chk = $this->current_handler->check();
353 if(!count($chk)){
355 $sc = $this->scripts[$this->current_script]['SCRIPT'];
356 $p = new My_Parser;
357 if($p -> parse($sc)){
359 if($this->scripts[$this->current_script]['MODE'] == "Source-Only"){
360 $this->scripts[$this->current_script]['MODE'] = "Source";
361 }
363 $this->scripts[$this->current_script]['PARSER'] = $p;
364 $this->scripts[$this->current_script]['EDITED'] = TRUE;
365 $this->scripts[$this->current_script]['STATUS'] = TRUE;
366 $this->scripts[$this->current_script]['MSG'] = _("Edited");
367 $this->current_handler = NULL;
368 }else{
369 print_red($p->status_text);;
370 }
371 }else{
372 print_red(_("Please fix all errors before saving."));
373 }
374 }
377 /*************
378 * Display edit dialog
379 *************/
381 /* Display edit dialog, depending on Mode display different uis
382 */
383 if($this->current_handler){
385 /****
386 * Add new element to ui
387 ****/
389 /* Abort add dialog */
390 if(isset($_POST['select_new_element_type_cancel'])){
391 $this->add_new_element = FALSE;
392 }
394 /* Add a new element */
395 if($this->add_new_element){
397 $element_types= array(
398 "sieve_keep" => _("Keep"),
399 "sieve_comment" => _("Comment"),
400 "sieve_fileinto" => _("File into"),
401 "sieve_keep" => _("Keep"),
402 "sieve_discard" => _("Discard"),
403 "sieve_redirect" => _("Redirect"),
404 "sieve_reject" => _("Reject"),
405 "sieve_require" => _("Require"),
406 "sieve_stop" => _("Stop"),
407 "sieve_vacation" => _("Vacation message"),
408 "sieve_if" => _("If"));
411 /* Element selected */
412 if(isset($_POST['element_type']) && isset($element_types[$_POST['element_type']])){
413 $this->add_element_type = $_POST['element_type'];
414 }
416 /* Create new element and add it to
417 * the selected position
418 */
419 if(isset($_POST['select_new_element_type'])){
421 /* Create elements we should add */
422 $ele[] = new $this->add_element_type(NULL, preg_replace("/[^0-9]/","",microtime()));
423 if($this->add_element_type == "sieve_if"){
424 $ele[] = new sieve_block_start(NULL,preg_replace("/[^0-9]/","",microtime()));
425 $ele[] = new sieve_block_end(NULL,preg_replace("/[^0-9]/","",microtime()));
426 }
427 $start = $end = array();
428 $found = false;
429 $data = $this->current_handler->tree_->pap;
431 /* Add above current element*/
432 if($this->add_above_below == "above"){
433 foreach($data as $key => $obj){
434 if($obj->object_id == $this->add_new_id){
435 $found = true;
436 }
437 if(!$found){
438 $start[] = $obj;
439 }else{
440 $end[] = $obj;
441 }
442 }
443 }else{
444 /* Add below current element */
445 foreach($data as $key => $obj){
446 if(!$found){
447 $start[] = $obj;
448 }else{
449 $end[] = $obj;
450 }
451 if($obj->object_id == $this->add_new_id){
452 $found = true;
453 }
454 }
455 }
457 /* Only add, if current element could be located */
458 if($found){
459 $new = array();
460 foreach($start as $obj){
461 $new[] = $obj;
462 }
463 foreach($ele as $el){
464 $new[] = $el;
465 }
466 foreach($end as $obj){
467 $new[] = $obj;
468 }
469 $data= $new;
470 $this->current_handler->tree_->pap = $data;
471 $this->add_new_element = FALSE;
472 }else{
473 print_red(_("Something went wrong while adding a new entry."));
474 }
475 }
476 }
478 /* Only display select dialog if it is necessary */
479 if($this->add_new_element){
480 $smarty = get_smarty();
481 $smarty->assign("element_types",$element_types );
482 $smarty->assign("element_type",$this->add_element_type);
483 $str = $smarty->fetch(get_template_path("templates/add_element.tpl",TRUE,dirname(__FILE__)));
484 return($str);
485 }
489 /****************
490 * Handle test posts
491 ****************/
493 /* handle some special posts from test elements
494 */
495 foreach($_POST as $name => $value){
496 if(preg_match("/^Add_Test_Object_/",$name)) {
497 $name = preg_replace("/^Add_Test_Object_/","",$name);
498 $name = preg_replace("/_(x|y)$/","",$name);
500 $test_types_to_add = array(
501 "address" =>_("Address"),
502 "header" =>_("Header"),
503 "envelope"=>_("Envelope"),
504 "size" =>_("Size"),
505 "exists" =>_("Exists"),
506 "allof" =>_("All of"),
507 "anyof" =>_("Any of"),
508 "true" =>_("True"),
509 "false" =>_("False"));
511 $smarty = get_smarty();
512 $smarty->assign("ID",$name);
513 $smarty->assign("test_types_to_add",$test_types_to_add);
514 $ret = $smarty->fetch(get_template_path("templates/select_test_type.tpl",TRUE,dirname(__FILE__)));
515 return($ret);
516 }
517 }
519 $current = $this->scripts[$this->current_script];
521 /* Create html results */
522 $smarty = get_smarty();
523 $smarty->assign("Mode",$current['MODE']);
524 if($current['MODE'] == "Structured"){
525 $smarty->assign("Contents",$this->current_handler->tree_->execute());
526 }else{
527 $smarty->assign("Contents",$current['SCRIPT']);
528 }
529 $smarty->assign("Script_Error",$this->Script_Error);
530 $ret = $smarty->fetch(get_template_path("templates/edit_frame_base.tpl",TRUE,dirname(__FILE__)));
531 return($ret);
532 }
535 /* Create list of available sieve scripts
536 */
537 $List = new divSelectBox("sieveManagement");
538 foreach($this->scripts as $key => $script){
540 $edited = $script['EDITED'];
541 $active = $script['ACTIVE'];
543 $field1 = array("string" => " ",
544 "attach" => "style='width:20px;'");
545 if($active){
546 $field1 = array("string" => "<img src='images/true.png' alt='"._("Active")."'>",
547 "attach" => "style='width:20px;'");
548 }
549 $field2 = array("string" => $script['NAME']);
550 $field3 = array("string" => $script['MSG']);
551 $field4 = array("string" => _("Script length")." : ".strlen($script['SCRIPT']));
553 if($edited){
554 $field5 = array("string" => "<img src='images/fai_new_hook.png' alt='"._("Edited")."'>",
555 "attach" => "style='width:30px;'");
556 }else{
557 $field5 = array("string" => "",
558 "attach" => "style='width:30px;'");
559 }
561 if($active){
562 $field6 = array("string" => "<img src='images/empty.png' alt=' '>".
563 "<input type='image' name='editscript_".$key."' src='images/edit.png'>".
564 "<input type='image' name='delscript_".$key."' src='images/edittrash.png'>");
565 }else{
566 $field6 = array("string" => "<input type='image' name='active_script_".$key."' src='images/true.png'>".
567 "<input type='image' name='editscript_".$key."' src='images/edit.png'>".
568 "<input type='image' name='delscript_".$key."' src='images/edittrash.png'>");
569 }
570 $List ->AddEntry(array($field1,$field2,$field3,$field4,$field5,$field6));
571 }
573 $display ="<h2>Sieve script management</h2>";
574 $display .= _("Be careful. All your changes will be saved directly to sieve, if you use the save button below.");
575 $display .= "<br><input type='submit' name='create_new_script' value='"._("Create new script")."'>";
576 $display .= $List->DrawList();
578 $display .= "<p style=\"text-align:right\">\n";
579 $display .= "<input type=submit name=\"sieve_finish\" style=\"width:80px\" value=\""._("Ok")."\">\n";
580 $display .= " \n";
581 $display .= "<input type=submit name=\"sieve_cancel\" value=\""._("Cancel")."\">\n";
582 $display .= "</p>";
583 return($display);;
584 }
586 function save_object()
587 {
588 if($this->current_handler){
590 /* Check if there is an add object requested
591 */
592 $data = $this->current_handler->tree_->pap;
593 $once = TRUE;
594 foreach($_POST as $name => $value){
595 foreach($data as $key => $obj){
596 if(isset($obj->object_id) && preg_match("/^Add_Object_Top_".$obj->object_id."_/",$name) && $once){
597 $once = FALSE;
598 $this->add_new_element = TRUE;
599 $this->add_new_id = $obj->object_id;
600 $this->add_above_below = "above";
601 }
602 if(isset($obj->object_id) && preg_match("/^Add_Object_Bottom_".$obj->object_id."_/",$name) && $once){
603 $once = FALSE;
604 $this->add_new_element = TRUE;
605 $this->add_new_id = $obj->object_id;
606 $this->add_above_below = "below";
607 }
609 if(isset($obj->object_id) && preg_match("/^Remove_Object_".$obj->object_id."_/",$name) && $once){
610 $once = FALSE;
611 $this->current_handler->tree_->remove_object($key);
612 }
613 if(isset($obj->object_id) && preg_match("/^Move_Up_Object_".$obj->object_id."_/",$name) && $once){
614 $this->current_handler->tree_->move_up_down($key,"up");
615 $once = FALSE;
616 }
617 if(isset($obj->object_id) && preg_match("/^Move_Down_Object_".$obj->object_id."_/",$name) && $once){
618 $this->current_handler->tree_->move_up_down($key,"down");
619 $once = FALSE;
620 }
621 }
622 }
624 /* Skip Mode changes and Parse tests
625 * if we are currently in a subdialog
626 */
627 if(!$this->add_new_element) {
629 $Mode = $this->scripts[$this->current_script]['MODE'];
630 $skip_mode_change = false;
631 if(in_array($Mode,array("Source-Only","Source"))){
632 if(isset($_POST['script_contents'])){
633 $sc = stripslashes($_POST['script_contents']);
634 $this->scripts[$this->current_script]['SCRIPT'] = $sc;
635 $p = new My_Parser;
636 if($p -> parse($sc)){
637 $this->current_handler = $p;
638 $this->Script_Error = "";
639 } else {
640 $this->Script_Error = $p->status_text;
641 $skip_mode_change = TRUE;
642 }
643 }
644 }
645 if(in_array($Mode,array("Structured"))){
646 $this->current_handler->save_object();
647 $sc = $this->current_handler->get_sieve_script();
648 $this->scripts[$this->current_script]['SCRIPT'] = $sc;
649 $p = new My_Parser;
650 if($p -> parse($sc)){
651 $this->current_handler = $p;
652 $this->Script_Error = "";
653 } else {
654 $this->Script_Error = $p->status_text;
655 $skip_mode_change = TRUE;
656 }
657 }
658 if(!$skip_mode_change){
659 if($this->scripts[$this->current_script]['MODE'] != "Source-Only"){
660 if(isset($_POST['View_Source'])){
661 $this->scripts[$this->current_script]['MODE'] = "Source";
662 }
663 if(isset($_POST['View_Structured'])){
664 $this->scripts[$this->current_script]['MODE'] = "Structured";
665 }
666 }
667 }
668 }
669 $this->current_handler->save_object();
670 }
671 }
674 function save()
675 {
676 /* Connect to sieve class and try to get all available sieve scripts */
677 $cfg= $this->config->data['SERVERS']['IMAP'][$this->parent->gosaMailServer];
679 $this->sieve_handle=
680 new sieve( $cfg["sieve_server"],
681 $cfg["sieve_port"],
682 $this->parent->mail,
683 $cfg["password"],
684 $cfg["admin"]);
686 if (!$this->sieve_handle->sieve_login()){
687 print_red(sprintf(_("Can't log into SIEVE server. Server says '%s'."),to_string($this->sieve_handle->error_raw)));
688 return;
689 }
691 $everything_went_fine = TRUE;
693 foreach($this->scripts as $key => $script){
694 if($script['EDITED']){
695 $data = $this->scripts[$key]['SCRIPT'];
696 if(!$this->sieve_handle->sieve_sendscript($script['NAME'], $data)){
697 gosa_log("Failed to save sieve script named '".$script['NAME']."': ".to_string($this->sieve_handle->error_raw));
698 $everything_went_fine = FALSE;
699 print_red(to_string($this->sieve_handle->error_raw));
700 $this->scripts[$key]['MSG'] = "<font color='red'>".
701 _("Failed to save sieve script").": ".
702 to_string($this->sieve_handle->error_raw).
703 "</font>";
704 }
705 }
706 }
707 return($everything_went_fine);
708 }
709 }
710 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
711 ?>