Thomas Bruederli
2012-09-23 0c144b98a417d50b9c073ae3931fdad47390f1f7
Merge branch 'master' of github.com:roundcube/roundcubemail
4 files added
26 files modified
486 ■■■■ changed files
CHANGELOG 1 ●●●● patch | view | raw | blame | history
config/db.inc.php.dist 1 ●●●● patch | view | raw | blame | history
plugins/database_attachments/database_attachments.php 32 ●●●● patch | view | raw | blame | history
plugins/http_authentication/http_authentication.php 86 ●●●●● patch | view | raw | blame | history
plugins/http_authentication/package.xml 6 ●●●● patch | view | raw | blame | history
plugins/managesieve/Changelog 2 ●●●●● patch | view | raw | blame | history
plugins/managesieve/config.inc.php.dist 5 ●●●●● patch | view | raw | blame | history
plugins/managesieve/lib/rcube_sieve_script.php 96 ●●●●● patch | view | raw | blame | history
plugins/managesieve/localization/en_GB.inc 9 ●●●●● patch | view | raw | blame | history
plugins/managesieve/localization/en_US.inc 9 ●●●●● patch | view | raw | blame | history
plugins/managesieve/localization/pl_PL.inc 9 ●●●●● patch | view | raw | blame | history
plugins/managesieve/managesieve.js 6 ●●●● patch | view | raw | blame | history
plugins/managesieve/managesieve.php 79 ●●●●● patch | view | raw | blame | history
plugins/managesieve/package.xml 4 ●●●● patch | view | raw | blame | history
plugins/managesieve/tests/Parser.php 10 ●●●●● patch | view | raw | blame | history
plugins/managesieve/tests/src/parser_enotify_a 19 ●●●●● patch | view | raw | blame | history
plugins/managesieve/tests/src/parser_enotify_b 18 ●●●●● patch | view | raw | blame | history
plugins/managesieve/tests/src/parser_notify_a 18 ●●●●● patch | view | raw | blame | history
plugins/managesieve/tests/src/parser_notify_b 17 ●●●●● patch | view | raw | blame | history
program/include/html.php 23 ●●●●● patch | view | raw | blame | history
program/include/rcmail.php 2 ●●● patch | view | raw | blame | history
program/include/rcube_output_html.php 2 ●●● patch | view | raw | blame | history
program/include/rcube_utils.php 3 ●●●●● patch | view | raw | blame | history
program/js/app.js 6 ●●●● patch | view | raw | blame | history
program/steps/addressbook/edit.inc 7 ●●●●● patch | view | raw | blame | history
program/steps/addressbook/func.inc 5 ●●●●● patch | view | raw | blame | history
program/steps/addressbook/import.inc 2 ●●● patch | view | raw | blame | history
program/steps/settings/func.inc 2 ●●● patch | view | raw | blame | history
tests/Framework/Html.php 5 ●●●●● patch | view | raw | blame | history
tests/phpunit.xml 2 ●●● patch | view | raw | blame | history
CHANGELOG
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
- Fix HTML special characters handling in message list/header display (#1488523)
- List related text/html part as attachment in plain text mode (#1488677)
- Use IMAP BINARY (RFC3516) extension to fetch message/part bodies
- Fix folder creation under public namespace root (#1488665)
config/db.inc.php.dist
@@ -58,7 +58,6 @@
$rcmail_config['db_sequence_identities'] = 'identity_ids';
$rcmail_config['db_sequence_contacts'] = 'contact_ids';
$rcmail_config['db_sequence_contactgroups'] = 'contactgroups_ids';
$rcmail_config['db_sequence_cache'] = 'cache_ids';
$rcmail_config['db_sequence_searches'] = 'search_ids';
plugins/database_attachments/database_attachments.php
@@ -46,9 +46,9 @@
        $data = base64_encode($data);
        $status = $rcmail->db->query(
            "INSERT INTO ".get_table_name('cache')."
             (created, user_id, cache_key, data)
             VALUES (".$rcmail->db->now().", ?, ?, ?)",
            "INSERT INTO ".get_table_name('cache')
             ." (created, user_id, cache_key, data)"
             ." VALUES (".$rcmail->db->now().", ?, ?, ?)",
            $_SESSION['user_id'],
            $key,
            $data);
@@ -82,9 +82,9 @@
        $data = base64_encode($args['data']);
        $status = $rcmail->db->query(
            "INSERT INTO ".get_table_name('cache')."
             (created, user_id, cache_key, data)
             VALUES (".$rcmail->db->now().", ?, ?, ?)",
            "INSERT INTO ".get_table_name('cache')
             ." (created, user_id, cache_key, data)"
             ." VALUES (".$rcmail->db->now().", ?, ?, ?)",
            $_SESSION['user_id'],
            $key,
            $data);
@@ -106,9 +106,9 @@
        $args['status'] = false;
        $rcmail = rcmail::get_instance();
        $status = $rcmail->db->query(
            "DELETE FROM ".get_table_name('cache')."
             WHERE  user_id=?
             AND    cache_key=?",
            "DELETE FROM ".get_table_name('cache')
             ." WHERE user_id = ?"
                ." AND cache_key = ?",
            $_SESSION['user_id'],
            $args['id']);
@@ -138,10 +138,10 @@
        $rcmail = rcmail::get_instance();
        $sql_result = $rcmail->db->query(
            "SELECT cache_id, data
             FROM ".get_table_name('cache')."
             WHERE  user_id=?
             AND    cache_key=?",
            "SELECT data"
             ." FROM ".get_table_name('cache')
             ." WHERE user_id=?"
                ." AND cache_key=?",
            $_SESSION['user_id'],
            $args['id']);
@@ -161,9 +161,9 @@
        $prefix = $this->cache_prefix . $args['group'];
        $rcmail = rcmail::get_instance();
        $rcmail->db->query(
            "DELETE FROM ".get_table_name('cache')."
             WHERE  user_id=?
             AND cache_key like '{$prefix}%'",
            "DELETE FROM ".get_table_name('cache')
            ." WHERE user_id = ?"
                ." AND cache_key LIKE '{$prefix}%'",
            $_SESSION['user_id']);
    }
}
plugins/http_authentication/http_authentication.php
@@ -17,51 +17,67 @@
 */
class http_authentication extends rcube_plugin
{
  public $task = 'login|logout';
  function init()
  {
    $this->add_hook('startup', array($this, 'startup'));
    $this->add_hook('authenticate', array($this, 'authenticate'));
    $this->add_hook('logout_after', array($this, 'logout'));
  }
    function init()
    {
        $this->add_hook('startup', array($this, 'startup'));
        $this->add_hook('authenticate', array($this, 'authenticate'));
        $this->add_hook('logout_after', array($this, 'logout'));
    }
  function startup($args)
  {
    // change action to login
    if (empty($args['action']) && empty($_SESSION['user_id'])
        && !empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW']))
      $args['action'] = 'login';
    function startup($args)
    {
        if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
            $rcmail = rcmail::get_instance();
            $rcmail->add_shutdown_function(array('http_authentication', 'shutdown'));
    return $args;
  }
            // handle login action
            if (empty($args['action']) && empty($_SESSION['user_id'])) {
                $args['action'] = 'login';
            }
            // Set user password in session (see shutdown() method for more info)
            else if (!empty($_SESSION['user_id']) && empty($_SESION['password'])) {
                $_SESSION['password'] = $rcmail->encrypt($_SERVER['PHP_AUTH_PW']);
            }
        }
  function authenticate($args)
  {
    // Allow entering other user data in login form,
    // e.g. after log out (#1487953)
    if (!empty($args['user'])) {
        return $args;
    }
    if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
      $args['user'] = $_SERVER['PHP_AUTH_USER'];
      $args['pass'] = $_SERVER['PHP_AUTH_PW'];
    function authenticate($args)
    {
        // Allow entering other user data in login form,
        // e.g. after log out (#1487953)
        if (!empty($args['user'])) {
            return $args;
        }
        if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
            $args['user'] = $_SERVER['PHP_AUTH_USER'];
            $args['pass'] = $_SERVER['PHP_AUTH_PW'];
        }
        $args['cookiecheck'] = false;
        $args['valid'] = true;
        return $args;
    }
    $args['cookiecheck'] = false;
    $args['valid'] = true;
    return $args;
  }
  function logout($args)
  {
    // redirect to configured URL in order to clear HTTP auth credentials
    if (!empty($_SERVER['PHP_AUTH_USER']) && $args['user'] == $_SERVER['PHP_AUTH_USER'] && ($url = rcmail::get_instance()->config->get('logout_url'))) {
      header("Location: $url", true, 307);
    function logout($args)
    {
        // redirect to configured URL in order to clear HTTP auth credentials
        if (!empty($_SERVER['PHP_AUTH_USER']) && $args['user'] == $_SERVER['PHP_AUTH_USER']) {
            if ($url = rcmail::get_instance()->config->get('logout_url')) {
                header("Location: $url", true, 307);
            }
        }
    }
  }
    function shutdown()
    {
        // There's no need to store password (even if encrypted) in session
        // We'll set it back on startup (#1486553)
        rcmail::get_instance()->session->remove('password');
    }
}
plugins/http_authentication/package.xml
@@ -13,10 +13,10 @@
        <email>roundcube@gmail.com</email>
        <active>yes</active>
    </lead>
    <date>2011-11-21</date>
    <date>2012-09-18</date>
    <version>
        <release>1.4</release>
        <api>1.4</api>
        <release>1.5</release>
        <api>1.5</api>
    </version>
    <stability>
        <release>stable</release>
plugins/managesieve/Changelog
@@ -1,4 +1,6 @@
- Fixed issue with DBMail bug [http://pear.php.net/bugs/bug.php?id=19077] (#1488594)
- Added support for enotify/notify (RFC5435, RFC5436, draft-ietf-sieve-notify-00)
- Change default port to 4190 (IANA-allocated), add port auto-detection (#1488713)
* version 5.2 [2012-07-24]
-----------------------------------------------------------
plugins/managesieve/config.inc.php.dist
@@ -1,7 +1,8 @@
<?php
// managesieve server port
$rcmail_config['managesieve_port'] = 2000;
// managesieve server port. When empty the port will be determined automatically
// using getservbyname() function, with 4190 as a fallback.
$rcmail_config['managesieve_port'] = null;
// managesieve server address, default is localhost.
// Replacement variables supported in host name:
plugins/managesieve/lib/rcube_sieve_script.php
@@ -41,7 +41,9 @@
        'variables',                // RFC5229
        'body',                     // RFC5173
        'subaddress',               // RFC5233
        // @TODO: enotify/notify, spamtest+virustest, mailbox, date
        'enotify',                  // RFC5435
        'notify',                   // draft-ietf-sieve-notify-00
        // @TODO: spamtest+virustest, mailbox, date
    );
    /**
@@ -197,6 +199,9 @@
                }
            }
        }
        $imapflags = in_array('imap4flags', $this->supported) ? 'imap4flags' : 'imapflags';
        $notify    = in_array('enotify', $this->supported) ? 'enotify' : 'notify';
        // rules
        foreach ($this->content as $rule) {
@@ -370,11 +375,7 @@
                    case 'addflag':
                    case 'setflag':
                    case 'removeflag':
                        if (in_array('imap4flags', $this->supported))
                            array_push($exts, 'imap4flags');
                        else
                            array_push($exts, 'imapflags');
                        array_push($exts, $imapflags);
                        $action_script .= $action['type'].' '
                            . self::escape_string($action['target']);
                        break;
@@ -401,6 +402,46 @@
                            $action_script .= ":$opt ";
                        }
                        $action_script .= self::escape_string($action['name']) . ' ' . self::escape_string($action['value']);
                        break;
                    case 'notify':
                        array_push($exts, $notify);
                        $action_script .= 'notify';
                        // Here we support only 00 version of notify draft, there
                        // were a couple regressions in 00 to 04 changelog, we use
                        // the version used by Cyrus
                        if ($notify == 'notify') {
                            switch ($action['importance']) {
                                case 1: $action_script .= " :high"; break;
                                case 2: $action_script .= " :normal"; break;
                                case 3: $action_script .= " :low"; break;
                            }
                            unset($action['importance']);
                        }
                        foreach (array('from', 'importance', 'options', 'message') as $n_tag) {
                            if (!empty($action[$n_tag])) {
                                $action_script .= " :$n_tag " . self::escape_string($action[$n_tag]);
                            }
                        }
                        if (!empty($action['address'])) {
                            $method = 'mailto:' . $action['address'];
                            if (!empty($action['body'])) {
                                $method .= '?body=' . rawurlencode($action['body']);
                            }
                        }
                        else {
                            $method = $action['method'];
                        }
                        // method is optional in notify extension
                        if (!empty($method)) {
                            $action_script .= ($notify == 'notify' ? " :method " : " ") . self::escape_string($method);
                        }
                        break;
                    case 'vacation':
@@ -840,6 +881,49 @@
                // $result[] = array('type' => 'require', 'target' => $tokens);
                break;
            case 'notify':
                $notify = array('type' => 'notify');
                $priorities = array(':high' => 1, ':normal' => 2, ':low' => 3);
                // Parameters: :from, :importance, :options, :message
                //     additional (optional) :method parameter for notify extension
                for ($i=0, $len=count($tokens); $i<$len; $i++) {
                    $tok = strtolower($tokens[$i]);
                    if ($tok[0] == ':') {
                        // Here we support only 00 version of notify draft, there
                        // were a couple regressions in 00 to 04 changelog, we use
                        // the version used by Cyrus
                        if (isset($priorities[$tok])) {
                            $notify['importance'] = $priorities[$tok];
                        }
                        else {
                            $notify[substr($tok, 1)] = $tokens[++$i];
                        }
                    }
                    else {
                        // unnamed parameter is a :method in enotify extension
                        $notify['method'] = $tokens[$i];
                    }
                }
                $method_components = parse_url($notify['method']);
                if ($method_components['scheme'] == 'mailto') {
                    $notify['address'] = $method_components['path'];
                    $method_params = array();
                    if (array_key_exists('query', $method_components)) {
                        parse_str($method_components['query'], $method_params);
                    }
                    $method_params = array_change_key_case($method_params, CASE_LOWER);
                    // magic_quotes_gpc and magic_quotes_sybase affect the output of parse_str
                    if (ini_get('magic_quotes_gpc') || ini_get('magic_quotes_sybase')) {
                        array_map('stripslashes', $method_params);
                    }
                    $notify['body'] = (array_key_exists('body', $method_params)) ? $method_params['body'] : '';
                }
                $result[] = $notify;
                break;
            }
            if ($separator == $end)
plugins/managesieve/localization/en_GB.inc
@@ -97,6 +97,15 @@
$labels['setvarname'] = 'Variable name:';
$labels['setvarvalue'] = 'Variable value:';
$labels['setvarmodifiers'] = 'Modifiers:';
$labels['notify'] = 'Send notification';
$labels['notifyaddress'] = 'To e-mail address:';
$labels['notifybody'] = 'Notification body:';
$labels['notifysubject'] = 'Notification subject:';
$labels['notifyfrom'] = 'Notification sender:';
$labels['notifyimportance'] = 'Importance:';
$labels['notifyimportancelow'] = 'low';
$labels['notifyimportancenormal'] = 'normal';
$labels['notifyimportancehigh'] = 'high';
$labels['filtercreate'] = 'Create filter';
$labels['usedata'] = 'Use following data in the filter:';
$labels['nextstep'] = 'Next Step';
plugins/managesieve/localization/en_US.inc
@@ -88,6 +88,15 @@
$labels['varupperfirst'] = 'first character upper-case';
$labels['varquotewildcard'] = 'quote special characters';
$labels['varlength'] = 'length';
$labels['notify'] = 'Send notification';
$labels['notifyaddress'] = 'To e-mail address:';
$labels['notifybody'] = 'Notification body:';
$labels['notifysubject'] = 'Notification subject:';
$labels['notifyfrom'] = 'Notification sender:';
$labels['notifyimportance'] = 'Importance:';
$labels['notifyimportancelow'] = 'low';
$labels['notifyimportancenormal'] = 'normal';
$labels['notifyimportancehigh'] = 'high';
$labels['filtercreate'] = 'Create filter';
$labels['usedata'] = 'Use following data in the filter:';
$labels['nextstep'] = 'Next Step';
plugins/managesieve/localization/pl_PL.inc
@@ -103,6 +103,15 @@
$labels['varupperfirst'] = 'pierwsza litera duża (:upperfirst)';
$labels['varquotewildcard'] = 'anulowane znaki specjalne (:quotewildcard)';
$labels['varlength'] = 'dÅ‚ugość (:length)';
$labels['notify'] = 'WyÅ›lij powiadomienie';
$labels['notifyaddress'] = 'Na adres e-mail:';
$labels['notifybody'] = 'Treść powiadomienia:';
$labels['notifysubject'] = 'Temat powiadomienia:';
$labels['notifyfrom'] = 'Nadawca powiadomienia:';
$labels['notifyimportance'] = 'Priorytet:';
$labels['notifyimportancelow'] = 'niski';
$labels['notifyimportancenormal'] = 'normalny';
$labels['notifyimportancehigh'] = 'wysoki';
$labels['filtercreate'] = 'Utwórz filtr';
$labels['usedata'] = 'Użyj nastÄ™pujÄ…cych danych do utworzenia filtra:';
$labels['nextstep'] = 'NastÄ™pny krok';
plugins/managesieve/managesieve.js
@@ -639,7 +639,8 @@
      target_area: document.getElementById('action_target_area' + id),
      flags: document.getElementById('action_flags' + id),
      vacation: document.getElementById('action_vacation' + id),
      set: document.getElementById('action_set' + id)
      set: document.getElementById('action_set' + id),
      notify: document.getElementById('action_notify' + id)
    };
  if (obj.value == 'fileinto' || obj.value == 'fileinto_copy') {
@@ -660,6 +661,9 @@
  else if (obj.value == 'set') {
    enabled.set = 1;
  }
  else if (obj.value == 'notify') {
    enabled.notify = 1;
  }
  for (var x in elems) {
    elems[x].style.display = !enabled[x] ? 'none' : 'inline';
plugins/managesieve/managesieve.php
@@ -7,13 +7,13 @@
 * It's clickable interface which operates on text scripts and communicates
 * with server using managesieve protocol. Adds Filters tab in Settings.
 *
 * @version 5.0
 * @version @package_version@
 * @author Aleksander Machniak <alec@alec.pl>
 *
 * Configuration (see config.inc.php.dist)
 *
 * Copyright (C) 2008-2011, The Roundcube Dev Team
 * Copyright (C) 2011, Kolab Systems AG
 * Copyright (C) 2008-2012, The Roundcube Dev Team
 * Copyright (C) 2011-2012, Kolab Systems AG
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
@@ -62,8 +62,9 @@
        "x-beenthere",
    );
    const VERSION = '5.2';
    const VERSION  = '5.2';
    const PROGNAME = 'Roundcube (Managesieve)';
    const PORT     = 4190;
    function init()
@@ -200,9 +201,15 @@
        set_include_path($include_path);
        $host = rcube_parse_host($this->rc->config->get('managesieve_host', 'localhost'));
        $port = $this->rc->config->get('managesieve_port', 2000);
        $host = rcube_idn_to_ascii($host);
        $port = $this->rc->config->get('managesieve_port');
        if (empty($port)) {
            $port = getservbyname('sieve', 'tcp');
            if (empty($port)) {
                $port = self::PORT;
            }
        }
        $plugin = $this->rc->plugins->exec_hook('managesieve_connect', array(
            'user'      => $_SESSION['username'],
@@ -625,6 +632,11 @@
            $varnames       = get_input_value('_action_varname', RCUBE_INPUT_POST);
            $varvalues      = get_input_value('_action_varvalue', RCUBE_INPUT_POST);
            $varmods        = get_input_value('_action_varmods', RCUBE_INPUT_POST);
            $notifyaddrs    = get_input_value('_action_notifyaddress', RCUBE_INPUT_POST);
            $notifybodies   = get_input_value('_action_notifybody', RCUBE_INPUT_POST);
            $notifymessages = get_input_value('_action_notifymessage', RCUBE_INPUT_POST);
            $notifyfrom     = get_input_value('_action_notifyfrom', RCUBE_INPUT_POST);
            $notifyimp      = get_input_value('_action_notifyimportance', RCUBE_INPUT_POST);
            // we need a "hack" for radiobuttons
            foreach ($sizeitems as $item)
@@ -877,6 +889,23 @@
                    if (!isset($varvalues[$idx]) || $varvalues[$idx] === '') {
                        $this->errors['actions'][$i]['value'] = $this->gettext('cannotbeempty');
                    }
                    break;
                case 'notify':
                    if (empty($notifyaddrs[$idx])) {
                        $this->errors['actions'][$i]['address'] = $this->gettext('cannotbeempty');
                    }
                    else if (!check_email($notifyaddrs[$idx])) {
                        $this->errors['actions'][$i]['address'] = $this->gettext('noemailwarning');
                    }
                    if (!empty($notifyfrom[$idx]) && !check_email($notifyfrom[$idx])) {
                        $this->errors['actions'][$i]['from'] = $this->gettext('noemailwarning');
                    }
                    $this->form['actions'][$i]['address'] = $notifyaddrs[$idx];
                    $this->form['actions'][$i]['body'] = $notifybodies[$idx];
                    $this->form['actions'][$i]['message'] = $notifymessages[$idx];
                    $this->form['actions'][$i]['from'] = $notifyfrom[$idx];
                    $this->form['actions'][$i]['importance'] = $notifyimp[$idx];
                    break;
                }
@@ -1479,6 +1508,9 @@
        if (in_array('variables', $this->exts)) {
            $select_action->add(Q($this->gettext('setvariable')), 'set');
        }
        if (in_array('enotify', $this->exts) || in_array('notify', $this->exts)) {
            $select_action->add(Q($this->gettext('notify')), 'notify');
        }
        $select_action->add(Q($this->gettext('rulestop')), 'stop');
        $select_type = $action['type'];
@@ -1571,6 +1603,41 @@
        }
        $out .= '</div>';
        // notify
        // skip :options tag - not used by the mailto method
        $out .= '<div id="action_notify' .$id.'" style="display:' .($action['type']=='notify' ? 'inline' : 'none') .'">';
        $out .= '<span class="label">' .Q($this->gettext('notifyaddress')) . '</span><br />'
            .'<input type="text" name="_action_notifyaddress['.$id.']" id="action_notifyaddress'.$id.'" '
            .'value="' . Q($action['address']) . '" size="35" '
            . $this->error_class($id, 'action', 'address', 'action_notifyaddress') .' />';
        $out .= '<br /><span class="label">'. Q($this->gettext('notifybody')) .'</span><br />'
            .'<textarea name="_action_notifybody['.$id.']" id="action_notifybody' .$id. '" '
            .'rows="3" cols="35" '. $this->error_class($id, 'action', 'method', 'action_notifybody') . '>'
            . Q($action['body'], 'strict', false) . "</textarea>\n";
        $out .= '<br /><span class="label">' .Q($this->gettext('notifysubject')) . '</span><br />'
            .'<input type="text" name="_action_notifymessage['.$id.']" id="action_notifymessage'.$id.'" '
            .'value="' . Q($action['message']) . '" size="35" '
            . $this->error_class($id, 'action', 'message', 'action_notifymessage') .' />';
        $out .= '<br /><span class="label">' .Q($this->gettext('notifyfrom')) . '</span><br />'
            .'<input type="text" name="_action_notifyfrom['.$id.']" id="action_notifyfrom'.$id.'" '
            .'value="' . Q($action['from']) . '" size="35" '
            . $this->error_class($id, 'action', 'from', 'action_notifyfrom') .' />';
        $importance_options = array(
            3 => 'notifyimportancelow',
            2 => 'notifyimportancenormal',
            1 => 'notifyimportancehigh'
        );
        $select_importance = new html_select(array(
            'name' => '_action_notifyimportance[' . $id . ']',
            'id' => '_action_notifyimportance' . $id,
            'class' => $this->error_class($id, 'action', 'importance', 'action_notifyimportance')));
        foreach ($importance_options as $io_v => $io_n) {
            $select_importance->add(Q($this->gettext($io_n)), $io_v);
        }
        $out .= '<br /><span class="label">' . Q($this->gettext('notifyimportance')) . '</span><br />';
        $out .= $select_importance->show($action['importance'] ? $action['importance'] : 2);
        $out .= '</div>';
        // mailbox select
        if ($action['type'] == 'fileinto')
            $mailbox = $this->mod_mailbox($action['target'], 'out');
plugins/managesieve/package.xml
@@ -17,9 +17,9 @@
        <email>alec@alec.pl</email>
        <active>yes</active>
    </lead>
    <date>2012-06-21</date>
    <date>2012-07-24</date>
    <version>
        <release>5.1</release>
        <release>5.2</release>
        <api>5.0</api>
    </version>
    <stability>
plugins/managesieve/tests/Parser.php
@@ -15,7 +15,15 @@
     */
    function test_parser($input, $output, $message)
    {
        $script = new rcube_sieve_script($input);
        // get capabilities list from the script
        $caps = array();
        if (preg_match('/require \[([a-z0-9", ]+)\]/', $input, $m)) {
            foreach (explode(',', $m[1]) as $cap) {
                $caps[] = trim($cap, '" ');
            }
        }
        $script = new rcube_sieve_script($input, $caps);
        $result = $script->as_text();
        $this->assertEquals(trim($result), trim($output), $message);
plugins/managesieve/tests/src/parser_enotify_a
New file
@@ -0,0 +1,19 @@
require ["enotify","variables"];
# rule:[notify1]
if header :contains "from" "boss@example.org"
{
    notify :importance "1" :message "This is probably very important" "mailto:alm@example.com";
    stop;
}
# rule:[subject]
if header :matches "Subject" "*"
{
    set "subject" "${1}";
}
# rule:[from notify2]
if header :matches "From" "*"
{
    set "from" "${1}";
    notify :importance "3" :message "${from}: ${subject}" "mailto:alm@example.com";
}
plugins/managesieve/tests/src/parser_enotify_b
New file
@@ -0,0 +1,18 @@
require ["envelope","variables","enotify"];
# rule:[from]
if envelope :all :matches "from" "*"
{
    set "env_from" " [really: ${1}]";
}
# rule:[subject]
if header :matches "Subject" "*"
{
    set "subject" "${1}";
}
# rule:[from notify]
if address :all :matches "from" "*"
{
    set "from_addr" "${1}";
    notify :message "${from_addr}${env_from}: ${subject}" "mailto:alm@example.com";
}
plugins/managesieve/tests/src/parser_notify_a
New file
@@ -0,0 +1,18 @@
require ["notify","variables"];
# rule:[notify1]
if header :contains "from" "boss@example.org"
{
    notify :low :message "This is probably very important";
    stop;
}
# rule:[subject]
if header :matches "Subject" "*"
{
    set "subject" "${1}";
}
# rule:[from notify2]
if header :matches "From" "*"
{
    set "from" "${1}";
    notify :high :message "${from}: ${subject}" :method "mailto:test@example.org";
}
plugins/managesieve/tests/src/parser_notify_b
New file
@@ -0,0 +1,17 @@
require ["envelope","variables","notify"];
# rule:[from]
if envelope :all :matches "from" "*"
{
    set "env_from" " [really: ${1}]";
}
# rule:[subject]
if header :matches "Subject" "*"
{
    set "subject" "${1}";
}
# rule:[from notify]
if address :all :matches "from" "*"
{
    set "from_addr" "${1}";
    notify :message "${from_addr}${env_from}: ${subject}" :method "sms:1234567890";
}
program/include/html.php
@@ -295,7 +295,7 @@
                }
            }
            else {
                $attrib_arr[] = $key . '="' . self::quote($value, true) . '"';
                $attrib_arr[] = $key . '="' . self::quote($value) . '"';
            }
        }
@@ -328,22 +328,13 @@
    /**
     * Replacing specials characters in html attribute value
     *
     * @param  string  $str       Input string
     * @param  bool    $validate  Enables double quotation prevention
     * @param string $str Input string
     *
     * @return string  The quoted string
     * @return string The quoted string
     */
    public static function quote($str, $validate = false)
    public static function quote($str)
    {
        $str = htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
        // avoid douple quotation of &
        // @TODO: get rid of it
        if ($validate) {
            $str = preg_replace('/&amp;([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $str);
        }
        return $str;
        return htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
    }
}
@@ -559,7 +550,7 @@
        }
        if (!empty($value) && empty($this->attrib['is_escaped'])) {
            $value = self::quote($value, true);
            $value = self::quote($value);
        }
        return self::tag($this->tagname, $this->attrib, $value,
@@ -635,7 +626,7 @@
            $option_content = $option['text'];
            if (empty($this->attrib['is_escaped'])) {
                $option_content = self::quote($option_content, true);
                $option_content = self::quote($option_content);
            }
            $this->content .= self::tag('option', $attr, $option_content);
program/include/rcmail.php
@@ -281,7 +281,7 @@
        }
        $list[$id] = array(
          'id'       => $id,
          'name'     => $prop['name'],
          'name'     => html::quote($prop['name']),
          'groups'   => is_array($prop['groups']),
          'readonly' => !$prop['writable'],
          'hidden'   => $prop['hidden'],
program/include/rcube_output_html.php
@@ -527,7 +527,7 @@
    {
        $GLOBALS['__version']   = html::quote(RCMAIL_VERSION);
        $GLOBALS['__comm_path'] = html::quote($this->app->comm_path);
        $GLOBALS['__skin_path'] = Q($this->config->get('skin_path'));
        $GLOBALS['__skin_path'] = html::quote($this->config->get('skin_path'));
        return preg_replace_callback('/\$(__[a-z0-9_\-]+)/',
            array($this, 'globals_callback'), $input);
program/include/rcube_utils.php
@@ -250,9 +250,6 @@
            $out = strtr($str, $encode_arr);
            // avoid douple quotation of &
            $out = preg_replace('/&amp;([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $out);
            return $newlines ? nl2br($out) : $out;
        }
program/js/app.js
@@ -208,7 +208,7 @@
          this.gui_objects.messagelist.parentNode.onmousedown = function(e){ return p.click_on_list(e); };
          this.message_list.init();
          this.enable_command('toggle_status', 'toggle_flag', 'menu-open', 'menu-save', true);
          this.enable_command('toggle_status', 'toggle_flag', 'menu-open', 'menu-save', 'sort', true);
          // load messages
          this.command('list');
@@ -6114,7 +6114,7 @@
              this.show_contentframe(false);
            // disable commands useless when mailbox is empty
            this.enable_command(this.env.message_commands, 'purge', 'expunge',
              'select-all', 'select-none', 'sort', 'expand-all', 'expand-unread', 'collapse-all', false);
              'select-all', 'select-none', 'expand-all', 'expand-unread', 'collapse-all', false);
          }
          if (this.message_list)
            this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:this.message_list.rowcount });
