source: subversion/trunk/plugins/managesieve/managesieve.php @ 3703

Last change on this file since 3703 was 3703, checked in by alec, 3 years ago
  • Support %n and %d variables in managesieve_host option
  • Property svn:keywords set to Id
File size: 46.0 KB
Line 
1<?php
2
3/**
4 * Managesieve (Sieve Filters)
5 *
6 * Plugin that adds a possibility to manage Sieve filters in Thunderbird's style.
7 * It's clickable interface which operates on text scripts and communicates
8 * with server using managesieve protocol. Adds Filters tab in Settings.
9 *
10 * @version 2.6
11 * @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl>
12 *
13 * Configuration (see config.inc.php.dist)
14 *
15 * $Id$
16 */
17
18class managesieve extends rcube_plugin
19{
20    public $task = 'settings';
21
22    private $rc;
23    private $sieve;
24    private $errors;
25    private $form;
26    private $script = array();
27    private $exts = array();
28    private $headers = array(
29        'subject'   => 'Subject',
30        'sender'    => 'From',
31        'recipient' => 'To',
32    );
33
34
35    function init()
36    {
37        // add Tab label/title
38        $this->add_texts('localization/', array('filters','managefilters'));
39
40        // register actions
41        $this->register_action('plugin.managesieve', array($this, 'managesieve_actions'));
42        $this->register_action('plugin.managesieve-save', array($this, 'managesieve_save'));
43
44        // include main js script
45        $this->include_script('managesieve.js');
46    }
47
48    function managesieve_start()
49    {
50        $this->rc = rcmail::get_instance();
51        $this->load_config();
52
53        // register UI objects
54        $this->rc->output->add_handlers(array(
55            'filterslist'    => array($this, 'filters_list'),
56            'filtersetslist' => array($this, 'filtersets_list'),
57            'filterframe'    => array($this, 'filter_frame'),
58            'filterform'     => array($this, 'filter_form'),
59            'filtersetform'  => array($this, 'filterset_form'),
60        ));
61
62        require_once($this->home . '/lib/Net/Sieve.php');
63        require_once($this->home . '/lib/rcube_sieve.php');
64
65        $host = rcube_parse_host($this->rc->config->get('managesieve_host', 'localhost'));
66        $port = $this->rc->config->get('managesieve_port', 2000);
67
68        // try to connect to managesieve server and to fetch the script
69        $this->sieve = new rcube_sieve($_SESSION['username'],
70            $this->rc->decrypt($_SESSION['password']), $host, $port,
71            $this->rc->config->get('managesieve_usetls', false),
72            $this->rc->config->get('managesieve_disabled_extensions'),
73            $this->rc->config->get('managesieve_debug', false)
74        );
75
76        if (!($error = $this->sieve->error())) {
77
78            $list = $this->sieve->get_scripts();
79            $active = $this->sieve->get_active();
80            $_SESSION['managesieve_active'] = $active;
81
82            if (!empty($_GET['_set'])) {
83                $script_name = get_input_value('_set', RCUBE_INPUT_GET);
84            }
85            else if (!empty($_SESSION['managesieve_current'])) {
86                $script_name = $_SESSION['managesieve_current'];
87            }
88            else {
89                // get active script
90                if ($active) {
91                    $script_name = $active;
92                }
93                else if ($list) {
94                    $script_name = $list[0];
95                }
96                // create a new (initial) script
97                else {
98                    // if script not exists build default script contents
99                    $script_file = $this->rc->config->get('managesieve_default');
100                    $script_name = 'roundcube';
101                    if ($script_file && is_readable($script_file))
102                        $content = file_get_contents($script_file);
103
104                // add script and set it active
105                if ($this->sieve->save_script($script_name, $content))
106                    if ($this->sieve->activate($script_name))
107                        $_SESSION['managesieve_active'] = $script_name;
108                }
109            }
110
111            if ($script_name)
112                $this->sieve->load($script_name);
113
114            $error = $this->sieve->error();
115        }
116
117        // finally set script objects
118        if ($error) {
119            switch ($error) {
120                case SIEVE_ERROR_CONNECTION:
121                case SIEVE_ERROR_LOGIN:
122                    $this->rc->output->show_message('managesieve.filterconnerror', 'error');
123                    break;
124                default:
125                    $this->rc->output->show_message('managesieve.filterunknownerror', 'error');
126                    break;
127            }
128
129            raise_error(array('code' => 403, 'type' => 'php',
130                'file' => __FILE__, 'line' => __LINE__,
131                'message' => "Unable to connect to managesieve on $host:$port"), true, false);
132
133            // to disable 'Add filter' button set env variable
134            $this->rc->output->set_env('filterconnerror', true);
135            $this->script = array();
136        }
137        else {
138            $this->script = $this->sieve->script->as_array();
139            $this->exts = $this->sieve->get_extensions();
140            $this->rc->output->set_env('active_set', $_SESSION['managesieve_active']);
141            $_SESSION['managesieve_current'] = $this->sieve->current;
142        }
143
144        return $error;
145    }
146
147    function managesieve_actions()
148    {
149        // Init plugin and handle managesieve connection
150        $error = $this->managesieve_start();
151
152        // Handle user requests
153        if ($action = get_input_value('_act', RCUBE_INPUT_GPC)) {
154            $fid = (int) get_input_value('_fid', RCUBE_INPUT_GET);
155
156            if ($action == 'up' && !$error) {
157                if ($fid && isset($this->script[$fid]) && isset($this->script[$fid-1])) {
158                    if ($this->sieve->script->update_rule($fid, $this->script[$fid-1]) !== false
159                        && $this->sieve->script->update_rule($fid-1, $this->script[$fid]) !== false) {
160                        $result = $this->sieve->save();
161                    }
162
163                    if ($result) {
164//                      $this->rc->output->show_message('managesieve.filtersaved', 'confirmation');
165                        $this->rc->output->command('managesieve_updatelist', 'up', '', $fid);
166                    } else
167                        $this->rc->output->show_message('managesieve.filtersaveerror', 'error');
168                }
169            }
170            else if ($action == 'down' && !$error) {
171                if (isset($this->script[$fid]) && isset($this->script[$fid+1])) {
172                    if ($this->sieve->script->update_rule($fid, $this->script[$fid+1]) !== false
173                        && $this->sieve->script->update_rule($fid+1, $this->script[$fid]) !== false) {
174                        $result = $this->sieve->save();
175                    }
176
177                    if ($result === true) {
178//                      $this->rc->output->show_message('managesieve.filtersaved', 'confirmation');
179                        $this->rc->output->command('managesieve_updatelist', 'down', '', $fid);
180                    } else {
181                        $this->rc->output->show_message('managesieve.filtersaveerror', 'error');
182                    }
183                }
184            }
185            else if ($action == 'delete' && !$error) {
186                if (isset($this->script[$fid])) {
187                    if ($this->sieve->script->delete_rule($fid))
188                        $result = $this->sieve->save();
189
190                    if ($result === true) {
191                        $this->rc->output->show_message('managesieve.filterdeleted', 'confirmation');
192                        $this->rc->output->command('managesieve_updatelist', 'delete', '', $fid);
193                    } else {
194                        $this->rc->output->show_message('managesieve.filterdeleteerror', 'error');
195                    }
196                }
197            }
198            else if ($action == 'setact' && !$error) {
199                $script_name = get_input_value('_set', RCUBE_INPUT_GPC);
200                $result = $this->sieve->activate($script_name);
201
202                if ($result === true) {
203                    $this->rc->output->set_env('active_set', $script_name);
204                    $this->rc->output->show_message('managesieve.setactivated', 'confirmation');
205                    $this->rc->output->command('managesieve_reset');
206                    $_SESSION['managesieve_active'] = $script_name;
207                } else {
208                    $this->rc->output->show_message('managesieve.setactivateerror', 'error');
209                }
210            }
211            else if ($action == 'deact' && !$error) {
212                $result = $this->sieve->deactivate();
213
214                if ($result === true) {
215                    $this->rc->output->set_env('active_set', '');
216                    $this->rc->output->show_message('managesieve.setdeactivated', 'confirmation');
217                    $this->rc->output->command('managesieve_reset');
218                    $_SESSION['managesieve_active'] = '';
219                } else {
220                    $this->rc->output->show_message('managesieve.setdeactivateerror', 'error');
221                }
222            }
223            else if ($action == 'setdel' && !$error) {
224                $script_name = get_input_value('_set', RCUBE_INPUT_GPC);
225                $result = $this->sieve->remove($script_name);
226
227                if ($result === true) {
228                    $this->rc->output->show_message('managesieve.setdeleted', 'confirmation');
229                    $this->rc->output->command('managesieve_reload');
230                    $this->rc->session->remove('managesieve_current');
231                } else {
232                    $this->rc->output->show_message('managesieve.setdeleteerror', 'error');
233                }
234            }
235            else if ($action == 'setget') {
236                $script_name = get_input_value('_set', RCUBE_INPUT_GPC);
237                $script = $this->sieve->get_script($script_name);
238
239                if (PEAR::isError($script))
240                    exit;
241
242                $browser = new rcube_browser;
243
244                // send download headers
245                header("Content-Type: application/octet-stream");
246                header("Content-Length: ".strlen($script));
247
248                if ($browser->ie)
249                    header("Content-Type: application/force-download");
250                if ($browser->ie && $browser->ver < 7)
251                    $filename = rawurlencode(abbreviate_string($script_name, 55));
252                else if ($browser->ie)
253                    $filename = rawurlencode($script_name);
254                else
255                    $filename = addcslashes($script_name, '\\"');
256
257                header("Content-Disposition: attachment; filename=\"$filename.txt\"");
258                echo $script;
259                exit;
260            }
261            elseif ($action == 'ruleadd') {
262                $rid = get_input_value('_rid', RCUBE_INPUT_GPC);
263                $id = $this->genid();
264                $content = $this->rule_div($fid, $id, false);
265
266                $this->rc->output->command('managesieve_rulefill', $content, $id, $rid);
267            }
268            elseif ($action == 'actionadd') {
269                $aid = get_input_value('_aid', RCUBE_INPUT_GPC);
270                $id = $this->genid();
271                $content = $this->action_div($fid, $id, false);
272
273                $this->rc->output->command('managesieve_actionfill', $content, $id, $aid);
274            }
275
276            $this->rc->output->send();
277        }
278
279        $this->managesieve_send();
280    }
281
282    function managesieve_save()
283    {
284        // Init plugin and handle managesieve connection
285        $error = $this->managesieve_start();
286
287        // filters set add action
288        if (!empty($_POST['_newset'])) {
289            $name = get_input_value('_name', RCUBE_INPUT_POST);
290            $copy = get_input_value('_copy', RCUBE_INPUT_POST);
291            $from = get_input_value('_from', RCUBE_INPUT_POST);
292
293            if (!$name)
294                $error = 'managesieve.emptyname';
295            else if (mb_strlen($name)>128)
296                $error = 'managesieve.nametoolong';
297            else if ($from == 'file') {
298                // from file
299                if (is_uploaded_file($_FILES['_file']['tmp_name'])) {
300                    $file = file_get_contents($_FILES['_file']['tmp_name']);
301                    $file = preg_replace('/\r/', '', $file);
302                    // for security don't save script directly
303                    // check syntax before, like this...
304                    $this->sieve->load_script($file);
305                    if (!$this->sieve->save($name)) {
306                        $error = 'managesieve.setcreateerror';
307                    }
308                }
309                else {  // upload failed
310                    $err = $_FILES['_file']['error'];
311                    $error = true;
312
313                    if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
314                        $msg = rcube_label(array('name' => 'filesizeerror',
315                            'vars' => array('size' =>
316                                show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
317                    }
318                    else {
319                        $error = 'fileuploaderror';
320                    }
321                }
322            }
323            else if (!$this->sieve->copy($name, $from == 'set' ? $copy : '')) {
324                $error = 'managesieve.setcreateerror';
325            }
326
327            if (!$error) {
328                $this->rc->output->show_message('managesieve.setcreated', 'confirmation');
329                $this->rc->output->command('parent.managesieve_reload', $name);
330            } else if ($msg) {
331                $this->rc->output->command('display_message', $msg, 'error');
332            } else {
333                $this->rc->output->show_message($error, 'error');
334            }
335        }
336        // filter add/edit action
337        else if (isset($_POST['_name'])) {
338            $name = trim(get_input_value('_name', RCUBE_INPUT_POST, true));
339            $fid  = trim(get_input_value('_fid', RCUBE_INPUT_POST));
340            $join = trim(get_input_value('_join', RCUBE_INPUT_POST));
341
342            // and arrays
343            $headers = $_POST['_header'];
344            $cust_headers = $_POST['_custom_header'];
345            $ops = $_POST['_rule_op'];
346            $sizeops = $_POST['_rule_size_op'];
347            $sizeitems = $_POST['_rule_size_item'];
348            $sizetargets = $_POST['_rule_size_target'];
349            $targets = $_POST['_rule_target'];
350            $act_types = $_POST['_action_type'];
351            $mailboxes = $_POST['_action_mailbox'];
352            $act_targets = $_POST['_action_target'];
353            $area_targets = $_POST['_action_target_area'];
354            $reasons = $_POST['_action_reason'];
355            $addresses = $_POST['_action_addresses'];
356            $days = $_POST['_action_days'];
357
358            // we need a "hack" for radiobuttons
359            foreach ($sizeitems as $item)
360                $items[] = $item;
361
362            $this->form['disabled'] = $_POST['_disabled'] ? true : false;
363            $this->form['join']     = $join=='allof' ? true : false;
364            $this->form['name']     = $name;
365            $this->form['tests']    = array();
366            $this->form['actions']  = array();
367
368            if ($name == '')
369                $this->errors['name'] = $this->gettext('cannotbeempty');
370            else
371                foreach($this->script as $idx => $rule)
372                    if($rule['name'] == $name && $idx != $fid) {
373                        $this->errors['name'] = $this->gettext('ruleexist');
374                        break;
375                    }
376
377            $i = 0;
378            // rules
379            if ($join == 'any') {
380                $this->form['tests'][0]['test'] = 'true';
381            }
382            else {
383                foreach($headers as $idx => $header) {
384                    $header = $this->strip_value($header);
385                    $target = $this->strip_value($targets[$idx], true);
386                    $op     = $this->strip_value($ops[$idx]);
387
388                    // normal header
389                    if (in_array($header, $this->headers)) {
390                        if(preg_match('/^not/', $op))
391                            $this->form['tests'][$i]['not'] = true;
392                        $type = preg_replace('/^not/', '', $op);
393
394                        if ($type == 'exists') {
395                            $this->form['tests'][$i]['test'] = 'exists';
396                            $this->form['tests'][$i]['arg'] = $header;
397                        }
398                        else {
399                            $this->form['tests'][$i]['type'] = $type;
400                            $this->form['tests'][$i]['test'] = 'header';
401                            $this->form['tests'][$i]['arg1'] = $header;
402                            $this->form['tests'][$i]['arg2'] = $target;
403
404                            if ($target == '')
405                                $this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty');
406                        }
407                    }
408                    else
409                        switch ($header) {
410                        case 'size':
411                            $sizeop     = $this->strip_value($sizeops[$idx]);
412                            $sizeitem   = $this->strip_value($items[$idx]);
413                            $sizetarget = $this->strip_value($sizetargets[$idx]);
414
415                            $this->form['tests'][$i]['test'] = 'size';
416                            $this->form['tests'][$i]['type'] = $sizeop;
417                            $this->form['tests'][$i]['arg']  = $sizetarget.$sizeitem;
418
419                            if (!preg_match('/^[0-9]+(K|M|G)*$/i', $sizetarget))
420                                $this->errors['tests'][$i]['sizetarget'] = $this->gettext('wrongformat');
421                            break;
422                        case '...':
423                            $cust_header = $headers = $this->strip_value($cust_headers[$idx]);
424
425                            if(preg_match('/^not/', $op))
426                                $this->form['tests'][$i]['not'] = true;
427                            $type = preg_replace('/^not/', '', $op);
428
429                            if ($cust_header == '')
430                                $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty');
431                            else {
432                                $headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY);
433
434                                if (!count($headers))
435                                    $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty');
436                                else {
437                                    foreach ($headers as $hr)
438                                        if (!preg_match('/^[a-z0-9-]+$/i', $hr))
439                                            $this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars');
440                                }
441                            }
442
443                            if (empty($this->errors['tests'][$i]['header']))
444                                $cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers;
445
446                            if ($type == 'exists') {
447                                $this->form['tests'][$i]['test'] = 'exists';
448                                $this->form['tests'][$i]['arg']  = $cust_header;
449                            }
450                            else {
451                                $this->form['tests'][$i]['test'] = 'header';
452                                $this->form['tests'][$i]['type'] = $type;
453                                $this->form['tests'][$i]['arg1'] = $cust_header;
454                                $this->form['tests'][$i]['arg2'] = $target;
455
456                                if ($target == '')
457                                    $this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty');
458                            }
459                            break;
460                        }
461                    $i++;
462                }
463            }
464
465            $i = 0;
466            // actions
467            foreach($act_types as $idx => $type) {
468                $type   = $this->strip_value($type);
469                $target = $this->strip_value($act_targets[$idx]);
470
471                $this->form['actions'][$i]['type'] = $type;
472
473                switch ($type) {
474                case 'fileinto':
475                    $mailbox = $this->strip_value($mailboxes[$idx]);
476                    $this->form['actions'][$i]['target'] = $mailbox;
477                    break;
478                case 'reject':
479                case 'ereject':
480                    $target = $this->strip_value($area_targets[$idx]);
481                    $this->form['actions'][$i]['target'] = str_replace("\r\n", "\n", $target);
482
483 //                 if ($target == '')
484//                      $this->errors['actions'][$i]['targetarea'] = $this->gettext('cannotbeempty');
485                    break;
486                case 'redirect':
487                    $this->form['actions'][$i]['target'] = $target;
488
489                    if ($this->form['actions'][$i]['target'] == '')
490                        $this->errors['actions'][$i]['target'] = $this->gettext('cannotbeempty');
491                    else if (!check_email($this->form['actions'][$i]['target']))
492                        $this->errors['actions'][$i]['target'] = $this->gettext('noemailwarning');
493                    break;
494                case 'vacation':
495                    $reason = $this->strip_value($reasons[$idx]);
496                    $this->form['actions'][$i]['reason']    = str_replace("\r\n", "\n", $reason);
497                    $this->form['actions'][$i]['days']      = $days[$idx];
498                    $this->form['actions'][$i]['addresses'] = explode(',', $addresses[$idx]);
499// @TODO: vacation :subject, :mime, :from, :handle
500
501                    if ($this->form['actions'][$i]['addresses']) {
502                        foreach($this->form['actions'][$i]['addresses'] as $aidx => $address) {
503                            $address = trim($address);
504                            if (!$address)
505                                unset($this->form['actions'][$i]['addresses'][$aidx]);
506                            else if(!check_email($address)) {
507                                $this->errors['actions'][$i]['addresses'] = $this->gettext('noemailwarning');
508                                break;
509                            } else
510                                $this->form['actions'][$i]['addresses'][$aidx] = $address;
511                        }
512                    }
513
514                    if ($this->form['actions'][$i]['reason'] == '')
515                        $this->errors['actions'][$i]['reason'] = $this->gettext('cannotbeempty');
516                    if ($this->form['actions'][$i]['days'] && !preg_match('/^[0-9]+$/', $this->form['actions'][$i]['days']))
517                        $this->errors['actions'][$i]['days'] = $this->gettext('forbiddenchars');
518                    break;
519                }
520
521                $i++;
522            }
523
524            if (!$this->errors) {
525                // zapis skryptu
526                if (!isset($this->script[$fid])) {
527                    $fid = $this->sieve->script->add_rule($this->form);
528                    $new = true;
529                } else
530                    $fid = $this->sieve->script->update_rule($fid, $this->form);
531
532                if ($fid !== false)
533                    $save = $this->sieve->save();
534
535                if ($save && $fid !== false) {
536                    $this->rc->output->show_message('managesieve.filtersaved', 'confirmation');
537                    $this->rc->output->add_script(
538                        sprintf("rcmail.managesieve_updatelist('%s', '%s', %d, %d);",
539                            isset($new) ? 'add' : 'update', Q($this->form['name']),
540                            $fid, $this->form['disabled']),
541                        'foot');
542                }
543                else {
544                    $this->rc->output->show_message('managesieve.filtersaveerror', 'error');
545//                  $this->rc->output->send();
546                }
547            }
548        }
549
550        $this->managesieve_send();
551    }
552
553    private function managesieve_send()
554    {
555        // Handle form action
556        if (isset($_GET['_framed']) || isset($_POST['_framed'])) {
557            if (isset($_GET['_newset']) || isset($_POST['_newset'])) {
558                $this->rc->output->send('managesieve.setedit');
559            }
560            else {
561                $this->rc->output->send('managesieve.filteredit');
562            }
563        } else {
564            $this->rc->output->set_pagetitle($this->gettext('filters'));
565            $this->rc->output->send('managesieve.managesieve');
566        }
567    }
568
569    // return the filters list as HTML table
570    function filters_list($attrib)
571    {
572        // add id to message list table if not specified
573        if (!strlen($attrib['id']))
574            $attrib['id'] = 'rcmfilterslist';
575
576        // define list of cols to be displayed
577        $a_show_cols = array('managesieve.filtername');
578
579        foreach($this->script as $idx => $filter)
580            $result[] = array(
581                'managesieve.filtername' => $filter['name'],
582                'id' => $idx,
583                'class' => $filter['disabled'] ? 'disabled' : '',
584            );
585
586        // create XHTML table
587        $out = rcube_table_output($attrib, $result, $a_show_cols, 'id');
588
589        // set client env
590        $this->rc->output->add_gui_object('filterslist', $attrib['id']);
591        $this->rc->output->include_script('list.js');
592
593        // add some labels to client
594        $this->rc->output->add_label('managesieve.filterdeleteconfirm');
595
596        return $out;
597    }
598
599    // return the filters list as <SELECT>
600    function filtersets_list($attrib)
601    {
602        // add id to message list table if not specified
603        if (!strlen($attrib['id']))
604            $attrib['id'] = 'rcmfiltersetslist';
605
606        $list = $this->sieve->get_scripts();
607        $active = $this->sieve->get_active();
608
609        $select = new html_select(array('name' => '_set', 'id' => $attrib['id'],
610            'onchange' => 'rcmail.managesieve_set()'));
611
612        if ($list) {
613            asort($list, SORT_LOCALE_STRING);
614
615            foreach ($list as $set)
616                $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set);
617        }
618
619        $out = $select->show($this->sieve->current);
620
621        // set client env
622        $this->rc->output->add_gui_object('filtersetslist', $attrib['id']);
623        $this->rc->output->add_label(
624            'managesieve.setdeleteconfirm',
625            'managesieve.active',
626            'managesieve.filtersetact',
627            'managesieve.filtersetdeact'
628        );
629
630        return $out;
631    }
632
633    function filter_frame($attrib)
634    {
635        if (!$attrib['id'])
636            $attrib['id'] = 'rcmfilterframe';
637
638        $attrib['name'] = $attrib['id'];
639
640        $this->rc->output->set_env('contentframe', $attrib['name']);
641        $this->rc->output->set_env('blankpage', $attrib['src'] ?
642        $this->rc->output->abs_url($attrib['src']) : 'program/blank.gif');
643
644        return html::tag('iframe', $attrib);
645    }
646
647    function filterset_form($attrib)
648    {
649        if (!$attrib['id'])
650            $attrib['id'] = 'rcmfiltersetform';
651
652        $out = '<form name="filtersetform" action="./" method="post" enctype="multipart/form-data">'."\n";
653
654        $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task));
655        $hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save'));
656        $hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
657        $hiddenfields->add(array('name' => '_newset', 'value' => 1));
658
659        $out .= $hiddenfields->show();
660
661        $name     = get_input_value('_name', RCUBE_INPUT_POST);
662        $copy     = get_input_value('_copy', RCUBE_INPUT_POST);
663        $selected = get_input_value('_from', RCUBE_INPUT_POST);
664
665        $table = new html_table(array('cols' => 2));
666
667        // filter set name input
668        $input_name = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30,
669            'class' => ($this->errors['name'] ? 'error' : '')));
670
671        $table->add('title', sprintf('<label for="%s"><b>%s:</b></label>',
672            '_name', Q($this->gettext('filtersetname'))));
673        $table->add(null, $input_name->show($name));
674
675        $from ='<div class="itemlist">';
676        $from .= '<input type="radio" id="from_none" name="_from" value="none"'
677            .(!$selected || $selected=='none' ? ' checked="checked"' : '').'></input>';
678        $from .= sprintf('<label for="%s">%s</label> ', 'from_none', Q($this->gettext('none')));
679
680        // filters set list
681        $list   = $this->sieve->get_scripts();
682        $active = $this->sieve->get_active();
683
684        $select = new html_select(array('name' => '_copy', 'id' => '_copy'));
685
686        if (is_array($list)) {
687            asort($list, SORT_LOCALE_STRING);
688
689            foreach ($list as $set)
690                $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set);
691
692            $from .= '<br /><input type="radio" id="from_set" name="_from" value="set"'
693                .($selected=='set' ? ' checked="checked"' : '').'></input>';
694            $from .= sprintf('<label for="%s">%s:</label> ', 'from_set', Q($this->gettext('fromset')));
695            $from .= $select->show($copy);
696        }
697
698        // script upload box
699        $upload = new html_inputfield(array('name' => '_file', 'id' => '_file', 'size' => 30,
700            'type' => 'file', 'class' => ($this->errors['name'] ? 'error' : '')));
701
702        $from .= '<br /><input type="radio" id="from_file" name="_from" value="file"'
703            .($selected=='file' ? ' checked="checked"' : '').'></input>';
704        $from .= sprintf('<label for="%s">%s:</label> ', 'from_file', Q($this->gettext('fromfile')));
705        $from .= $upload->show();
706        $from .= '</div>';
707
708        $table->add('title', '<label>'.$this->gettext('filters').':</label>');
709        $table->add(null, $from);
710
711        $out .= $table->show();
712
713        $this->rc->output->add_gui_object('sieveform', 'filtersetform');
714
715        return $out;
716    }
717
718
719    function filter_form($attrib)
720    {
721        if (!$attrib['id'])
722            $attrib['id'] = 'rcmfilterform';
723
724        $fid = get_input_value('_fid', RCUBE_INPUT_GPC);
725        $scr = isset($this->form) ? $this->form : $this->script[$fid];
726
727        $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task));
728        $hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save'));
729        $hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
730        $hiddenfields->add(array('name' => '_fid', 'value' => $fid));
731
732        $out = '<form name="filterform" action="./" method="post">'."\n";
733        $out .= $hiddenfields->show();
734
735        // 'any' flag
736        if (sizeof($scr['tests']) == 1 && $scr['tests'][0]['test'] == 'true' && !$scr['tests'][0]['not'])
737            $any = true;
738
739        // filter name input
740        $field_id = '_name';
741        $input_name = new html_inputfield(array('name' => '_name', 'id' => $field_id, 'size' => 30,
742            'class' => ($this->errors['name'] ? 'error' : '')));
743
744        if (isset($scr))
745            $input_name = $input_name->show($scr['name']);
746        else
747            $input_name = $input_name->show();
748
749        $out .= sprintf("\n<label for=\"%s\"><b>%s:</b></label> %s<br /><br />\n",
750            $field_id, Q($this->gettext('filtername')), $input_name);
751
752        $out .= '<fieldset><legend>' . Q($this->gettext('messagesrules')) . "</legend>\n";
753
754        // any, allof, anyof radio buttons
755        $field_id = '_allof';
756        $input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'allof',
757            'onclick' => 'rule_join_radio(\'allof\')', 'class' => 'radio'));
758
759        if (isset($scr) && !$any)
760            $input_join = $input_join->show($scr['join'] ? 'allof' : '');
761        else
762            $input_join = $input_join->show();
763
764        $out .= sprintf("%s<label for=\"%s\">%s</label>&nbsp;\n",
765            $input_join, $field_id, Q($this->gettext('filterallof')));
766
767        $field_id = '_anyof';
768        $input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'anyof',
769            'onclick' => 'rule_join_radio(\'anyof\')', 'class' => 'radio'));
770
771        if (isset($scr) && !$any)
772            $input_join = $input_join->show($scr['join'] ? '' : 'anyof');
773        else
774            $input_join = $input_join->show('anyof'); // default
775
776        $out .= sprintf("%s<label for=\"%s\">%s</label>\n",
777            $input_join, $field_id, Q($this->gettext('filteranyof')));
778
779        $field_id = '_any';
780        $input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'any',
781            'onclick' => 'rule_join_radio(\'any\')', 'class' => 'radio'));
782
783        $input_join = $input_join->show($any ? 'any' : '');
784
785        $out .= sprintf("%s<label for=\"%s\">%s</label>\n",
786            $input_join, $field_id, Q($this->gettext('filterany')));
787
788        $rows_num = isset($scr) ? sizeof($scr['tests']) : 1;
789
790        $out .= '<div id="rules"'.($any ? ' style="display: none"' : '').'>';
791        for ($x=0; $x<$rows_num; $x++)
792            $out .= $this->rule_div($fid, $x);
793        $out .= "</div>\n";
794
795        $out .= "</fieldset>\n";
796
797        // actions
798        $out .= '<fieldset><legend>' . Q($this->gettext('messagesactions')) . "</legend>\n";
799
800        $rows_num = isset($scr) ? sizeof($scr['actions']) : 1;
801
802        $out .= '<div id="actions">';
803        for ($x=0; $x<$rows_num; $x++)
804            $out .= $this->action_div($fid, $x);
805        $out .= "</div>\n";
806
807        $out .= "</fieldset>\n";
808
809        if ($scr['disabled']) {
810            $this->rc->output->set_env('rule_disabled', true);
811        }
812        $this->rc->output->add_label(
813            'managesieve.ruledeleteconfirm',
814            'managesieve.actiondeleteconfirm'
815        );
816        $this->rc->output->add_gui_object('sieveform', 'filterform');
817
818        return $out;
819    }
820
821    function rule_div($fid, $id, $div=true)
822    {
823        $rule     = isset($this->form) ? $this->form['tests'][$id] : $this->script[$fid]['tests'][$id];
824        $rows_num = isset($this->form) ? sizeof($this->form['tests']) : sizeof($this->script[$fid]['tests']);
825
826        $out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : '';
827
828        $out .= '<table><tr><td class="rowactions">';
829
830        // headers select
831        $select_header = new html_select(array('name' => "_header[]", 'id' => 'header'.$id,
832            'onchange' => 'header_select(' .$id .')'));
833        foreach($this->headers as $name => $val)
834            $select_header->add(Q($this->gettext($name)), Q($val));
835        $select_header->add(Q($this->gettext('size')), 'size');
836        $select_header->add(Q($this->gettext('...')), '...');
837
838        // TODO: list arguments
839
840        if ((isset($rule['test']) && $rule['test'] == 'header')
841            && !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers))
842            $out .= $select_header->show($rule['arg1']);
843        else if ((isset($rule['test']) && $rule['test'] == 'exists')
844            && !is_array($rule['arg']) && in_array($rule['arg'], $this->headers))
845            $out .= $select_header->show($rule['arg']);
846        else if (isset($rule['test']) && $rule['test'] == 'size')
847            $out .= $select_header->show('size');
848        else if (isset($rule['test']) && $rule['test'] != 'true')
849            $out .= $select_header->show('...');
850        else
851            $out .= $select_header->show();
852
853        $out .= '</td><td class="rowtargets">';
854
855        if ((isset($rule['test']) && $rule['test'] == 'header')
856            && (is_array($rule['arg1']) || !in_array($rule['arg1'], $this->headers)))
857            $custom = is_array($rule['arg1']) ? implode(', ', $rule['arg1']) : $rule['arg1'];
858        else if ((isset($rule['test']) && $rule['test'] == 'exists')
859            && (is_array($rule['arg']) || !in_array($rule['arg'], $this->headers)))
860            $custom = is_array($rule['arg']) ? implode(', ', $rule['arg']) : $rule['arg'];
861
862        $out .= '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '">
863            <input type="text" name="_custom_header[]" '. $this->error_class($id, 'test', 'header')
864            .' value="' .Q($custom). '" size="20" />&nbsp;</div>' . "\n";
865
866        // matching type select (operator)
867        $select_op = new html_select(array('name' => "_rule_op[]", 'id' => 'rule_op'.$id,
868            'style' => 'display:' .($rule['test']!='size' ? 'inline' : 'none'),
869            'onchange' => 'rule_op_select('.$id.')'));
870        $select_op->add(Q($this->gettext('filtercontains')), 'contains');
871        $select_op->add(Q($this->gettext('filternotcontains')), 'notcontains');
872        $select_op->add(Q($this->gettext('filteris')), 'is');
873        $select_op->add(Q($this->gettext('filterisnot')), 'notis');
874        $select_op->add(Q($this->gettext('filterexists')), 'exists');
875        $select_op->add(Q($this->gettext('filternotexists')), 'notexists');
876//      $select_op->add(Q($this->gettext('filtermatches')), 'matches');
877//      $select_op->add(Q($this->gettext('filternotmatches')), 'notmatches');
878
879        // target input (TODO: lists)
880
881        if ($rule['test'] == 'header') {
882            $out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['type']);
883            $target = $rule['arg2'];
884        }
885        else if ($rule['test'] == 'size') {
886            $out .= $select_op->show();
887            if(preg_match('/^([0-9]+)(K|M|G)*$/', $rule['arg'], $matches)) {
888                $sizetarget = $matches[1];
889                $sizeitem = $matches[2];
890            }
891        }
892        else {
893            $out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['test']);
894            $target = '';
895        }
896
897        $out .= '<input type="text" name="_rule_target[]" id="rule_target' .$id. '"
898            value="' .Q($target). '" size="20" ' . $this->error_class($id, 'test', 'target')
899            . ' style="display:' . ($rule['test']!='size' && $rule['test'] != 'exists' ? 'inline' : 'none') . '" />'."\n";
900
901        $select_size_op = new html_select(array('name' => "_rule_size_op[]", 'id' => 'rule_size_op'.$id));
902        $select_size_op->add(Q($this->gettext('filterunder')), 'under');
903        $select_size_op->add(Q($this->gettext('filterover')), 'over');
904
905        $out .= '<div id="rule_size' .$id. '" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">';
906        $out .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : '');
907        $out .= '<input type="text" name="_rule_size_target[]" value="'.$sizetarget.'" size="10" ' 
908            . $this->error_class($id, 'test', 'sizetarget') .' />
909            <input type="radio" name="_rule_size_item['.$id.']" value=""'. (!$sizeitem ? ' checked="checked"' : '') .' class="radio" />B
910            <input type="radio" name="_rule_size_item['.$id.']" value="K"'. ($sizeitem=='K' ? ' checked="checked"' : '') .' class="radio" />kB
911            <input type="radio" name="_rule_size_item['.$id.']" value="M"'. ($sizeitem=='M' ? ' checked="checked"' : '') .' class="radio" />MB
912            <input type="radio" name="_rule_size_item['.$id.']" value="G"'. ($sizeitem=='G' ? ' checked="checked"' : '') .' class="radio" />GB';
913        $out .= '</div>';
914        $out .= '</td>';
915
916        // add/del buttons
917        $out .= '<td class="rowbuttons">';
918        $out .= '<input type="button" id="ruleadd' . $id .'" value="'. Q($this->gettext('add')). '"
919            onclick="rcmail.managesieve_ruleadd(' . $id .')" class="button" /> ';
920        $out .= '<input type="button" id="ruledel' . $id .'" value="'. Q($this->gettext('del')). '"
921            onclick="rcmail.managesieve_ruledel(' . $id .')" class="button' . ($rows_num<2 ? ' disabled' : '') .'"'
922            . ($rows_num<2 ? ' disabled="disabled"' : '') .' />';
923        $out .= '</td></tr></table>';
924
925        $out .= $div ? "</div>\n" : '';
926
927        return $out;
928    }
929
930    function action_div($fid, $id, $div=true)
931    {
932        $action   = isset($this->form) ? $this->form['actions'][$id] : $this->script[$fid]['actions'][$id];
933        $rows_num = isset($this->form) ? sizeof($this->form['actions']) : sizeof($this->script[$fid]['actions']);
934
935        $out = $div ? '<div class="actionrow" id="actionrow' .$id .'">'."\n" : '';
936
937        $out .= '<table><tr><td class="rowactions">';
938
939        // action select
940        $select_action = new html_select(array('name' => "_action_type[]", 'id' => 'action_type'.$id,
941            'onchange' => 'action_type_select(' .$id .')'));
942        if (in_array('fileinto', $this->exts))
943            $select_action->add(Q($this->gettext('messagemoveto')), 'fileinto');
944        $select_action->add(Q($this->gettext('messageredirect')), 'redirect');
945        if (in_array('reject', $this->exts))
946            $select_action->add(Q($this->gettext('messagediscard')), 'reject');
947        else if (in_array('ereject', $this->exts))
948            $select_action->add(Q($this->gettext('messagediscard')), 'ereject');
949        if (in_array('vacation', $this->exts))
950            $select_action->add(Q($this->gettext('messagereply')), 'vacation');
951        $select_action->add(Q($this->gettext('messagedelete')), 'discard');
952        $select_action->add(Q($this->gettext('rulestop')), 'stop');
953
954        $out .= $select_action->show($action['type']);
955        $out .= '</td>';
956
957        // actions target inputs
958        $out .= '<td class="rowtargets">';
959        // shared targets
960        $out .= '<input type="text" name="_action_target[]" id="action_target' .$id. '" '
961            .'value="' .($action['type']=='redirect' ? Q($action['target'], 'strict', false) : ''). '" size="40" '
962            .'style="display:' .($action['type']=='redirect' ? 'inline' : 'none') .'" '
963            . $this->error_class($id, 'action', 'target') .' />';
964        $out .= '<textarea name="_action_target_area[]" id="action_target_area' .$id. '" '
965            .'rows="3" cols="40" '. $this->error_class($id, 'action', 'targetarea')
966            .'style="display:' .(in_array($action['type'], array('reject', 'ereject')) ? 'inline' : 'none') .'">'
967            . (in_array($action['type'], array('reject', 'ereject')) ? Q($action['target'], 'strict', false) : '')
968            . "</textarea>\n";
969
970        // vacation
971        $out .= '<div id="action_vacation' .$id.'" style="display:' .($action['type']=='vacation' ? 'inline' : 'none') .'">';
972        $out .= '<span class="label">'. Q($this->gettext('vacationreason')) .'</span><br />'
973            .'<textarea name="_action_reason[]" id="action_reason' .$id. '" '
974            .'rows="3" cols="40" '. $this->error_class($id, 'action', 'reason') . '>'
975            . Q($action['reason'], 'strict', false) . "</textarea>\n";
976        $out .= '<br /><span class="label">' .Q($this->gettext('vacationaddresses')) . '</span><br />'
977            .'<input type="text" name="_action_addresses[]" '
978            .'value="' . (is_array($action['addresses']) ? Q(implode(', ', $action['addresses']), 'strict', false) : $action['addresses']) . '" size="40" '
979            . $this->error_class($id, 'action', 'addresses') .' />';
980        $out .= '<br /><span class="label">' . Q($this->gettext('vacationdays')) . '</span><br />'
981            .'<input type="text" name="_action_days[]" '
982            .'value="' .Q($action['days'], 'strict', false) . '" size="2" '
983            . $this->error_class($id, 'action', 'days') .' />';
984        $out .= '</div>';
985
986        // mailbox select
987        $out .= '<select id="action_mailbox' .$id. '" name="_action_mailbox[]" style="display:'
988            .(!isset($action) || $action['type']=='fileinto' ? 'inline' : 'none'). '">';
989
990        $this->rc->imap_connect();
991
992        $a_folders = $this->rc->imap->list_mailboxes();
993        $delimiter = $this->rc->imap->get_hierarchy_delimiter();
994
995        // set mbox encoding
996        $mbox_encoding = $this->rc->config->get('managesieve_mbox_encoding', 'UTF7-IMAP');
997
998        if ($action['type'] == 'fileinto')
999            $mailbox = $action['target'];
1000        else
1001            $mailbox = '';
1002
1003        foreach ($a_folders as $folder) {
1004            $utf7folder = $this->rc->imap->mod_mailbox($folder);
1005            $names = explode($delimiter, rcube_charset_convert($folder, 'UTF7-IMAP'));
1006            $name  = $names[sizeof($names)-1];
1007
1008            if ($replace_delimiter = $this->rc->config->get('managesieve_replace_delimiter'))
1009                $utf7folder = str_replace($delimiter, $replace_delimiter, $utf7folder);
1010
1011            // convert to Sieve implementation encoding
1012            $utf7folder = $this->mbox_encode($utf7folder, $mbox_encoding);
1013
1014            if ($folder_class = rcmail_folder_classname($name))
1015                $foldername = $this->gettext($folder_class);
1016            else
1017                $foldername = $name;
1018
1019            $out .= sprintf('<option value="%s"%s>%s%s</option>'."\n",
1020                htmlspecialchars($utf7folder),
1021                ($mailbox == $utf7folder ? ' selected="selected"' : ''),
1022                str_repeat('&nbsp;', 4 * (sizeof($names)-1)),
1023                Q(abbreviate_string($foldername, 40 - (2 * sizeof($names)-1))));
1024        }
1025        $out .= '</select>';
1026        $out .= '</td>';
1027
1028        // add/del buttons
1029        $out .= '<td class="rowbuttons">';
1030        $out .= '<input type="button" id="actionadd' . $id .'" value="'. Q($this->gettext('add')). '"
1031            onclick="rcmail.managesieve_actionadd(' . $id .')" class="button" /> ';
1032        $out .= '<input type="button" id="actiondel' . $id .'" value="'. Q($this->gettext('del')). '"
1033            onclick="rcmail.managesieve_actiondel(' . $id .')" class="button' . ($rows_num<2 ? ' disabled' : '') .'"'
1034            . ($rows_num<2 ? ' disabled="disabled"' : '') .' />';
1035        $out .= '</td>';
1036
1037        $out .= '</tr></table>';
1038
1039        $out .= $div ? "</div>\n" : '';
1040
1041        return $out;
1042    }
1043
1044    private function genid()
1045    {
1046        $result = intval(rcube_timer());
1047        return $result;
1048    }
1049
1050    private function strip_value($str, $allow_html=false)
1051    {
1052        if (!$allow_html)
1053            $str = strip_tags($str);
1054
1055        return trim($str);
1056    }
1057
1058    private function error_class($id, $type, $target, $name_only=false)
1059    {
1060        // TODO: tooltips
1061        if ($type == 'test' && isset($this->errors['tests'][$id][$target]))
1062            return ($name_only ? 'error' : ' class="error"');
1063        else if ($type == 'action' && isset($this->errors['actions'][$id][$target]))
1064            return ($name_only ? 'error' : ' class="error"');
1065
1066        return '';
1067    }
1068
1069    private function mbox_encode($text, $encoding)
1070    {
1071        return rcube_charset_convert($text, 'UTF7-IMAP', $encoding);
1072    }
1073}
1074
1075?>
Note: See TracBrowser for help on using the repository browser.