From 47d8d39cf49310b688967f7571b0d66b5971b39c Mon Sep 17 00:00:00 2001 From: thomascube <thomas@roundcube.net> Date: Sun, 21 Feb 2010 11:44:39 -0500 Subject: [PATCH] Use rcmail::imap_connect() to establish IMAP connections; always initialize rcube_imap object in mail steps --- plugins/managesieve/managesieve.php | 342 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 256 insertions(+), 86 deletions(-) diff --git a/plugins/managesieve/managesieve.php b/plugins/managesieve/managesieve.php index d29ad34..219c334 100644 --- a/plugins/managesieve/managesieve.php +++ b/plugins/managesieve/managesieve.php @@ -7,36 +7,12 @@ * It's clickable interface which operates on text scripts and communicates * with server using managesieve protocol. Adds Filters tab in Settings. * - * @version 1.0 + * @version 2.2 * @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl> * - * Configuration (main.inc.php): - -// managesieve server port -$rcmail_config['managesieve_port'] = 2000; - -// managesieve server address -$rcmail_config['managesieve_host'] = 'localhost'; - -// use or not TLS for managesieve server connection -// it's because I've problems with TLS and dovecot's managesieve plugin -// and it's not needed on localhost -$rcmail_config['managesieve_usetls'] = false; - -// default contents of filters script (eg. default spam filter) -$rcmail_config['managesieve_default'] = '/etc/dovecot/sieve/global'; - -// I need this because my dovecot (with listescape plugin) uses -// ':' delimiter, but creates folders with dot delimiter -$rcmail_config['managesieve_replace_delimiter'] = ''; - -// disabled sieve extensions (body, copy, date, editheader, encoded-character, -// envelope, environment, ereject, fileinto, ihave, imap4flags, index, -// mailbox, mboxmetadata, regex, reject, relational, servermetadata, -// spamtest, spamtestplus, subaddress, vacation, variables, virustest, etc. -// Note: not all extensions are implemented -$rcmail_config['managesieve_disabled_extensions'] = array(); - + * Configuration (see config.inc.php.dist) + * + * $Id$ */ class managesieve extends rcube_plugin @@ -61,7 +37,7 @@ $this->add_texts('localization/', array('filters','managefilters')); // register actions - $this->register_action('plugin.managesieve', array($this, 'managesieve_init')); + $this->register_action('plugin.managesieve', array($this, 'managesieve_actions')); $this->register_action('plugin.managesieve-save', array($this, 'managesieve_save')); // include main js script @@ -73,39 +49,73 @@ $rcmail = rcmail::get_instance(); $this->rc = &$rcmail; + $this->load_config(); + // register UI objects $this->rc->output->add_handlers(array( 'filterslist' => array($this, 'filters_list'), + 'filtersetslist' => array($this, 'filtersets_list'), 'filterframe' => array($this, 'filter_frame'), 'filterform' => array($this, 'filter_form'), + 'filtersetform' => array($this, 'filterset_form'), )); require_once($this->home . '/lib/Net/Sieve.php'); require_once($this->home . '/lib/rcube_sieve.php'); + $host = str_replace('%h', $_SESSION['imap_host'], $this->rc->config->get('managesieve_host', 'localhost')); + $port = $this->rc->config->get('managesieve_port', 2000); + // try to connect to managesieve server and to fetch the script $this->sieve = new rcube_sieve($_SESSION['username'], $this->rc->decrypt($_SESSION['password']), - $this->rc->config->get('managesieve_host', 'localhost'), - $this->rc->config->get('managesieve_port', 2000), + $host, $port, $this->rc->config->get('managesieve_usetls', false), - $this->rc->config->get('managesieve_disabled_extensions')); + $this->rc->config->get('managesieve_disabled_extensions'), + $this->rc->config->get('managesieve_debug', false) + ); - $error = $this->sieve->error(); + if (!($error = $this->sieve->error())) { + + $list = $this->sieve->get_scripts(); + $active = $this->sieve->get_active(); + $_SESSION['managesieve_active'] = $active; + + if (!empty($_GET['_sid'])) { + $script_name = get_input_value('_sid', RCUBE_INPUT_GET); + } else if (!empty($_SESSION['managesieve_current'])) { + $script_name = $_SESSION['managesieve_current']; + } else { + // get active script + if ($active) { + $script_name = $active; + } else if ($list) { + $script_name = $list[0]; + // create a new (initial) script + } else { + // if script not exists build default script contents + $script_file = $this->rc->config->get('managesieve_default'); + $script_name = 'roundcube'; + if ($script_file && is_readable($script_file)) + $content = file_get_contents($script_file); - if ($error == SIEVE_ERROR_NOT_EXISTS) - { - // if script not exists build default script contents - $script_file = $this->rc->config->get('managesieve_default'); - if ($script_file && is_readable($script_file)) - $this->sieve->script->add_text(file_get_contents($script_file)); - // that's not exactly an error - $error = false; + // add script and set it active + if ($this->sieve->save_script($script_name, $content)) + if ($this->sieve->activate($script_name)) + $_SESSION['managesieve_active'] = $script_name; + } + } + + if ($script_name) + $this->sieve->load($script_name); + + $error = $this->sieve->error(); } - elseif ($error) + + // finally set script objects + if ($error) { - switch ($error) - { + switch ($error) { case SIEVE_ERROR_CONNECTION: case SIEVE_ERROR_LOGIN: $this->rc->output->show_message('managesieve.filterconnerror', 'error'); @@ -115,25 +125,24 @@ break; } + raise_error(array('code' => 403, 'type' => 'php', 'message' => "Unable to connect to managesieve on $host:$port"), true, false); + // to disable 'Add filter' button set env variable $this->rc->output->set_env('filterconnerror', true); - } - - // finally set script objects - if ($error) - { $this->script = array(); } else { $this->script = $this->sieve->script->as_array(); $this->exts = $this->sieve->get_extensions(); + $this->rc->output->set_env('active_set', $_SESSION['managesieve_active']); + $_SESSION['managesieve_current'] = $this->sieve->current; } return $error; } - function managesieve_init() + function managesieve_actions() { // Init plugin and handle managesieve connection $error = $this->managesieve_start(); @@ -158,7 +167,7 @@ $this->rc->output->show_message('managesieve.filtersaveerror', 'error'); } } - elseif ($action=='down' && !$error) + else if ($action=='down' && !$error) { if (isset($this->script[$fid]) && isset($this->script[$fid+1])) { @@ -166,27 +175,56 @@ && $this->sieve->script->update_rule($fid+1, $this->script[$fid]) !== false) $result = $this->sieve->save(); - if ($result) { + if ($result === true) { // $this->rc->output->show_message('managesieve.filtersaved', 'confirmation'); $this->rc->output->command('managesieve_updatelist', 'down', '', $fid); - } else + } else { $this->rc->output->show_message('managesieve.filtersaveerror', 'error'); - } + } + } } - elseif ($action=='delete' && !$error) + else if ($action=='delete' && !$error) { if (isset($this->script[$fid])) { if ($this->sieve->script->delete_rule($fid)) $result = $this->sieve->save(); - if (!$result) - $this->rc->output->show_message('managesieve.filterdeleteerror', 'error'); - else { + if ($result === true) { $this->rc->output->show_message('managesieve.filterdeleted', 'confirmation'); $this->rc->output->command('managesieve_updatelist', 'delete', '', $fid); + } else { + $this->rc->output->show_message('managesieve.filterdeleteerror', 'error'); } - } + } + } + else if ($action=='setact' && !$error) + { + $script_name = get_input_value('_set', RCUBE_INPUT_GPC); + $result = $this->sieve->activate($script_name); + + if ($result === true) { + $this->rc->output->set_env('active_set', $script_name); + $this->rc->output->show_message('managesieve.setactivated', 'confirmation'); + $this->rc->output->command('enable_command', 'plugin.managesieve-setact', false); + $this->rc->output->command('managesieve_reset', $script_name); + $_SESSION['managesieve_active'] = $script_name; + } else { + $this->rc->output->show_message('managesieve.setactivateerror', 'error'); + } + } + else if ($action=='setdel' && !$error) + { + $script_name = get_input_value('_set', RCUBE_INPUT_GPC); + $result = $this->sieve->remove($script_name); + + if ($result === true) { + $this->rc->output->show_message('managesieve.setdeleted', 'confirmation'); + $this->rc->output->command('managesieve_reload'); + rcube_sess_unset('managesieve_current'); + } else { + $this->rc->output->show_message('managesieve.setdeleteerror', 'error'); + } } elseif ($action=='ruleadd') { @@ -216,10 +254,31 @@ // Init plugin and handle managesieve connection $error = $this->managesieve_start(); - // add/edit action - if (isset($_POST['_name'])) + // filters set add action + if (!empty($_POST['_newset'])) { - $name = trim(get_input_value('_name', RCUBE_INPUT_POST)); + $name = get_input_value('_name', RCUBE_INPUT_GPC); + $copy = get_input_value('_copy', RCUBE_INPUT_GPC); + + if (!$name) + $error = 'managesieve.emptyname'; + else if (mb_strlen($name)>128) + $error = 'managesieve.nametoolong'; + else if (!$this->sieve->copy($name, $copy)) + $error = 'managesieve.setcreateerror'; + + if (!$error) { + $this->rc->output->show_message('managesieve.setcreated', 'confirmation'); + $this->rc->output->command('parent.managesieve_reload', $name); +// rcube_sess_unset('managesieve_current'); + } else { + $this->rc->output->show_message($error, 'error'); + } + } + // filter add/edit action + else if (isset($_POST['_name'])) + { + $name = trim(get_input_value('_name', RCUBE_INPUT_POST, true)); $fid = trim(get_input_value('_fid', RCUBE_INPUT_POST)); $join = trim(get_input_value('_join', RCUBE_INPUT_POST)); @@ -266,7 +325,7 @@ else foreach($headers as $idx => $header) { $header = $this->strip_value($header); - $target = $this->strip_value($targets[$idx]); + $target = $this->strip_value($targets[$idx], true); $op = $this->strip_value($ops[$idx]); // normal header @@ -308,7 +367,7 @@ $this->errors['tests'][$i]['sizetarget'] = $this->gettext('wrongformat'); break; case '...': - $cust_header = $this->strip_value($cust_headers[$idx]); + $cust_header = $headers = $this->strip_value($cust_headers[$idx]); if(preg_match('/^not/', $op)) $this->form['tests'][$i]['not'] = true; @@ -316,10 +375,22 @@ if ($cust_header == '') $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); - elseif (!preg_match('/^[a-z0-9-]+$/i', $cust_header)) - $this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars'); - - if ($type == 'exists') + else { + $headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY); + + if (!count($headers)) + $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); + else { + foreach ($headers as $hr) + if (!preg_match('/^[a-z0-9-]+$/i', $hr)) + $this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars'); + } + } + + if (empty($this->errors['tests'][$i]['header'])) + $cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers; + + if ($type == 'exists') { $this->form['tests'][$i]['test'] = 'exists'; $this->form['tests'][$i]['arg'] = $cust_header; @@ -416,9 +487,7 @@ { $this->rc->output->show_message('managesieve.filtersaved', 'confirmation'); $this->rc->output->add_script(sprintf("rcmail.managesieve_updatelist('%s', '%s', %d);", - isset($new) ? 'add' : 'update', $this->form['name'], $fid), 'foot'); -// $this->rc->output->command('managesieve_updatelist', isset($new) ? 'add' : 'update', $this->form['name'], $fid); -// $this->rc->output->send(); + isset($new) ? 'add' : 'update', Q($this->form['name']), $fid), 'foot'); } else { @@ -434,9 +503,12 @@ private function managesieve_send() { // Handle form action - if (isset($_GET['_framed']) || isset($_POST['_framed'])) - $this->rc->output->send('managesieve.managesieveedit'); - else { + if (isset($_GET['_framed']) || isset($_POST['_framed'])) { + if (isset($_GET['_newset']) || isset($_POST['_newset'])) + $this->rc->output->send('managesieve.setedit'); + else + $this->rc->output->send('managesieve.filteredit'); + } else { $this->rc->output->set_pagetitle($this->gettext('filters')); $this->rc->output->send('managesieve.managesieve'); } @@ -463,7 +535,36 @@ $this->rc->output->include_script('list.js'); // add some labels to client - $this->rc->output->add_label('managesieve.filterconfirmdelete'); + $this->rc->output->add_label('managesieve.filterdeleteconfirm'); + + return $out; + } + + // return the filters list as <SELECT> + function filtersets_list($attrib) + { + // add id to message list table if not specified + if (!strlen($attrib['id'])) + $attrib['id'] = 'rcmfiltersetslist'; + + $list = $this->sieve->get_scripts(); + $active = $this->sieve->get_active(); + + $select = new html_select(array('name' => '_set', 'id' => $attrib['id'], 'onchange' => 'rcmail.managesieve_set()')); + + if ($list) { + asort($list, SORT_LOCALE_STRING); + + foreach($list as $set) + $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set); + } + + $out = $select->show($this->sieve->current); + + // set client env + $this->rc->output->add_gui_object('filtersetslist', $attrib['id']); + $this->rc->output->add_label('managesieve.setdeleteconfirm'); + $this->rc->output->add_label('managesieve.active'); return $out; } @@ -477,9 +578,58 @@ $this->rc->output->set_env('contentframe', $attrib['name']); $this->rc->output->set_env('blankpage', $attrib['src'] ? - $this->rc->output->abs_url($attrib['src']) : 'program/blank.gif'); + $this->rc->output->abs_url($attrib['src']) : 'program/blank.gif'); return html::tag('iframe', $attrib); + } + + + function filterset_form($attrib) + { + if (!$attrib['id']) + $attrib['id'] = 'rcmfiltersetform'; + + $out = '<form name="filtersetform" action="./" method="post">'."\n"; + + $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task)); + $hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save')); + $hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0))); + $hiddenfields->add(array('name' => '_newset', 'value' => 1)); + + $out .= $hiddenfields->show(); + + $name = get_input_value('_name', RCUBE_INPUT_GPC); + $copy = get_input_value('_copy', RCUBE_INPUT_GPC); + + $table = new html_table(array('cols' => 2)); + + // filter set name input + $input_name = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30, + 'class' => ($this->errors['name'] ? 'error' : ''))); + + $table->add('title', sprintf('<label for="%s"><b>%s:</b></label>', '_name', Q($this->gettext('filtersetname')))); + $table->add(null, $input_name->show($name)); + + // filters set list + $list = $this->sieve->get_scripts(); + $active = $this->sieve->get_active(); + + $select = new html_select(array('name' => '_copy', 'id' => '_copy')); + + asort($list, SORT_LOCALE_STRING); + + $select->add($this->gettext('none'), ''); + foreach($list as $set) + $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set); + + $table->add('title', '<label>'.$this->gettext('copyfromset').':</label>'); + $table->add(null, $select->show($copy)); + + $out .= $table->show(); + + $this->rc->output->add_gui_object('sieveform', 'filtersetform'); + + return $out; } @@ -599,9 +749,11 @@ // TODO: list arguments - if ((isset($rule['test']) && $rule['test'] == 'header') && in_array($rule['arg1'], $this->headers)) + if ((isset($rule['test']) && $rule['test'] == 'header') + && !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers)) $out .= $select_header->show($rule['arg1']); - elseif ((isset($rule['test']) && $rule['test'] == 'exists') && in_array($rule['arg'], $this->headers)) + elseif ((isset($rule['test']) && $rule['test'] == 'exists') + && !is_array($rule['arg']) && in_array($rule['arg'], $this->headers)) $out .= $select_header->show($rule['arg']); elseif (isset($rule['test']) && $rule['test'] == 'size') $out .= $select_header->show('size'); @@ -612,10 +764,12 @@ $out .= '</td><td class="rowtargets">'; - if ((isset($rule['test']) && $rule['test'] == 'header') && !in_array($rule['arg1'], $this->headers)) - $custom = $rule['arg1']; - elseif ((isset($rule['test']) && $rule['test'] == 'exists') && !in_array($rule['arg'], $this->headers)) - $custom = $rule['arg']; + if ((isset($rule['test']) && $rule['test'] == 'header') + && (is_array($rule['arg1']) || !in_array($rule['arg1'], $this->headers))) + $custom = is_array($rule['arg1']) ? implode(', ', $rule['arg1']) : $rule['arg1']; + elseif ((isset($rule['test']) && $rule['test'] == 'exists') + && (is_array($rule['arg']) || !in_array($rule['arg'], $this->headers))) + $custom = is_array($rule['arg']) ? implode(', ', $rule['arg']) : $rule['arg']; $out .= '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '"> <input type="text" name="_custom_header[]" '. $this->error_class($id, 'test', 'header') @@ -747,10 +901,13 @@ $out .= '<select id="action_mailbox' .$id. '" name="_action_mailbox[]" style="display:' .(!isset($action) || $action['type']=='fileinto' ? 'inline' : 'none'). '">'; - $this->rc->imap_init(true); + $this->rc->imap_connect(); $a_folders = $this->rc->imap->list_mailboxes(); $delimiter = $this->rc->imap->get_hierarchy_delimiter(); + + // set mbox encoding + $mbox_encoding = $this->rc->config->get('managesieve_mbox_encoding', 'UTF7-IMAP'); if ($action['type'] == 'fileinto') $mailbox = $action['target']; @@ -759,12 +916,15 @@ foreach ($a_folders as $folder) { - $utf7folder = $folder; + $utf7folder = $this->rc->imap->mod_mailbox($folder); $names = explode($delimiter, rcube_charset_convert($folder, 'UTF7-IMAP')); $name = $names[sizeof($names)-1]; if ($replace_delimiter = $this->rc->config->get('managesieve_replace_delimiter')) $utf7folder = str_replace($delimiter, $replace_delimiter, $utf7folder); + + // convert to Sieve implementation encoding + $utf7folder = $this->mbox_encode($utf7folder, $mbox_encoding); if ($folder_class = rcmail_folder_classname($name)) $foldername = $this->gettext($folder_class); @@ -802,9 +962,12 @@ return $result; } - private function strip_value($str) + private function strip_value($str, $allow_html=false) { - return trim(strip_tags($str)); + if (!$allow_html) + $str = strip_tags($str); + + return trim($str); } private function error_class($id, $type, $target, $name_only=false) @@ -820,6 +983,9 @@ private function check_email($email) { + if (function_exists('check_email')); + return check_email($email); + // Check for invalid characters if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) return false; @@ -857,6 +1023,10 @@ return false; } + private function mbox_encode($text, $encoding) + { + return rcube_charset_convert($text, 'UTF7-IMAP', $encoding); + } } ?> -- Gitblit v1.9.1