@@ -6127,7 +6127,7 @@
        this.env.qsearch = null;
      case 'list':
        if (this.task == 'mail') {
          this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0));
          this.enable_command('show', 'expunge', 'select-all', 'select-none', (this.env.messagecount > 0));
          this.enable_command('purge', this.purge_mailbox_test());
          this.enable_command('expand-all', 'expand-unread', 'collapse-all', this.env.threading && this.env.messagecount);
program/steps/addressbook/edit.inc
@@ -244,11 +244,12 @@
    if (count($sources_list) < 2) {
        $source = $sources_list[$SOURCE_ID];
        $hiddenfield = new html_hiddenfield(array('name' => '_source', 'value' => $SOURCE_ID));
        return html::span($attrib, Q($source['name']) . $hiddenfield->show());
        return html::span($attrib, $source['name'] . $hiddenfield->show());
    }
    $attrib['name'] = '_source';
    $attrib['onchange'] = JS_OBJECT_NAME . ".command('save', 'reload', this.form)";
    $attrib['name']       = '_source';
    $attrib['is_escaped'] = true;
    $attrib['onchange']   = JS_OBJECT_NAME . ".command('save', 'reload', this.form)";
    $select = new html_select($attrib);
program/steps/addressbook/func.inc
@@ -178,7 +178,7 @@
        if (!$name && $source == 0) {
            $name = rcube_label('personaladrbook');
        }
        $OUTPUT->set_env('sourcename', $name);
        $OUTPUT->set_env('sourcename', html_entity_decode($name, ENT_COMPAT, 'UTF-8'));
    }
}
@@ -219,12 +219,13 @@
        if ($source['class_name'])
            $class_name .= ' ' . $source['class_name'];
        $name = !empty($source['name']) ? $source['name'] : $id;
        $out .= sprintf($line_templ,
            html_identifier($id),
            $class_name,
            Q(rcmail_url(null, array('_source' => $id))),
            $source['id'],
            $js_id, (!empty($source['name']) ? Q($source['name']) : Q($id)));
            $js_id, $name);
        $groupdata = array('out' => $out, 'jsdata' => $jsdata, 'source' => $id);
        if ($source['groups'])
program/steps/addressbook/import.inc
@@ -43,7 +43,7 @@
  // addressbook selector
  if (count($writable_books) > 1) {
    $select = new html_select(array('name' => '_target', 'id' => 'rcmimporttarget'));
    $select = new html_select(array('name' => '_target', 'id' => 'rcmimporttarget', 'is_escaped' => true));
    foreach ($writable_books as $book)
        $select->add($book['name'], $book['id']);
program/steps/settings/func.inc
@@ -667,7 +667,7 @@
      $select_abook = new html_select(array('name' => '_default_addressbook', 'id' => $field_id));
      foreach ($books as $book) {
        $select_abook->add($book['name'], $book['id']);
        $select_abook->add(html_entity_decode($book['name'], ENT_COMPAT, 'UTF-8'), $book['id']);
      }
      $blocks['main']['options']['default_addressbook'] = array(
tests/Framework/Html.php
@@ -31,7 +31,6 @@
            array('>', '&gt;'),
            array('&', '&amp;'),
            array('&amp;', '&amp;amp;'),
            array('&amp;', '&amp;', true),
        );
    }
@@ -39,8 +38,8 @@
     * Test for quote()
     * @dataProvider data_quote
     */
    function test_quote($str, $result, $validate = false)
    function test_quote($str, $result)
    {
        $this->assertEquals(html::quote($str, $validate), $result);
        $this->assertEquals(html::quote($str), $result);
    }
}
tests/phpunit.xml
@@ -29,7 +29,7 @@
            <file>HtmlToText.php</file>
            <file>MailFunc.php</file>
        </testsuite>
        <testsuite name="managesieve">
        <testsuite name="Managesieve Tests">
            <file>./../plugins/managesieve/tests/Parser.php</file>
            <file>./../plugins/managesieve/tests/Tokenizer.php</file>
        </testsuite>