diff options
41 files changed, 5863 insertions, 5624 deletions
@@ -32,6 +32,7 @@ | | +-------------------------------------------------------------------------+ | Author: Thomas Bruederli <roundcube@gmail.com> | + | Author: Aleksander Machniak <alec@alec.pl> | +-------------------------------------------------------------------------+ */ @@ -49,34 +50,36 @@ ob_start(); // check if config files had errors if ($err_str = $RCMAIL->config->get_error()) { - rcmail::raise_error(array( - 'code' => 601, - 'type' => 'php', - 'message' => $err_str), false, true); + rcmail::raise_error(array( + 'code' => 601, + 'type' => 'php', + 'message' => $err_str), false, true); } // check DB connections and exit on failure if ($err_str = $RCMAIL->db->is_error()) { - rcmail::raise_error(array( - 'code' => 603, - 'type' => 'db', - 'message' => $err_str), FALSE, TRUE); + rcmail::raise_error(array( + 'code' => 603, + 'type' => 'db', + 'message' => $err_str), FALSE, TRUE); } // error steps if ($RCMAIL->action == 'error' && !empty($_GET['_code'])) { - rcmail::raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE); + rcmail::raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE); } // check if https is required (for login) and redirect if necessary if (empty($_SESSION['user_id']) && ($force_https = $RCMAIL->config->get('force_https', false))) { - $https_port = is_bool($force_https) ? 443 : $force_https; - if (!rcube_utils::https_check($https_port)) { - $host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']); - $host .= ($https_port != 443 ? ':' . $https_port : ''); - header('Location: https://' . $host . $_SERVER['REQUEST_URI']); - exit; - } + $https_port = is_bool($force_https) ? 443 : $force_https; + + if (!rcube_utils::https_check($https_port)) { + $host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']); + $host .= ($https_port != 443 ? ':' . $https_port : ''); + + header('Location: https://' . $host . $_SERVER['REQUEST_URI']); + exit; + } } // trigger startup plugin hook @@ -86,165 +89,176 @@ $RCMAIL->action = $startup['action']; // try to log in if ($RCMAIL->task == 'login' && $RCMAIL->action == 'login') { - $request_valid = $_SESSION['temp'] && $RCMAIL->check_request(rcube_utils::INPUT_POST, 'login'); - - // purge the session in case of new login when a session already exists - $RCMAIL->kill_session(); - - $auth = $RCMAIL->plugins->exec_hook('authenticate', array( - 'host' => $RCMAIL->autoselect_host(), - 'user' => trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST)), - 'pass' => rcube_utils::get_input_value('_pass', rcube_utils::INPUT_POST, true, - $RCMAIL->config->get('password_charset', 'ISO-8859-1')), - 'cookiecheck' => true, - 'valid' => $request_valid, - )); - - // Login - if ($auth['valid'] && !$auth['abort'] && - $RCMAIL->login($auth['user'], $auth['pass'], $auth['host'], $auth['cookiecheck']) - ) { - // create new session ID, don't destroy the current session - // it was destroyed already by $RCMAIL->kill_session() above - $RCMAIL->session->remove('temp'); - $RCMAIL->session->regenerate_id(false); - - // send auth cookie if necessary - $RCMAIL->session->set_auth_cookie(); - - // log successful login - $RCMAIL->log_login(); - - // restore original request parameters - $query = array(); - if ($url = rcube_utils::get_input_value('_url', rcube_utils::INPUT_POST)) { - parse_str($url, $query); - - // prevent endless looping on login page - if ($query['_task'] == 'login') - unset($query['_task']); - - // prevent redirect to compose with specified ID (#1488226) - if ($query['_action'] == 'compose' && !empty($query['_id'])) - $query = array(); - } + $request_valid = $_SESSION['temp'] && $RCMAIL->check_request(rcube_utils::INPUT_POST, 'login'); - // allow plugins to control the redirect url after login success - $redir = $RCMAIL->plugins->exec_hook('login_after', $query + array('_task' => 'mail')); - unset($redir['abort'], $redir['_err']); + // purge the session in case of new login when a session already exists + $RCMAIL->kill_session(); - // send redirect - $OUTPUT->redirect($redir); - } - else { - if (!$auth['valid']) { - $error_code = RCMAIL::ERROR_INVALID_REQUEST; + $auth = $RCMAIL->plugins->exec_hook('authenticate', array( + 'host' => $RCMAIL->autoselect_host(), + 'user' => trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST)), + 'pass' => rcube_utils::get_input_value('_pass', rcube_utils::INPUT_POST, true, + $RCMAIL->config->get('password_charset', 'ISO-8859-1')), + 'cookiecheck' => true, + 'valid' => $request_valid, + )); + + // Login + if ($auth['valid'] && !$auth['abort'] + && $RCMAIL->login($auth['user'], $auth['pass'], $auth['host'], $auth['cookiecheck']) + ) { + // create new session ID, don't destroy the current session + // it was destroyed already by $RCMAIL->kill_session() above + $RCMAIL->session->remove('temp'); + $RCMAIL->session->regenerate_id(false); + + // send auth cookie if necessary + $RCMAIL->session->set_auth_cookie(); + + // log successful login + $RCMAIL->log_login(); + + // restore original request parameters + $query = array(); + if ($url = rcube_utils::get_input_value('_url', rcube_utils::INPUT_POST)) { + parse_str($url, $query); + + // prevent endless looping on login page + if ($query['_task'] == 'login') { + unset($query['_task']); + } + + // prevent redirect to compose with specified ID (#1488226) + if ($query['_action'] == 'compose' && !empty($query['_id'])) { + $query = array(); + } + } + + // allow plugins to control the redirect url after login success + $redir = $RCMAIL->plugins->exec_hook('login_after', $query + array('_task' => 'mail')); + unset($redir['abort'], $redir['_err']); + + // send redirect + $OUTPUT->redirect($redir); } else { - $error_code = $auth['error'] ? $auth['error'] : $RCMAIL->login_error(); - } + if (!$auth['valid']) { + $error_code = RCMAIL::ERROR_INVALID_REQUEST; + } + else { + $error_code = $auth['error'] ? $auth['error'] : $RCMAIL->login_error(); + } - $error_labels = array( - RCMAIL::ERROR_STORAGE => 'storageerror', - RCMAIL::ERROR_COOKIES_DISABLED => 'cookiesdisabled', - RCMAIL::ERROR_INVALID_REQUEST => 'invalidrequest', - RCMAIL::ERROR_INVALID_HOST => 'invalidhost', - ); + $error_labels = array( + RCMAIL::ERROR_STORAGE => 'storageerror', + RCMAIL::ERROR_COOKIES_DISABLED => 'cookiesdisabled', + RCMAIL::ERROR_INVALID_REQUEST => 'invalidrequest', + RCMAIL::ERROR_INVALID_HOST => 'invalidhost', + ); - $error_message = $error_labels[$error_code] ? $error_labels[$error_code] : 'loginfailed'; + $error_message = $error_labels[$error_code] ? $error_labels[$error_code] : 'loginfailed'; - // log failed login - $RCMAIL->log_login($auth['user'], true, $error_code); + $OUTPUT->show_message($error_message, 'warning'); - $OUTPUT->show_message($error_message, 'warning'); - $RCMAIL->plugins->exec_hook('login_failed', array( - 'code' => $error_code, 'host' => $auth['host'], 'user' => $auth['user'])); - $RCMAIL->kill_session(); - } + // log failed login + $RCMAIL->log_login($auth['user'], true, $error_code); + + $RCMAIL->plugins->exec_hook('login_failed', array( + 'code' => $error_code, 'host' => $auth['host'], 'user' => $auth['user'])); + + $RCMAIL->kill_session(); + } } // end session (after optional referer check) -else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id']) && (!$RCMAIL->config->get('referer_check') || rcube_utils::check_referer())) { - $userdata = array( - 'user' => $_SESSION['username'], - 'host' => $_SESSION['storage_host'], - 'lang' => $RCMAIL->user->language, - ); - $OUTPUT->show_message('loggedout'); - $RCMAIL->logout_actions(); - $RCMAIL->kill_session(); - $RCMAIL->plugins->exec_hook('logout_after', $userdata); +else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id']) + && (!$RCMAIL->config->get('referer_check') || rcube_utils::check_referer()) +) { + $userdata = array( + 'user' => $_SESSION['username'], + 'host' => $_SESSION['storage_host'], + 'lang' => $RCMAIL->user->language, + ); + + $OUTPUT->show_message('loggedout'); + + $RCMAIL->logout_actions(); + $RCMAIL->kill_session(); + $RCMAIL->plugins->exec_hook('logout_after', $userdata); } // check session and auth cookie else if ($RCMAIL->task != 'login' && $_SESSION['user_id'] && $RCMAIL->action != 'send') { - if (!$RCMAIL->session->check_auth()) { - $RCMAIL->kill_session(); - $session_error = true; - } + if (!$RCMAIL->session->check_auth()) { + $RCMAIL->kill_session(); + $session_error = true; + } } // not logged in -> show login page if (empty($RCMAIL->user->ID)) { - // log session failures - $task = rcube_utils::get_input_value('_task', rcube_utils::INPUT_GPC); - if ($task && !in_array($task, array('login','logout')) && !$session_error && ($sess_id = $_COOKIE[ini_get('session.name')])) { - $RCMAIL->session->log("Aborted session " . $sess_id . "; no valid session data found"); - $session_error = true; - } - - // check if installer is still active - if ($RCMAIL->config->get('enable_installer') && is_readable('./installer/index.php')) { - $OUTPUT->add_footer(html::div(array('style' => "background:#ef9398; border:2px solid #dc5757; padding:0.5em; margin:2em auto; width:50em"), - html::tag('h2', array('style' => "margin-top:0.2em"), "Installer script is still accessible") . - html::p(null, "The install script of your Roundcube installation is still stored in its default location!") . - html::p(null, "Please <b>remove</b> the whole <tt>installer</tt> folder from the Roundcube directory because . - these files may expose sensitive configuration data like server passwords and encryption keys - to the public. Make sure you cannot access the <a href=\"./installer/\">installer script</a> from your browser.") - ) - ); - } + // log session failures + $task = rcube_utils::get_input_value('_task', rcube_utils::INPUT_GPC); + + if ($task && !in_array($task, array('login','logout')) + && !$session_error && ($sess_id = $_COOKIE[ini_get('session.name')]) + ) { + $RCMAIL->session->log("Aborted session $sess_id; no valid session data found"); + $session_error = true; + } + + // check if installer is still active + if ($RCMAIL->config->get('enable_installer') && is_readable('./installer/index.php')) { + $OUTPUT->add_footer(html::div(array('style' => "background:#ef9398; border:2px solid #dc5757; padding:0.5em; margin:2em auto; width:50em"), + html::tag('h2', array('style' => "margin-top:0.2em"), "Installer script is still accessible") . + html::p(null, "The install script of your Roundcube installation is still stored in its default location!") . + html::p(null, "Please <b>remove</b> the whole <tt>installer</tt> folder from the Roundcube directory because . + these files may expose sensitive configuration data like server passwords and encryption keys + to the public. Make sure you cannot access the <a href=\"./installer/\">installer script</a> from your browser.") + )); + } + + if ($session_error || $_REQUEST['_err'] == 'session') { + $OUTPUT->show_message('sessionerror', 'error', null, true, -1); + } - if ($session_error || $_REQUEST['_err'] == 'session') { - $OUTPUT->show_message('sessionerror', 'error', null, true, -1); - } + if ($OUTPUT->ajax_call || !empty($_REQUEST['_framed'])) { + $OUTPUT->command('session_error', $RCMAIL->url(array('_err' => 'session'))); + $OUTPUT->send('iframe'); + } - if ($OUTPUT->ajax_call || !empty($_REQUEST['_framed'])) { - $OUTPUT->command('session_error', $RCMAIL->url(array('_err' => 'session'))); - $OUTPUT->send('iframe'); - } + $plugin = $RCMAIL->plugins->exec_hook('unauthenticated', array('task' => 'login', 'error' => $session_error)); - $plugin = $RCMAIL->plugins->exec_hook('unauthenticated', array('task' => 'login', 'error' => $session_error)); + $RCMAIL->set_task($plugin['task']); - $RCMAIL->set_task($plugin['task']); - $OUTPUT->send($plugin['task']); + $OUTPUT->send($plugin['task']); } // CSRF prevention else { - // don't check for valid request tokens in these actions - $request_check_whitelist = array('login'=>1, 'spell'=>1, 'spell_html'=>1); - - if (!$request_check_whitelist[$RCMAIL->action]) { - // check client X-header to verify request origin - if ($OUTPUT->ajax_call) { - if (rcube_utils::request_header('X-Roundcube-Request') != $RCMAIL->get_request_token()) { - header('HTTP/1.1 403 Forbidden'); - die("Invalid Request"); - } - } - // check request token in POST form submissions - else if (!empty($_POST) && !$RCMAIL->check_request()) { - $OUTPUT->show_message('invalidrequest', 'error'); - $OUTPUT->send($RCMAIL->task); + // don't check for valid request tokens in these actions + $request_check_whitelist = array('login'=>1, 'spell'=>1, 'spell_html'=>1); + + if (!$request_check_whitelist[$RCMAIL->action]) { + // check client X-header to verify request origin + if ($OUTPUT->ajax_call) { + if (rcube_utils::request_header('X-Roundcube-Request') != $RCMAIL->get_request_token()) { + header('HTTP/1.1 403 Forbidden'); + die("Invalid Request"); + } + } + // check request token in POST form submissions + else if (!empty($_POST) && !$RCMAIL->check_request()) { + $OUTPUT->show_message('invalidrequest', 'error'); + $OUTPUT->send($RCMAIL->task); + } + + // check referer if configured + if ($RCMAIL->config->get('referer_check') && !rcube_utils::check_referer()) { + raise_error(array( + 'code' => 403, 'type' => 'php', + 'message' => "Referer check failed"), true, true); + } } - - // check referer if configured - if ($RCMAIL->config->get('referer_check') && !rcube_utils::check_referer()) { - raise_error(array( - 'code' => 403, 'type' => 'php', - 'message' => "Referer check failed"), true, true); - } - } } // we're ready, user is authenticated and the request is safe @@ -254,58 +268,57 @@ $RCMAIL->action = $plugin['action']; // handle special actions if ($RCMAIL->action == 'keep-alive') { - $OUTPUT->reset(); - $RCMAIL->plugins->exec_hook('keep_alive', array()); - $OUTPUT->send(); + $OUTPUT->reset(); + $RCMAIL->plugins->exec_hook('keep_alive', array()); + $OUTPUT->send(); } else if ($RCMAIL->action == 'save-pref') { - include INSTALL_PATH . 'program/steps/utils/save_pref.inc'; + include INSTALL_PATH . 'program/steps/utils/save_pref.inc'; } // include task specific functions -if (is_file($incfile = INSTALL_PATH . 'program/steps/'.$RCMAIL->task.'/func.inc')) - include_once $incfile; +if (is_file($incfile = INSTALL_PATH . 'program/steps/'.$RCMAIL->task.'/func.inc')) { + include_once $incfile; +} // allow 5 "redirects" to another action $redirects = 0; $incstep = null; while ($redirects < 5) { - // execute a plugin action - if ($RCMAIL->plugins->is_plugin_task($RCMAIL->task)) { - if (!$RCMAIL->action) $RCMAIL->action = 'index'; - $RCMAIL->plugins->exec_action($RCMAIL->task.'.'.$RCMAIL->action); - break; - } - else if (preg_match('/^plugin\./', $RCMAIL->action)) { - $RCMAIL->plugins->exec_action($RCMAIL->action); - break; - } - // try to include the step file - else if (($stepfile = $RCMAIL->get_action_file()) - && is_file($incfile = INSTALL_PATH . 'program/steps/'.$RCMAIL->task.'/'.$stepfile) - ) { - // include action file only once (in case it don't exit) - include_once $incfile; - $redirects++; - } - else { - break; - } + // execute a plugin action + if ($RCMAIL->plugins->is_plugin_task($RCMAIL->task)) { + if (!$RCMAIL->action) $RCMAIL->action = 'index'; + $RCMAIL->plugins->exec_action($RCMAIL->task.'.'.$RCMAIL->action); + break; + } + else if (preg_match('/^plugin\./', $RCMAIL->action)) { + $RCMAIL->plugins->exec_action($RCMAIL->action); + break; + } + // try to include the step file + else if (($stepfile = $RCMAIL->get_action_file()) + && is_file($incfile = INSTALL_PATH . 'program/steps/'.$RCMAIL->task.'/'.$stepfile) + ) { + // include action file only once (in case it don't exit) + include_once $incfile; + $redirects++; + } + else { + break; + } } if ($RCMAIL->action == 'refresh') { - $RCMAIL->plugins->exec_hook('refresh', array('last' => intval(rcube_utils::get_input_value('_last', rcube_utils::INPUT_GPC)))); + $RCMAIL->plugins->exec_hook('refresh', array('last' => intval(rcube_utils::get_input_value('_last', rcube_utils::INPUT_GPC)))); } // parse main template (default) $OUTPUT->send($RCMAIL->task); - // if we arrive here, something went wrong rcmail::raise_error(array( - 'code' => 404, - 'type' => 'php', - 'line' => __LINE__, - 'file' => __FILE__, - 'message' => "Invalid request"), true, true); - + 'code' => 404, + 'type' => 'php', + 'line' => __LINE__, + 'file' => __FILE__, + 'message' => "Invalid request"), true, true); diff --git a/plugins/enigma/lib/enigma_ui.php b/plugins/enigma/lib/enigma_ui.php index 188987bf6..2e95938f2 100644 --- a/plugins/enigma/lib/enigma_ui.php +++ b/plugins/enigma/lib/enigma_ui.php @@ -104,7 +104,7 @@ class enigma_ui if ($this->css_loaded) return; - $skin_path = $this->local_skin_path(); + $skin_path = $this->enigma->local_skin_path(); if (is_file($this->home . "/$skin_path/enigma.css")) { $this->enigma->include_stylesheet("$skin_path/enigma.css"); } diff --git a/program/include/clisetup.php b/program/include/clisetup.php index 07e318521..47a40719a 100644 --- a/program/include/clisetup.php +++ b/program/include/clisetup.php @@ -20,7 +20,7 @@ */ if (php_sapi_name() != 'cli') { - die('Not on the "shell" (php-cli).'); + die('Not on the "shell" (php-cli).'); } require_once INSTALL_PATH . 'program/include/iniset.php'; diff --git a/program/include/iniset.php b/program/include/iniset.php index 919cc7682..f6ad466da 100644 --- a/program/include/iniset.php +++ b/program/include/iniset.php @@ -84,4 +84,3 @@ function rcmail_autoload($classname) return false; } - diff --git a/program/include/rcmail.php b/program/include/rcmail.php index dbf56e55f..a927b7946 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -5,8 +5,8 @@ | program/include/rcmail.php | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2008-2012, The Roundcube Dev Team | - | Copyright (C) 2011-2012, Kolab Systems AG | + | Copyright (C) 2008-2013, The Roundcube Dev Team | + | Copyright (C) 2011-2013, Kolab Systems AG | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -21,7 +21,6 @@ +-----------------------------------------------------------------------+ */ - /** * Application class of Roundcube Webmail * implemented as singleton @@ -30,616 +29,640 @@ */ class rcmail extends rcube { - /** - * Main tasks. - * - * @var array - */ - static public $main_tasks = array('mail','settings','addressbook','login','logout','utils','dummy'); - - /** - * Current task. - * - * @var string - */ - public $task; - - /** - * Current action. - * - * @var string - */ - public $action = ''; - public $comm_path = './'; - public $filename = ''; - - private $address_books = array(); - private $action_map = array(); - - - const ERROR_STORAGE = -2; - const ERROR_INVALID_REQUEST = 1; - const ERROR_INVALID_HOST = 2; - const ERROR_COOKIES_DISABLED = 3; - - - /** - * This implements the 'singleton' design pattern - * - * @param string Environment name to run (e.g. live, dev, test) - * @return rcmail The one and only instance - */ - static function get_instance($env = '') - { - if (!self::$instance || !is_a(self::$instance, 'rcmail')) { - self::$instance = new rcmail($env); - self::$instance->startup(); // init AFTER object was linked with self::$instance - } + /** + * Main tasks. + * + * @var array + */ + static public $main_tasks = array('mail','settings','addressbook','login','logout','utils','dummy'); - return self::$instance; - } - - - /** - * Initial startup function - * to register session, create database and imap connections - */ - protected function startup() - { - $this->init(self::INIT_WITH_DB | self::INIT_WITH_PLUGINS); - - // set filename if not index.php - if (($basename = basename($_SERVER['SCRIPT_FILENAME'])) && $basename != 'index.php') - $this->filename = $basename; - - // start session - $this->session_init(); - - // create user object - $this->set_user(new rcube_user($_SESSION['user_id'])); - - // set task and action properties - $this->set_task(rcube_utils::get_input_value('_task', rcube_utils::INPUT_GPC)); - $this->action = asciiwords(rcube_utils::get_input_value('_action', rcube_utils::INPUT_GPC)); - - // reset some session parameters when changing task - if ($this->task != 'utils') { - // we reset list page when switching to another task - // but only to the main task interface - empty action (#1489076) - // this will prevent from unintentional page reset on cross-task requests - if ($this->session && $_SESSION['task'] != $this->task && empty($this->action)) - $this->session->remove('page'); - // set current task to session - $_SESSION['task'] = $this->task; - } + /** + * Current task. + * + * @var string + */ + public $task; - // init output class - if (!empty($_REQUEST['_remote'])) - $GLOBALS['OUTPUT'] = $this->json_init(); - else - $GLOBALS['OUTPUT'] = $this->load_gui(!empty($_REQUEST['_framed'])); - - // load plugins - $this->plugins->init($this, $this->task); - $this->plugins->load_plugins((array)$this->config->get('plugins', array()), array('filesystem_attachments', 'jqueryui')); - } - - - /** - * Setter for application task - * - * @param string Task to set - */ - public function set_task($task) - { - $task = asciiwords($task, true); - - if ($this->user && $this->user->ID) - $task = !$task ? 'mail' : $task; - else - $task = 'login'; - - $this->task = $task; - $this->comm_path = $this->url(array('task' => $this->task)); - - if ($this->output) - $this->output->set_env('task', $this->task); - } - - - /** - * Setter for system user object - * - * @param rcube_user Current user instance - */ - public function set_user($user) - { - if (is_object($user)) { - $this->user = $user; - - // overwrite config with user preferences - $this->config->set_user_prefs((array)$this->user->get_prefs()); - } + /** + * Current action. + * + * @var string + */ + public $action = ''; + public $comm_path = './'; + public $filename = ''; - $lang = $this->language_prop($this->config->get('language', $_SESSION['language'])); - $_SESSION['language'] = $this->user->language = $lang; + private $address_books = array(); + private $action_map = array(); - // set localization - setlocale(LC_ALL, $lang . '.utf8', $lang . '.UTF-8', 'en_US.utf8', 'en_US.UTF-8'); - // workaround for http://bugs.php.net/bug.php?id=18556 - if (version_compare(PHP_VERSION, '5.5.0', '<') && in_array($lang, array('tr_TR', 'ku', 'az_AZ'))) { - setlocale(LC_CTYPE, 'en_US.utf8', 'en_US.UTF-8'); - } - } - - - /** - * Return instance of the internal address book class - * - * @param string Address book identifier (-1 for default addressbook) - * @param boolean True if the address book needs to be writeable - * - * @return rcube_contacts Address book object - */ - public function get_address_book($id, $writeable = false) - { - $contacts = null; - $ldap_config = (array)$this->config->get('ldap_public'); - - // 'sql' is the alias for '0' used by autocomplete - if ($id == 'sql') - $id = '0'; - else if ($id == -1) { - $id = $this->config->get('default_addressbook'); - $default = true; - } + const ERROR_STORAGE = -2; + const ERROR_INVALID_REQUEST = 1; + const ERROR_INVALID_HOST = 2; + const ERROR_COOKIES_DISABLED = 3; - // use existing instance - if (isset($this->address_books[$id]) && ($this->address_books[$id] instanceof rcube_addressbook)) { - $contacts = $this->address_books[$id]; - } - else if ($id && $ldap_config[$id]) { - $contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['storage_host'])); - } - else if ($id === '0') { - $contacts = new rcube_contacts($this->db, $this->get_user_id()); - } - else { - $plugin = $this->plugins->exec_hook('addressbook_get', array('id' => $id, 'writeable' => $writeable)); - // plugin returned instance of a rcube_addressbook - if ($plugin['instance'] instanceof rcube_addressbook) { - $contacts = $plugin['instance']; - } - } + /** + * This implements the 'singleton' design pattern + * + * @param string Environment name to run (e.g. live, dev, test) + * + * @return rcmail The one and only instance + */ + static function get_instance($env = '') + { + if (!self::$instance || !is_a(self::$instance, 'rcmail')) { + self::$instance = new rcmail($env); + // init AFTER object was linked with self::$instance + self::$instance->startup(); + } - // when user requested default writeable addressbook - // we need to check if default is writeable, if not we - // will return first writeable book (if any exist) - if ($contacts && $default && $contacts->readonly && $writeable) { - $contacts = null; + return self::$instance; } - // Get first addressbook from the list if configured default doesn't exist - // This can happen when user deleted the addressbook (e.g. Kolab folder) - if (!$contacts && (!$id || $default)) { - $source = reset($this->get_address_sources($writeable, !$default)); - if (!empty($source)) { - $contacts = $this->get_address_book($source['id']); - if ($contacts) { - $id = $source['id']; + /** + * Initial startup function + * to register session, create database and imap connections + */ + protected function startup() + { + $this->init(self::INIT_WITH_DB | self::INIT_WITH_PLUGINS); + + // set filename if not index.php + if (($basename = basename($_SERVER['SCRIPT_FILENAME'])) && $basename != 'index.php') { + $this->filename = $basename; } - } - } - if (!$contacts) { - // there's no default, just return - if ($default) { - return null; - } - - self::raise_error(array( - 'code' => 700, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Addressbook source ($id) not found!"), - true, true); - } + // start session + $this->session_init(); - // add to the 'books' array for shutdown function - $this->address_books[$id] = $contacts; + // create user object + $this->set_user(new rcube_user($_SESSION['user_id'])); - if ($writeable && $contacts->readonly) { - return null; - } + // set task and action properties + $this->set_task(rcube_utils::get_input_value('_task', rcube_utils::INPUT_GPC)); + $this->action = asciiwords(rcube_utils::get_input_value('_action', rcube_utils::INPUT_GPC)); - // set configured sort order - if ($sort_col = $this->config->get('addressbook_sort_col')) { - $contacts->set_sort_order($sort_col); - } + // reset some session parameters when changing task + if ($this->task != 'utils') { + // we reset list page when switching to another task + // but only to the main task interface - empty action (#1489076) + // this will prevent from unintentional page reset on cross-task requests + if ($this->session && $_SESSION['task'] != $this->task && empty($this->action)) { + $this->session->remove('page'); + } - return $contacts; - } - - - /** - * Return identifier of the address book object - * - * @param rcube_addressbook Addressbook source object - * - * @return string Source identifier - */ - public function get_address_book_id($object) - { - foreach ($this->address_books as $index => $book) { - if ($book === $object) { - return $index; - } - } - } - - - /** - * Return address books list - * - * @param boolean True if the address book needs to be writeable - * @param boolean True if the address book needs to be not hidden - * - * @return array Address books array - */ - public function get_address_sources($writeable = false, $skip_hidden = false) - { - $abook_type = (string) $this->config->get('address_book_type'); - $ldap_config = (array) $this->config->get('ldap_public'); - $autocomplete = (array) $this->config->get('autocomplete_addressbooks'); - $list = array(); - - // We are using the DB address book or a plugin address book - if (!empty($abook_type) && strtolower($abook_type) != 'ldap') { - if (!isset($this->address_books['0'])) - $this->address_books['0'] = new rcube_contacts($this->db, $this->get_user_id()); - $list['0'] = array( - 'id' => '0', - 'name' => $this->gettext('personaladrbook'), - 'groups' => $this->address_books['0']->groups, - 'readonly' => $this->address_books['0']->readonly, - 'autocomplete' => in_array('sql', $autocomplete), - 'undelete' => $this->address_books['0']->undelete && $this->config->get('undo_timeout'), - ); - } + // set current task to session + $_SESSION['task'] = $this->task; + } - if (!empty($ldap_config)) { - foreach ($ldap_config as $id => $prop) { - // handle misconfiguration - if (empty($prop) || !is_array($prop)) { - continue; - } - $list[$id] = array( - 'id' => $id, - 'name' => html::quote($prop['name']), - 'groups' => !empty($prop['groups']) || !empty($prop['group_filters']), - 'readonly' => !$prop['writable'], - 'hidden' => $prop['hidden'], - 'autocomplete' => in_array($id, $autocomplete) - ); - } - } + // init output class + if (!empty($_REQUEST['_remote'])) + $GLOBALS['OUTPUT'] = $this->json_init(); + else + $GLOBALS['OUTPUT'] = $this->load_gui(!empty($_REQUEST['_framed'])); - $plugin = $this->plugins->exec_hook('addressbooks_list', array('sources' => $list)); - $list = $plugin['sources']; - - foreach ($list as $idx => $item) { - // register source for shutdown function - if (!is_object($this->address_books[$item['id']])) { - $this->address_books[$item['id']] = $item; - } - // remove from list if not writeable as requested - if ($writeable && $item['readonly']) { - unset($list[$idx]); - } - // remove from list if hidden as requested - else if ($skip_hidden && $item['hidden']) { - unset($list[$idx]); - } + // load plugins + $this->plugins->init($this, $this->task); + $this->plugins->load_plugins((array)$this->config->get('plugins', array()), + array('filesystem_attachments', 'jqueryui')); } - return $list; - } - - /** - * Getter for compose responses. - * These are stored in local config and user preferences. - * - * @param boolean True to sort the list alphabetically - * @param boolean True if only this user's responses shall be listed - * @return array List of the current user's stored responses - */ - public function get_compose_responses($sorted = false, $user_only = false) - { - $responses = array(); - - if (!$user_only) { - foreach ($this->config->get('compose_responses_static', array()) as $response) { - if (empty($response['key'])) - $response['key'] = substr(md5($response['name']), 0, 16); - $response['static'] = true; - $response['class'] = 'readonly'; - $k = $sorted ? '0000-' . strtolower($response['name']) : $response['key']; - $responses[$k] = $response; - } - } + /** + * Setter for application task + * + * @param string Task to set + */ + public function set_task($task) + { + $task = asciiwords($task, true); - foreach ($this->config->get('compose_responses', array()) as $response) { - if (empty($response['key'])) - $response['key'] = substr(md5($response['name']), 0, 16); - $k = $sorted ? strtolower($response['name']) : $response['key']; - $responses[$k] = $response; - } + if ($this->user && $this->user->ID) + $task = !$task ? 'mail' : $task; + else + $task = 'login'; - // sort list by name - if ($sorted) { - ksort($responses, SORT_LOCALE_STRING); - } + $this->task = $task; + $this->comm_path = $this->url(array('task' => $this->task)); - return array_values($responses); - } - - - /** - * Init output object for GUI and add common scripts. - * This will instantiate a rcmail_output_html object and set - * environment vars according to the current session and configuration - * - * @param boolean True if this request is loaded in a (i)frame - * @return rcube_output Reference to HTML output object - */ - public function load_gui($framed = false) - { - // init output page - if (!($this->output instanceof rcmail_output_html)) - $this->output = new rcmail_output_html($this->task, $framed); - - // set refresh interval - $this->output->set_env('refresh_interval', $this->config->get('refresh_interval', 0)); - $this->output->set_env('session_lifetime', $this->config->get('session_lifetime', 0) * 60); - - if ($framed) { - $this->comm_path .= '&_framed=1'; - $this->output->set_env('framed', true); + if ($this->output) { + $this->output->set_env('task', $this->task); + } } - $this->output->set_env('task', $this->task); - $this->output->set_env('action', $this->action); - $this->output->set_env('comm_path', $this->comm_path); - $this->output->set_charset(RCUBE_CHARSET); - - if ($this->user && $this->user->ID) - $this->output->set_env('user_id', $this->user->get_hash()); - - // add some basic labels to client - $this->output->add_label('loading', 'servererror', 'requesttimedout', 'refreshing'); - - return $this->output; - } - - - /** - * Create an output object for JSON responses - * - * @return rcube_output Reference to JSON output object - */ - public function json_init() - { - if (!($this->output instanceof rcmail_output_json)) - $this->output = new rcmail_output_json($this->task); - - return $this->output; - } - - - /** - * Create session object and start the session. - */ - public function session_init() - { - parent::session_init(); - - // set initial session vars - if (!$_SESSION['user_id']) - $_SESSION['temp'] = true; - - // restore skin selection after logout - if ($_SESSION['temp'] && !empty($_SESSION['skin'])) - $this->config->set('skin', $_SESSION['skin']); - } - - - /** - * Perfom login to the mail server and to the webmail service. - * This will also create a new user entry if auto_create_user is configured. - * - * @param string Mail storage (IMAP) user name - * @param string Mail storage (IMAP) password - * @param string Mail storage (IMAP) host - * @param bool Enables cookie check - * - * @return boolean True on success, False on failure - */ - function login($username, $pass, $host = null, $cookiecheck = false) - { - $this->login_error = null; - - if (empty($username)) { - return false; - } + /** + * Setter for system user object + * + * @param rcube_user Current user instance + */ + public function set_user($user) + { + if (is_object($user)) { + $this->user = $user; - if ($cookiecheck && empty($_COOKIE)) { - $this->login_error = self::ERROR_COOKIES_DISABLED; - return false; - } + // overwrite config with user preferences + $this->config->set_user_prefs((array)$this->user->get_prefs()); + } - $config = $this->config->all(); - - if (!$host) - $host = $config['default_host']; - - // Validate that selected host is in the list of configured hosts - if (is_array($config['default_host'])) { - $allowed = false; - foreach ($config['default_host'] as $key => $host_allowed) { - if (!is_numeric($key)) - $host_allowed = $key; - if ($host == $host_allowed) { - $allowed = true; - break; - } - } - if (!$allowed) { - $host = null; - } - } - else if (!empty($config['default_host']) && $host != rcube_utils::parse_host($config['default_host'])) { - $host = null; - } + $lang = $this->language_prop($this->config->get('language', $_SESSION['language'])); + $_SESSION['language'] = $this->user->language = $lang; - if (!$host) { - $this->login_error = self::ERROR_INVALID_HOST; - return false; - } + // set localization + setlocale(LC_ALL, $lang . '.utf8', $lang . '.UTF-8', 'en_US.utf8', 'en_US.UTF-8'); - // parse $host URL - $a_host = parse_url($host); - if ($a_host['host']) { - $host = $a_host['host']; - $ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null; - if (!empty($a_host['port'])) - $port = $a_host['port']; - else if ($ssl && $ssl != 'tls' && (!$config['default_port'] || $config['default_port'] == 143)) - $port = 993; + // workaround for http://bugs.php.net/bug.php?id=18556 + if (version_compare(PHP_VERSION, '5.5.0', '<') && in_array($lang, array('tr_TR', 'ku', 'az_AZ'))) { + setlocale(LC_CTYPE, 'en_US.utf8', 'en_US.UTF-8'); + } } - if (!$port) { - $port = $config['default_port']; - } + /** + * Return instance of the internal address book class + * + * @param string Address book identifier (-1 for default addressbook) + * @param boolean True if the address book needs to be writeable + * + * @return rcube_contacts Address book object + */ + public function get_address_book($id, $writeable = false) + { + $contacts = null; + $ldap_config = (array)$this->config->get('ldap_public'); + + // 'sql' is the alias for '0' used by autocomplete + if ($id == 'sql') + $id = '0'; + else if ($id == -1) { + $id = $this->config->get('default_addressbook'); + $default = true; + } + + // use existing instance + if (isset($this->address_books[$id]) && ($this->address_books[$id] instanceof rcube_addressbook)) { + $contacts = $this->address_books[$id]; + } + else if ($id && $ldap_config[$id]) { + $domain = $this->config->mail_domain($_SESSION['storage_host']); + $contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $domain); + } + else if ($id === '0') { + $contacts = new rcube_contacts($this->db, $this->get_user_id()); + } + else { + $plugin = $this->plugins->exec_hook('addressbook_get', array('id' => $id, 'writeable' => $writeable)); - // Check if we need to add/force domain to username - if (!empty($config['username_domain'])) { - $domain = is_array($config['username_domain']) ? $config['username_domain'][$host] : $config['username_domain']; + // plugin returned instance of a rcube_addressbook + if ($plugin['instance'] instanceof rcube_addressbook) { + $contacts = $plugin['instance']; + } + } + + // when user requested default writeable addressbook + // we need to check if default is writeable, if not we + // will return first writeable book (if any exist) + if ($contacts && $default && $contacts->readonly && $writeable) { + $contacts = null; + } + + // Get first addressbook from the list if configured default doesn't exist + // This can happen when user deleted the addressbook (e.g. Kolab folder) + if (!$contacts && (!$id || $default)) { + $source = reset($this->get_address_sources($writeable, !$default)); + if (!empty($source)) { + $contacts = $this->get_address_book($source['id']); + if ($contacts) { + $id = $source['id']; + } + } + } - if ($domain = rcube_utils::parse_host((string)$domain, $host)) { - $pos = strpos($username, '@'); + if (!$contacts) { + // there's no default, just return + if ($default) { + return null; + } - // force configured domains - if (!empty($config['username_domain_forced']) && $pos !== false) { - $username = substr($username, 0, $pos) . '@' . $domain; + self::raise_error(array( + 'code' => 700, + 'file' => __FILE__, + 'line' => __LINE__, + 'message' => "Addressbook source ($id) not found!" + ), + true, true); } - // just add domain if not specified - else if ($pos === false) { - $username .= '@' . $domain; + + // add to the 'books' array for shutdown function + $this->address_books[$id] = $contacts; + + if ($writeable && $contacts->readonly) { + return null; } - } - } - if (!isset($config['login_lc'])) { - $config['login_lc'] = 2; // default - } + // set configured sort order + if ($sort_col = $this->config->get('addressbook_sort_col')) { + $contacts->set_sort_order($sort_col); + } - // Convert username to lowercase. If storage backend - // is case-insensitive we need to store always the same username (#1487113) - if ($config['login_lc']) { - if ($config['login_lc'] == 2 || $config['login_lc'] === true) { - $username = mb_strtolower($username); - } - else if (strpos($username, '@')) { - // lowercase domain name - list($local, $domain) = explode('@', $username); - $username = $local . '@' . mb_strtolower($domain); - } + return $contacts; } - // try to resolve email address from virtuser table - if (strpos($username, '@') && ($virtuser = rcube_user::email2user($username))) { - $username = $virtuser; + /** + * Return identifier of the address book object + * + * @param rcube_addressbook Addressbook source object + * + * @return string Source identifier + */ + public function get_address_book_id($object) + { + foreach ($this->address_books as $index => $book) { + if ($book === $object) { + return $index; + } + } } - // Here we need IDNA ASCII - // Only rcube_contacts class is using domain names in Unicode - $host = rcube_utils::idn_to_ascii($host); - $username = rcube_utils::idn_to_ascii($username); + /** + * Return address books list + * + * @param boolean True if the address book needs to be writeable + * @param boolean True if the address book needs to be not hidden + * + * @return array Address books array + */ + public function get_address_sources($writeable = false, $skip_hidden = false) + { + $abook_type = (string) $this->config->get('address_book_type'); + $ldap_config = (array) $this->config->get('ldap_public'); + $autocomplete = (array) $this->config->get('autocomplete_addressbooks'); + $list = array(); + + // We are using the DB address book or a plugin address book + if (!empty($abook_type) && strtolower($abook_type) != 'ldap') { + if (!isset($this->address_books['0'])) { + $this->address_books['0'] = new rcube_contacts($this->db, $this->get_user_id()); + } + + $list['0'] = array( + 'id' => '0', + 'name' => $this->gettext('personaladrbook'), + 'groups' => $this->address_books['0']->groups, + 'readonly' => $this->address_books['0']->readonly, + 'undelete' => $this->address_books['0']->undelete && $this->config->get('undo_timeout'), + 'autocomplete' => in_array('sql', $autocomplete), + ); + } - // user already registered -> overwrite username - if ($user = rcube_user::query($username, $host)) { - $username = $user->data['username']; + if (!empty($ldap_config)) { + foreach ($ldap_config as $id => $prop) { + // handle misconfiguration + if (empty($prop) || !is_array($prop)) { + continue; + } + + $list[$id] = array( + 'id' => $id, + 'name' => html::quote($prop['name']), + 'groups' => !empty($prop['groups']) || !empty($prop['group_filters']), + 'readonly' => !$prop['writable'], + 'hidden' => $prop['hidden'], + 'autocomplete' => in_array($id, $autocomplete) + ); + } + } + + $plugin = $this->plugins->exec_hook('addressbooks_list', array('sources' => $list)); + $list = $plugin['sources']; + + foreach ($list as $idx => $item) { + // register source for shutdown function + if (!is_object($this->address_books[$item['id']])) { + $this->address_books[$item['id']] = $item; + } + // remove from list if not writeable as requested + if ($writeable && $item['readonly']) { + unset($list[$idx]); + } + // remove from list if hidden as requested + else if ($skip_hidden && $item['hidden']) { + unset($list[$idx]); + } + } + + return $list; } - $storage = $this->get_storage(); + /** + * Getter for compose responses. + * These are stored in local config and user preferences. + * + * @param boolean True to sort the list alphabetically + * @param boolean True if only this user's responses shall be listed + * + * @return array List of the current user's stored responses + */ + public function get_compose_responses($sorted = false, $user_only = false) + { + $responses = array(); + + if (!$user_only) { + foreach ($this->config->get('compose_responses_static', array()) as $response) { + if (empty($response['key'])) { + $response['key'] = substr(md5($response['name']), 0, 16); + } + + $response['static'] = true; + $response['class'] = 'readonly'; + + $k = $sorted ? '0000-' . strtolower($response['name']) : $response['key']; + $responses[$k] = $response; + } + } + + foreach ($this->config->get('compose_responses', array()) as $response) { + if (empty($response['key'])) { + $response['key'] = substr(md5($response['name']), 0, 16); + } + + $k = $sorted ? strtolower($response['name']) : $response['key']; + $responses[$k] = $response; + } - // try to log in - if (!$storage->connect($host, $username, $pass, $port, $ssl)) { - return false; + // sort list by name + if ($sorted) { + ksort($responses, SORT_LOCALE_STRING); + } + + return array_values($responses); } - // user already registered -> update user's record - if (is_object($user)) { - // update last login timestamp - $user->touch(); + /** + * Init output object for GUI and add common scripts. + * This will instantiate a rcmail_output_html object and set + * environment vars according to the current session and configuration + * + * @param boolean True if this request is loaded in a (i)frame + * + * @return rcube_output Reference to HTML output object + */ + public function load_gui($framed = false) + { + // init output page + if (!($this->output instanceof rcmail_output_html)) { + $this->output = new rcmail_output_html($this->task, $framed); + } + + // set refresh interval + $this->output->set_env('refresh_interval', $this->config->get('refresh_interval', 0)); + $this->output->set_env('session_lifetime', $this->config->get('session_lifetime', 0) * 60); + + if ($framed) { + $this->comm_path .= '&_framed=1'; + $this->output->set_env('framed', true); + } + + $this->output->set_env('task', $this->task); + $this->output->set_env('action', $this->action); + $this->output->set_env('comm_path', $this->comm_path); + $this->output->set_charset(RCUBE_CHARSET); + + if ($this->user && $this->user->ID) { + $this->output->set_env('user_id', $this->user->get_hash()); + } + + // add some basic labels to client + $this->output->add_label('loading', 'servererror', 'requesttimedout', 'refreshing'); + + return $this->output; } - // create new system user - else if ($config['auto_create_user']) { - if ($created = rcube_user::create($username, $host)) { - $user = $created; - } - else { - self::raise_error(array( - 'code' => 620, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Failed to create a user record. Maybe aborted by a plugin?" - ), true, false); - } + + /** + * Create an output object for JSON responses + * + * @return rcube_output Reference to JSON output object + */ + public function json_init() + { + if (!($this->output instanceof rcmail_output_json)) { + $this->output = new rcmail_output_json($this->task); + } + + return $this->output; } - else { - self::raise_error(array( - 'code' => 621, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Access denied for new user $username. 'auto_create_user' is disabled" - ), true, false); + + /** + * Create session object and start the session. + */ + public function session_init() + { + parent::session_init(); + + // set initial session vars + if (!$_SESSION['user_id']) { + $_SESSION['temp'] = true; + } + + // restore skin selection after logout + if ($_SESSION['temp'] && !empty($_SESSION['skin'])) { + $this->config->set('skin', $_SESSION['skin']); + } } - // login succeeded - if (is_object($user) && $user->ID) { - // Configure environment - $this->set_user($user); - $this->set_storage_prop(); + /** + * Perfom login to the mail server and to the webmail service. + * This will also create a new user entry if auto_create_user is configured. + * + * @param string Mail storage (IMAP) user name + * @param string Mail storage (IMAP) password + * @param string Mail storage (IMAP) host + * @param bool Enables cookie check + * + * @return boolean True on success, False on failure + */ + function login($username, $pass, $host = null, $cookiecheck = false) + { + $this->login_error = null; + + if (empty($username)) { + return false; + } + + if ($cookiecheck && empty($_COOKIE)) { + $this->login_error = self::ERROR_COOKIES_DISABLED; + return false; + } - // fix some old settings according to namespace prefix - $this->fix_namespace_settings($user); + $config = $this->config->all(); - // create default folders on first login - if ($config['create_default_folders'] && (!empty($created) || empty($user->data['last_login']))) { - $storage->create_default_folders(); - } + if (!$host) { + $host = $config['default_host']; + } - // set session vars - $_SESSION['user_id'] = $user->ID; - $_SESSION['username'] = $user->data['username']; - $_SESSION['storage_host'] = $host; - $_SESSION['storage_port'] = $port; - $_SESSION['storage_ssl'] = $ssl; - $_SESSION['password'] = $this->encrypt($pass); - $_SESSION['login_time'] = time(); + // Validate that selected host is in the list of configured hosts + if (is_array($config['default_host'])) { + $allowed = false; - if (isset($_REQUEST['_timezone']) && $_REQUEST['_timezone'] != '_default_') - $_SESSION['timezone'] = rcube_utils::get_input_value('_timezone', rcube_utils::INPUT_GPC); + foreach ($config['default_host'] as $key => $host_allowed) { + if (!is_numeric($key)) { + $host_allowed = $key; + } + if ($host == $host_allowed) { + $allowed = true; + break; + } + } - // force reloading complete list of subscribed mailboxes - $storage->clear_cache('mailboxes', true); + if (!$allowed) { + $host = null; + } + } + else if (!empty($config['default_host']) && $host != rcube_utils::parse_host($config['default_host'])) { + $host = null; + } - return true; - } + if (!$host) { + $this->login_error = self::ERROR_INVALID_HOST; + return false; + } + + // parse $host URL + $a_host = parse_url($host); + if ($a_host['host']) { + $host = $a_host['host']; + $ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null; - return false; - } + if (!empty($a_host['port'])) + $port = $a_host['port']; + else if ($ssl && $ssl != 'tls' && (!$config['default_port'] || $config['default_port'] == 143)) + $port = 993; + } + + if (!$port) { + $port = $config['default_port']; + } + + // Check if we need to add/force domain to username + if (!empty($config['username_domain'])) { + $domain = is_array($config['username_domain']) ? $config['username_domain'][$host] : $config['username_domain']; + + if ($domain = rcube_utils::parse_host((string)$domain, $host)) { + $pos = strpos($username, '@'); + + // force configured domains + if (!empty($config['username_domain_forced']) && $pos !== false) { + $username = substr($username, 0, $pos) . '@' . $domain; + } + // just add domain if not specified + else if ($pos === false) { + $username .= '@' . $domain; + } + } + } + if (!isset($config['login_lc'])) { + $config['login_lc'] = 2; // default + } + + // Convert username to lowercase. If storage backend + // is case-insensitive we need to store always the same username (#1487113) + if ($config['login_lc']) { + if ($config['login_lc'] == 2 || $config['login_lc'] === true) { + $username = mb_strtolower($username); + } + else if (strpos($username, '@')) { + // lowercase domain name + list($local, $domain) = explode('@', $username); + $username = $local . '@' . mb_strtolower($domain); + } + } + + // try to resolve email address from virtuser table + if (strpos($username, '@') && ($virtuser = rcube_user::email2user($username))) { + $username = $virtuser; + } + + // Here we need IDNA ASCII + // Only rcube_contacts class is using domain names in Unicode + $host = rcube_utils::idn_to_ascii($host); + $username = rcube_utils::idn_to_ascii($username); + + // user already registered -> overwrite username + if ($user = rcube_user::query($username, $host)) { + $username = $user->data['username']; + } + + $storage = $this->get_storage(); + + // try to log in + if (!$storage->connect($host, $username, $pass, $port, $ssl)) { + return false; + } + + // user already registered -> update user's record + if (is_object($user)) { + // update last login timestamp + $user->touch(); + } + // create new system user + else if ($config['auto_create_user']) { + if ($created = rcube_user::create($username, $host)) { + $user = $created; + } + else { + self::raise_error(array( + 'code' => 620, + 'file' => __FILE__, + 'line' => __LINE__, + 'message' => "Failed to create a user record. Maybe aborted by a plugin?" + ), + true, false); + } + } + else { + self::raise_error(array( + 'code' => 621, + 'file' => __FILE__, + 'line' => __LINE__, + 'message' => "Access denied for new user $username. 'auto_create_user' is disabled" + ), + true, false); + } + + // login succeeded + if (is_object($user) && $user->ID) { + // Configure environment + $this->set_user($user); + $this->set_storage_prop(); + + // fix some old settings according to namespace prefix + $this->fix_namespace_settings($user); + + // create default folders on first login + if ($config['create_default_folders'] && (!empty($created) || empty($user->data['last_login']))) { + $storage->create_default_folders(); + } + + // set session vars + $_SESSION['user_id'] = $user->ID; + $_SESSION['username'] = $user->data['username']; + $_SESSION['storage_host'] = $host; + $_SESSION['storage_port'] = $port; + $_SESSION['storage_ssl'] = $ssl; + $_SESSION['password'] = $this->encrypt($pass); + $_SESSION['login_time'] = time(); + + if (isset($_REQUEST['_timezone']) && $_REQUEST['_timezone'] != '_default_') { + $_SESSION['timezone'] = rcube_utils::get_input_value('_timezone', rcube_utils::INPUT_GPC); + } + + // force reloading complete list of subscribed mailboxes + $storage->clear_cache('mailboxes', true); + + return true; + } + + return false; + } /** * Returns error code of last login operation @@ -657,315 +680,317 @@ class rcmail extends rcube } } + /** + * Auto-select IMAP host based on the posted login information + * + * @return string Selected IMAP host + */ + public function autoselect_host() + { + $default_host = $this->config->get('default_host'); + $host = null; - /** - * Auto-select IMAP host based on the posted login information - * - * @return string Selected IMAP host - */ - public function autoselect_host() - { - $default_host = $this->config->get('default_host'); - $host = null; - - if (is_array($default_host)) { - $post_host = rcube_utils::get_input_value('_host', rcube_utils::INPUT_POST); - $post_user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST); - - list(, $domain) = explode('@', $post_user); - - // direct match in default_host array - if ($default_host[$post_host] || in_array($post_host, array_values($default_host))) { - $host = $post_host; - } - // try to select host by mail domain - else if (!empty($domain)) { - foreach ($default_host as $storage_host => $mail_domains) { - if (is_array($mail_domains) && in_array_nocase($domain, $mail_domains)) { - $host = $storage_host; - break; - } - else if (stripos($storage_host, $domain) !== false || stripos(strval($mail_domains), $domain) !== false) { - $host = is_numeric($storage_host) ? $mail_domains : $storage_host; - break; - } + if (is_array($default_host)) { + $post_host = rcube_utils::get_input_value('_host', rcube_utils::INPUT_POST); + $post_user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST); + + list(, $domain) = explode('@', $post_user); + + // direct match in default_host array + if ($default_host[$post_host] || in_array($post_host, array_values($default_host))) { + $host = $post_host; + } + // try to select host by mail domain + else if (!empty($domain)) { + foreach ($default_host as $storage_host => $mail_domains) { + if (is_array($mail_domains) && in_array_nocase($domain, $mail_domains)) { + $host = $storage_host; + break; + } + else if (stripos($storage_host, $domain) !== false || stripos(strval($mail_domains), $domain) !== false) { + $host = is_numeric($storage_host) ? $mail_domains : $storage_host; + break; + } + } + } + + // take the first entry if $host is still not set + if (empty($host)) { + list($key, $val) = each($default_host); + $host = is_numeric($key) ? $val : $key; + } + } + else if (empty($default_host)) { + $host = rcube_utils::get_input_value('_host', rcube_utils::INPUT_POST); + } + else { + $host = rcube_utils::parse_host($default_host); } - } - // take the first entry if $host is still not set - if (empty($host)) { - list($key, $val) = each($default_host); - $host = is_numeric($key) ? $val : $key; - } + return $host; } - else if (empty($default_host)) { - $host = rcube_utils::get_input_value('_host', rcube_utils::INPUT_POST); + + /** + * Destroy session data and remove cookie + */ + public function kill_session() + { + $this->plugins->exec_hook('session_destroy'); + + $this->session->kill(); + $_SESSION = array('language' => $this->user->language, 'temp' => true, 'skin' => $this->config->get('skin')); + $this->user->reset(); } - else - $host = rcube_utils::parse_host($default_host); - return $host; - } + /** + * Do server side actions on logout + */ + public function logout_actions() + { + $config = $this->config->all(); + $storage = $this->get_storage(); + + if ($config['logout_purge'] && !empty($config['trash_mbox'])) { + $storage->clear_folder($config['trash_mbox']); + } + if ($config['logout_expunge']) { + $storage->expunge_folder('INBOX'); + } - /** - * Destroy session data and remove cookie - */ - public function kill_session() - { - $this->plugins->exec_hook('session_destroy'); + // Try to save unsaved user preferences + if (!empty($_SESSION['preferences'])) { + $this->user->save_prefs(unserialize($_SESSION['preferences'])); + } + } - $this->session->kill(); - $_SESSION = array('language' => $this->user->language, 'temp' => true, 'skin' => $this->config->get('skin')); - $this->user->reset(); - } + /** + * Generate a unique token to be used in a form request + * + * @return string The request token + */ + public function get_request_token() + { + $sess_id = $_COOKIE[ini_get('session.name')]; + if (!$sess_id) { + $sess_id = session_id(); + } - /** - * Do server side actions on logout - */ - public function logout_actions() - { - $config = $this->config->all(); - $storage = $this->get_storage(); + $plugin = $this->plugins->exec_hook('request_token', array( + 'value' => md5('RT' . $this->get_user_id() . $this->config->get('des_key') . $sess_id))); - if ($config['logout_purge'] && !empty($config['trash_mbox'])) { - $storage->clear_folder($config['trash_mbox']); + return $plugin['value']; } - if ($config['logout_expunge']) { - $storage->expunge_folder('INBOX'); - } + /** + * Check if the current request contains a valid token + * + * @param int Request method + * + * @return boolean True if request token is valid false if not + */ + public function check_request($mode = rcube_utils::INPUT_POST) + { + $token = rcube_utils::get_input_value('_token', $mode); + $sess_id = $_COOKIE[ini_get('session.name')]; - // Try to save unsaved user preferences - if (!empty($_SESSION['preferences'])) { - $this->user->save_prefs(unserialize($_SESSION['preferences'])); - } - } - - - /** - * Generate a unique token to be used in a form request - * - * @return string The request token - */ - public function get_request_token() - { - $sess_id = $_COOKIE[ini_get('session.name')]; - if (!$sess_id) $sess_id = session_id(); - - $plugin = $this->plugins->exec_hook('request_token', array( - 'value' => md5('RT' . $this->get_user_id() . $this->config->get('des_key') . $sess_id))); - - return $plugin['value']; - } - - - /** - * Check if the current request contains a valid token - * - * @param int Request method - * @return boolean True if request token is valid false if not - */ - public function check_request($mode = rcube_utils::INPUT_POST) - { - $token = rcube_utils::get_input_value('_token', $mode); - $sess_id = $_COOKIE[ini_get('session.name')]; - return !empty($sess_id) && $token == $this->get_request_token(); - } - - - /** - * Build a valid URL to this instance of Roundcube - * - * @param mixed Either a string with the action or url parameters as key-value pairs - * - * @return string Valid application URL - */ - public function url($p) - { - if (!is_array($p)) { - if (strpos($p, 'http') === 0) - return $p; - - $p = array('_action' => @func_get_arg(0)); + return !empty($sess_id) && $token == $this->get_request_token(); } - $task = $p['_task'] ? $p['_task'] : ($p['task'] ? $p['task'] : $this->task); - $p['_task'] = $task; - unset($p['task']); - - $url = './' . $this->filename; - $delm = '?'; - foreach (array_reverse($p) as $key => $val) { - if ($val !== '' && $val !== null) { - $par = $key[0] == '_' ? $key : '_'.$key; - $url .= $delm.urlencode($par).'='.urlencode($val); - $delm = '&'; - } - } - return $url; - } + /** + * Build a valid URL to this instance of Roundcube + * + * @param mixed Either a string with the action or url parameters as key-value pairs + * + * @return string Valid application URL + */ + public function url($p) + { + if (!is_array($p)) { + if (strpos($p, 'http') === 0) { + return $p; + } + $p = array('_action' => @func_get_arg(0)); + } - /** - * Function to be executed in script shutdown - */ - public function shutdown() - { - parent::shutdown(); + $task = $p['_task'] ? $p['_task'] : ($p['task'] ? $p['task'] : $this->task); + $p['_task'] = $task; + unset($p['task']); - foreach ($this->address_books as $book) { - if (is_object($book) && is_a($book, 'rcube_addressbook')) - $book->close(); - } + $url = './' . $this->filename; + $delm = '?'; - // write performance stats to logs/console - if ($this->config->get('devel_mode')) { - if (function_exists('memory_get_usage')) - $mem = $this->show_bytes(memory_get_usage()); - if (function_exists('memory_get_peak_usage')) - $mem .= '/'.$this->show_bytes(memory_get_peak_usage()); - - $log = $this->task . ($this->action ? '/'.$this->action : '') . ($mem ? " [$mem]" : ''); - if (defined('RCMAIL_START')) - self::print_timer(RCMAIL_START, $log); - else - self::console($log); - } - } - - - /** - * Registers action aliases for current task - * - * @param array $map Alias-to-filename hash array - */ - public function register_action_map($map) - { - if (is_array($map)) { - foreach ($map as $idx => $val) { - $this->action_map[$idx] = $val; - } - } - } - - - /** - * Returns current action filename - * - * @param array $map Alias-to-filename hash array - */ - public function get_action_file() - { - if (!empty($this->action_map[$this->action])) { - return $this->action_map[$this->action]; + foreach (array_reverse($p) as $key => $val) { + if ($val !== '' && $val !== null) { + $par = $key[0] == '_' ? $key : '_'.$key; + $url .= $delm.urlencode($par).'='.urlencode($val); + $delm = '&'; + } + } + + return $url; } - return strtr($this->action, '-', '_') . '.inc'; - } - - - /** - * Fixes some user preferences according to namespace handling change. - * Old Roundcube versions were using folder names with removed namespace prefix. - * Now we need to add the prefix on servers where personal namespace has prefix. - * - * @param rcube_user $user User object - */ - private function fix_namespace_settings($user) - { - $prefix = $this->storage->get_namespace('prefix'); - $prefix_len = strlen($prefix); - - if (!$prefix_len) - return; - - $prefs = $this->config->all(); - if (!empty($prefs['namespace_fixed'])) - return; - - // Build namespace prefix regexp - $ns = $this->storage->get_namespace(); - $regexp = array(); - - foreach ($ns as $entry) { - if (!empty($entry)) { - foreach ($entry as $item) { - if (strlen($item[0])) { - $regexp[] = preg_quote($item[0], '/'); - } + /** + * Function to be executed in script shutdown + */ + public function shutdown() + { + parent::shutdown(); + + foreach ($this->address_books as $book) { + if (is_object($book) && is_a($book, 'rcube_addressbook')) + $book->close(); } - } - } - $regexp = '/^('. implode('|', $regexp).')/'; - // Fix preferences - $opts = array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox', 'archive_mbox'); - foreach ($opts as $opt) { - if ($value = $prefs[$opt]) { - if ($value != 'INBOX' && !preg_match($regexp, $value)) { - $prefs[$opt] = $prefix.$value; + // write performance stats to logs/console + if ($this->config->get('devel_mode')) { + if (function_exists('memory_get_usage')) + $mem = $this->show_bytes(memory_get_usage()); + if (function_exists('memory_get_peak_usage')) + $mem .= '/'.$this->show_bytes(memory_get_peak_usage()); + + $log = $this->task . ($this->action ? '/'.$this->action : '') . ($mem ? " [$mem]" : ''); + + if (defined('RCMAIL_START')) + self::print_timer(RCMAIL_START, $log); + else + self::console($log); } - } } - if (!empty($prefs['default_folders'])) { - foreach ($prefs['default_folders'] as $idx => $name) { - if ($name != 'INBOX' && !preg_match($regexp, $name)) { - $prefs['default_folders'][$idx] = $prefix.$name; + /** + * Registers action aliases for current task + * + * @param array $map Alias-to-filename hash array + */ + public function register_action_map($map) + { + if (is_array($map)) { + foreach ($map as $idx => $val) { + $this->action_map[$idx] = $val; + } } - } } - if (!empty($prefs['search_mods'])) { - $folders = array(); - foreach ($prefs['search_mods'] as $idx => $value) { - if ($idx != 'INBOX' && $idx != '*' && !preg_match($regexp, $idx)) { - $idx = $prefix.$idx; + /** + * Returns current action filename + * + * @param array $map Alias-to-filename hash array + */ + public function get_action_file() + { + if (!empty($this->action_map[$this->action])) { + return $this->action_map[$this->action]; } - $folders[$idx] = $value; - } - $prefs['search_mods'] = $folders; + + return strtr($this->action, '-', '_') . '.inc'; } - if (!empty($prefs['message_threading'])) { - $folders = array(); - foreach ($prefs['message_threading'] as $idx => $value) { - if ($idx != 'INBOX' && !preg_match($regexp, $idx)) { - $idx = $prefix.$idx; + /** + * Fixes some user preferences according to namespace handling change. + * Old Roundcube versions were using folder names with removed namespace prefix. + * Now we need to add the prefix on servers where personal namespace has prefix. + * + * @param rcube_user $user User object + */ + private function fix_namespace_settings($user) + { + $prefix = $this->storage->get_namespace('prefix'); + $prefix_len = strlen($prefix); + + if (!$prefix_len) + return; + + $prefs = $this->config->all(); + if (!empty($prefs['namespace_fixed'])) + return; + + // Build namespace prefix regexp + $ns = $this->storage->get_namespace(); + $regexp = array(); + + foreach ($ns as $entry) { + if (!empty($entry)) { + foreach ($entry as $item) { + if (strlen($item[0])) { + $regexp[] = preg_quote($item[0], '/'); + } + } + } } - $folders[$prefix.$idx] = $value; - } - $prefs['message_threading'] = $folders; - } + $regexp = '/^('. implode('|', $regexp).')/'; - if (!empty($prefs['collapsed_folders'])) { - $folders = explode('&&', $prefs['collapsed_folders']); - $count = count($folders); - $folders_str = ''; + // Fix preferences + $opts = array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox', 'archive_mbox'); + foreach ($opts as $opt) { + if ($value = $prefs[$opt]) { + if ($value != 'INBOX' && !preg_match($regexp, $value)) { + $prefs[$opt] = $prefix.$value; + } + } + } - if ($count) { - $folders[0] = substr($folders[0], 1); - $folders[$count-1] = substr($folders[$count-1], 0, -1); - } + if (!empty($prefs['default_folders'])) { + foreach ($prefs['default_folders'] as $idx => $name) { + if ($name != 'INBOX' && !preg_match($regexp, $name)) { + $prefs['default_folders'][$idx] = $prefix.$name; + } + } + } + + if (!empty($prefs['search_mods'])) { + $folders = array(); + foreach ($prefs['search_mods'] as $idx => $value) { + if ($idx != 'INBOX' && $idx != '*' && !preg_match($regexp, $idx)) { + $idx = $prefix.$idx; + } + $folders[$idx] = $value; + } - foreach ($folders as $value) { - if ($value != 'INBOX' && !preg_match($regexp, $value)) { - $value = $prefix.$value; + $prefs['search_mods'] = $folders; } - $folders_str .= '&'.$value.'&'; - } - $prefs['collapsed_folders'] = $folders_str; - } - $prefs['namespace_fixed'] = true; + if (!empty($prefs['message_threading'])) { + $folders = array(); + foreach ($prefs['message_threading'] as $idx => $value) { + if ($idx != 'INBOX' && !preg_match($regexp, $idx)) { + $idx = $prefix.$idx; + } + $folders[$prefix.$idx] = $value; + } + + $prefs['message_threading'] = $folders; + } + + if (!empty($prefs['collapsed_folders'])) { + $folders = explode('&&', $prefs['collapsed_folders']); + $count = count($folders); + $folders_str = ''; + + if ($count) { + $folders[0] = substr($folders[0], 1); + $folders[$count-1] = substr($folders[$count-1], 0, -1); + } + + foreach ($folders as $value) { + if ($value != 'INBOX' && !preg_match($regexp, $value)) { + $value = $prefix.$value; + } + $folders_str .= '&'.$value.'&'; + } - // save updated preferences and reset imap settings (default folders) - $user->save_prefs($prefs); - $this->set_storage_prop(); - } + $prefs['collapsed_folders'] = $folders_str; + } + $prefs['namespace_fixed'] = true; + + // save updated preferences and reset imap settings (default folders) + $user->save_prefs($prefs); + $this->set_storage_prop(); + } /** * Overwrite action variable @@ -978,6 +1003,17 @@ class rcmail extends rcube $this->output->set_env('action', $action); } + /** + * Set environment variables for specified config options + */ + public function set_env_config($options) + { + foreach ((array) $options as $option) { + if ($this->config->get($option)) { + $this->output->set_env($option, true); + } + } + } /** * Returns RFC2822 formatted current date in user's timezone @@ -998,7 +1034,6 @@ class rcmail extends rcube return $date->format('r'); } - /** * Write login data (name, ID, IP address) to the 'userlogins' log file. */ @@ -1023,14 +1058,13 @@ class rcmail extends rcube } $message = sprintf('Successful login for %s (ID: %d) from %s in session %s', - $user_name, $user_id, rcube_utils::remote_ip(), session_id()); + $user_name, $user_id, rcube_utils::remote_ip(), session_id()); } // log login self::write_log('userlogins', $message); } - /** * Create a HTML table based on the given data * @@ -1080,7 +1114,6 @@ class rcmail extends rcube return $table->show($attrib); } - /** * Convert the given date to a human readable form * This uses the date formatting properties from config @@ -1210,7 +1243,6 @@ class rcmail extends rcube return $out; } - /** * Return folders list in HTML * @@ -1303,7 +1335,6 @@ class rcmail extends rcube return $out; } - /** * Return folders list as html_select object * @@ -1347,7 +1378,6 @@ class rcmail extends rcube return $select; } - /** * Create a hierarchical array of the mailbox list */ @@ -1405,7 +1435,6 @@ class rcmail extends rcube } } - /** * Return html for a structured list <ul> for the mailbox tree */ @@ -1500,7 +1529,6 @@ class rcmail extends rcube return $out; } - /** * Return html for a flat list <select> for the mailbox tree */ @@ -1545,7 +1573,6 @@ class rcmail extends rcube return $out; } - /** * Return internal name for the given folder if it matches the configured special folders */ @@ -1564,7 +1591,6 @@ class rcmail extends rcube } } - /** * Try to localize the given IMAP folder name. * UTF-7 decode it in case no localized text was found @@ -1682,7 +1708,6 @@ class rcmail extends rcube return $quota_result; } - /** * Outputs error message according to server error/response codes * @@ -1736,7 +1761,6 @@ class rcmail extends rcube } } - /** * Output HTML editor scripts * @@ -1777,7 +1801,6 @@ class rcmail extends rcube $this->output->add_script("rcmail_editor_init($script)", 'docready'); } - /** * Replaces TinyMCE's emoticon images with plain-text representation * @@ -1815,7 +1838,6 @@ class rcmail extends rcube return preg_replace($search, $replace, $html); } - /** * File upload progress handler. */ @@ -1847,7 +1869,6 @@ class rcmail extends rcube $this->output->send(); } - /** * Initializes file uploading interface. */ @@ -1865,6 +1886,7 @@ class rcmail extends rcube // find max filesize value $max_filesize = parse_bytes(ini_get('upload_max_filesize')); $max_postsize = parse_bytes(ini_get('post_max_size')); + if ($max_postsize && $max_postsize < $max_filesize) { $max_filesize = $max_postsize; } @@ -1877,7 +1899,6 @@ class rcmail extends rcube return $max_filesize; } - /** * Initializes client-side autocompletion. */ @@ -1904,7 +1925,6 @@ class rcmail extends rcube $this->output->add_label('autocompletechars', 'autocompletemore'); } - /** * Returns supported font-family specifications * @@ -1937,7 +1957,6 @@ class rcmail extends rcube return $fonts; } - /** * Create a human readable string for a number of bytes * @@ -1965,7 +1984,6 @@ class rcmail extends rcube return $str; } - /** * Returns real size (calculated) of the message part * diff --git a/program/include/rcmail_html_page.php b/program/include/rcmail_html_page.php index 5d07b8d04..d5610ab47 100644 --- a/program/include/rcmail_html_page.php +++ b/program/include/rcmail_html_page.php @@ -38,11 +38,12 @@ class rcmail_html_page extends rcmail_output_html } else { // set default styles for warning blocks inside the attachment part frame $this->add_header(html::tag('style', array('type' => 'text/css'), - ".rcmail-inline-message { font-family: sans-serif; border:2px solid #ffdf0e; background:#fef893; padding:0.6em 1em; margin-bottom:0.6em }\n" . + ".rcmail-inline-message { font-family: sans-serif; border:2px solid #ffdf0e;" + . "background:#fef893; padding:0.6em 1em; margin-bottom:0.6em }\n" . ".rcmail-inline-buttons { margin-bottom:0 }" )); } parent::write($contents); } -}
\ No newline at end of file +} diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index e4059b73d..4df755985 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -5,7 +5,7 @@ | program/include/rcmail_output_html.php | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2006-2012, The Roundcube Dev Team | + | Copyright (C) 2006-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -83,9 +83,9 @@ class rcmail_output_html extends rcmail_output $this->set_env('skin', $skin); if (!empty($_REQUEST['_extwin'])) - $this->set_env('extwin', 1); + $this->set_env('extwin', 1); if ($this->framed || !empty($_REQUEST['_framed'])) - $this->set_env('framed', 1); + $this->set_env('framed', 1); // add common javascripts $this->add_script('var '.self::JS_OBJECT_NAME.' = new rcube_webmail();', 'head_top'); @@ -119,6 +119,7 @@ class rcmail_output_html extends rcmail_output public function set_env($name, $value, $addtojs = true) { $this->env[$name] = $value; + if ($addtojs || isset($this->js_env[$name])) { $this->js_env[$name] = $value; } diff --git a/program/include/rcmail_string_replacer.php b/program/include/rcmail_string_replacer.php index 4fbc611c9..6771375e1 100644 --- a/program/include/rcmail_string_replacer.php +++ b/program/include/rcmail_string_replacer.php @@ -5,7 +5,7 @@ | program/include/rcmail_string_replacer.php | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2012, The Roundcube Dev Team | + | Copyright (C) 2012-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -19,7 +19,6 @@ +-----------------------------------------------------------------------+ */ - /** * Helper class for turning URLs and email addresses in plaintext content * into clickable links. @@ -40,15 +39,15 @@ class rcmail_string_replacer extends rcube_string_replacer */ public function mailto_callback($matches) { - $href = $matches[1]; - $suffix = $this->parse_url_brackets($href); + $href = $matches[1]; + $suffix = $this->parse_url_brackets($href); - $i = $this->add(html::a(array( - 'href' => 'mailto:' . $href, - 'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('compose','".rcube::JQ($href)."',this)", - ), rcube::Q($href)) . $suffix); + $i = $this->add(html::a(array( + 'href' => 'mailto:' . $href, + 'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('compose','".rcube::JQ($href)."',this)", + ), + rcube::Q($href)) . $suffix); - return $i >= 0 ? $this->get_replacement($i) : ''; + return $i >= 0 ? $this->get_replacement($i) : ''; } - -}
\ No newline at end of file +} diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php index 331b57e96..503e29d6f 100644 --- a/program/lib/Roundcube/rcube.php +++ b/program/lib/Roundcube/rcube.php @@ -1152,7 +1152,6 @@ class rcube // handle PHP exceptions if (is_object($arg) && is_a($arg, 'Exception')) { $arg = array( - 'type' => 'php', 'code' => $arg->getCode(), 'line' => $arg->getLine(), 'file' => $arg->getFile(), @@ -1160,7 +1159,7 @@ class rcube ); } else if (is_string($arg)) { - $arg = array('message' => $arg, 'type' => 'php'); + $arg = array('message' => $arg); } if (empty($arg['code'])) { @@ -1176,7 +1175,7 @@ class rcube $cli = php_sapi_name() == 'cli'; - if (($log || $terminate) && !$cli && $arg['type'] && $arg['message']) { + if (($log || $terminate) && !$cli && $arg['message']) { $arg['fatal'] = $terminate; self::log_bug($arg); } @@ -1204,7 +1203,7 @@ class rcube */ public static function log_bug($arg_arr) { - $program = strtoupper($arg_arr['type']); + $program = strtoupper(!empty($arg_arr['type']) ? $arg_arr['type'] : 'php'); $level = self::get_instance()->config->get('debug_level'); // disable errors for ajax requests, write to log instead (#1487831) diff --git a/program/lib/Roundcube/rcube_charset.php b/program/lib/Roundcube/rcube_charset.php index 19dbf6cbc..8612e7fca 100644 --- a/program/lib/Roundcube/rcube_charset.php +++ b/program/lib/Roundcube/rcube_charset.php @@ -199,10 +199,13 @@ class rcube_charset $iconv_options = ''; } } + else { + $iconv_options = false; + } } // convert charset using iconv module - if ($iconv_options !== null && $from != 'UTF7-IMAP' && $to != 'UTF7-IMAP') { + if ($iconv_options !== false && $from != 'UTF7-IMAP' && $to != 'UTF7-IMAP') { // throw an exception if iconv reports an illegal character in input // it means that input string has been truncated set_error_handler(array('rcube_charset', 'error_handler'), E_NOTICE); @@ -224,10 +227,13 @@ class rcube_charset $mbstring_list = mb_list_encodings(); $mbstring_list = array_map('strtoupper', $mbstring_list); } + else { + $mbstring_list = false; + } } // convert charset using mbstring module - if ($mbstring_list !== null) { + if ($mbstring_list !== false) { $aliases['WINDOWS-1257'] = 'ISO-8859-13'; // it happens that mbstring supports ASCII but not US-ASCII if (($from == 'US-ASCII' || $to == 'US-ASCII') && !in_array('US-ASCII', $mbstring_list)) { diff --git a/program/steps/addressbook/copy.inc b/program/steps/addressbook/copy.inc index 9af22ec35..9114cb1fd 100644 --- a/program/steps/addressbook/copy.inc +++ b/program/steps/addressbook/copy.inc @@ -5,7 +5,7 @@ | program/steps/addressbook/copy.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2007, The Roundcube Dev Team | + | Copyright (C) 2007-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -32,8 +32,7 @@ $success = 0; $errormsg = 'copyerror'; $maxnum = $RCMAIL->config->get('max_group_members', 0); -foreach ($cids as $source => $cid) -{ +foreach ($cids as $source => $cid) { // Something wrong, target not specified if (!strlen($target)) { break; diff --git a/program/steps/addressbook/delete.inc b/program/steps/addressbook/delete.inc index b2aac8a71..3d57d7074 100644 --- a/program/steps/addressbook/delete.inc +++ b/program/steps/addressbook/delete.inc @@ -5,7 +5,7 @@ | program/steps/addressbook/delete.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -30,8 +30,7 @@ $delcnt = 0; $undo_time = $RCMAIL->config->get('undo_timeout', 0); $RCMAIL->session->remove('contact_undo'); -foreach ($cids as $source => $cid) -{ +foreach ($cids as $source => $cid) { $CONTACTS = rcmail_contact_source($source); if ($CONTACTS->readonly) { diff --git a/program/steps/addressbook/edit.inc b/program/steps/addressbook/edit.inc index f7f0c7100..3bbbfccdf 100644 --- a/program/steps/addressbook/edit.inc +++ b/program/steps/addressbook/edit.inc @@ -59,6 +59,25 @@ else { $SOURCE_ID = $source; rcmail_set_sourcename($CONTACTS); + +$OUTPUT->add_handlers(array( + 'contactedithead' => 'rcmail_contact_edithead', + 'contacteditform' => 'rcmail_contact_editform', + 'contactphoto' => 'rcmail_contact_photo', + 'photouploadform' => 'rcmail_upload_photo_form', + 'sourceselector' => 'rcmail_source_selector', + 'filedroparea' => 'rcmail_photo_drop_area', +)); + +if ($RCMAIL->action == 'add' && $OUTPUT->template_exists('contactadd')) { + $OUTPUT->send('contactadd'); +} + +// this will be executed if no template for addcontact exists +$OUTPUT->send('contactedit'); + + + function rcmail_get_edit_record() { global $RCMAIL, $CONTACTS; @@ -289,19 +308,3 @@ function rcmail_photo_drop_area($attrib) $OUTPUT->set_env('filedrop', array('action' => 'upload-photo', 'fieldname' => '_photo', 'single' => 1, 'filter' => '^image/.+')); } } - - -$OUTPUT->add_handlers(array( - 'contactedithead' => 'rcmail_contact_edithead', - 'contacteditform' => 'rcmail_contact_editform', - 'contactphoto' => 'rcmail_contact_photo', - 'photouploadform' => 'rcmail_upload_photo_form', - 'sourceselector' => 'rcmail_source_selector', - 'filedroparea' => 'rcmail_photo_drop_area', -)); - -if ($RCMAIL->action == 'add' && $OUTPUT->template_exists('contactadd')) - $OUTPUT->send('contactadd'); - -// this will be executed if no template for addcontact exists -$OUTPUT->send('contactedit'); diff --git a/program/steps/addressbook/export.inc b/program/steps/addressbook/export.inc index c112f08a3..2b45e5cd1 100644 --- a/program/steps/addressbook/export.inc +++ b/program/steps/addressbook/export.inc @@ -6,7 +6,7 @@ | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2013, The Roundcube Dev Team | - | Copyright (C) 2011, Kolab Systems AG | + | Copyright (C) 2011-2013, Kolab Systems AG | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -21,49 +21,8 @@ +-----------------------------------------------------------------------+ */ - -/** - * Copy contact record properties into a vcard object - */ -function prepare_for_export(&$record, $source = null) -{ - $groups = $source && $source->groups && $source->export_groups ? $source->get_record_groups($record['ID']) : null; - - if (empty($record['vcard'])) { - $vcard = new rcube_vcard(); - if ($source) { - $vcard->extend_fieldmap($source->vcard_map); - } - $vcard->load($record['vcard']); - $vcard->reset(); - - foreach ($record as $key => $values) { - list($field, $section) = explode(':', $key); - foreach ((array)$values as $value) { - if (is_array($value) || @strlen($value)) { - $vcard->set($field, $value, strtoupper($section)); - } - } - } - - // append group names - if ($groups) { - $vcard->set('groups', join(',', $groups), null); - } - - $record['vcard'] = $vcard->export(true); - } - // patch categories to alread existing vcard block - else if ($record['vcard'] && !empty($groups) && !strpos($record['vcard'], 'CATEGORIES:')) { - $vgroups = 'CATEGORIES:' . rcube_vcard::vcard_quote(join(',', $groups)); - $record['vcard'] = str_replace('END:VCARD', $vgroups . rcube_vcard::$eol . 'END:VCARD', $record['vcard']); - } -} - - // Use search result -if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']])) -{ +if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']])) { $sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name'); $search = (array)$_SESSION['search'][$_REQUEST['_search']]; $records = array(); @@ -153,3 +112,42 @@ while ($result && ($row = $result->next())) { } exit; + + +/** + * Copy contact record properties into a vcard object + */ +function prepare_for_export(&$record, $source = null) +{ + $groups = $source && $source->groups && $source->export_groups ? $source->get_record_groups($record['ID']) : null; + + if (empty($record['vcard'])) { + $vcard = new rcube_vcard(); + if ($source) { + $vcard->extend_fieldmap($source->vcard_map); + } + $vcard->load($record['vcard']); + $vcard->reset(); + + foreach ($record as $key => $values) { + list($field, $section) = explode(':', $key); + foreach ((array)$values as $value) { + if (is_array($value) || @strlen($value)) { + $vcard->set($field, $value, strtoupper($section)); + } + } + } + + // append group names + if ($groups) { + $vcard->set('groups', join(',', $groups), null); + } + + $record['vcard'] = $vcard->export(true); + } + // patch categories to alread existing vcard block + else if ($record['vcard'] && !empty($groups) && !strpos($record['vcard'], 'CATEGORIES:')) { + $vgroups = 'CATEGORIES:' . rcube_vcard::vcard_quote(join(',', $groups)); + $record['vcard'] = str_replace('END:VCARD', $vgroups . rcube_vcard::$eol . 'END:VCARD', $record['vcard']); + } +} diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index 8be721c0b..b33396baf 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -109,6 +109,31 @@ if ($undo = $_SESSION['contact_undo']) { $RCMAIL->session->remove('contact_undo'); } +// register UI objects +$OUTPUT->add_handlers(array( + 'directorylist' => 'rcmail_directory_list', +// 'groupslist' => 'rcmail_contact_groups', + 'addresslist' => 'rcmail_contacts_list', + 'addresslisttitle' => 'rcmail_contacts_list_title', + 'addressframe' => 'rcmail_contact_frame', + 'recordscountdisplay' => 'rcmail_rowcount_display', + 'searchform' => array($OUTPUT, 'search_form') +)); + +// register action aliases +$RCMAIL->register_action_map(array( + 'add' => 'edit.inc', + 'group-create' => 'groups.inc', + 'group-rename' => 'groups.inc', + 'group-delete' => 'groups.inc', + 'group-addmembers' => 'groups.inc', + 'group-delmembers' => 'groups.inc', + 'search-create' => 'search.inc', + 'search-delete' => 'search.inc', +)); + + + // instantiate a contacts object according to the given source function rcmail_contact_source($source=null, $init_env=false, $writable=false) { @@ -895,27 +920,3 @@ function rcmail_get_cids($filter = null) return $filter !== null ? $result[$filter] : $result; } - - -// register UI objects -$OUTPUT->add_handlers(array( - 'directorylist' => 'rcmail_directory_list', -// 'groupslist' => 'rcmail_contact_groups', - 'addresslist' => 'rcmail_contacts_list', - 'addresslisttitle' => 'rcmail_contacts_list_title', - 'addressframe' => 'rcmail_contact_frame', - 'recordscountdisplay' => 'rcmail_rowcount_display', - 'searchform' => array($OUTPUT, 'search_form') -)); - -// register action aliases -$RCMAIL->register_action_map(array( - 'add' => 'edit.inc', - 'group-create' => 'groups.inc', - 'group-rename' => 'groups.inc', - 'group-delete' => 'groups.inc', - 'group-addmembers' => 'groups.inc', - 'group-delmembers' => 'groups.inc', - 'search-create' => 'search.inc', - 'search-delete' => 'search.inc', -)); diff --git a/program/steps/addressbook/import.inc b/program/steps/addressbook/import.inc index 600ba8301..33e473242 100644 --- a/program/steps/addressbook/import.inc +++ b/program/steps/addressbook/import.inc @@ -20,164 +20,6 @@ +-----------------------------------------------------------------------+ */ -/** - * Handler function to display the import/upload form - */ -function rcmail_import_form($attrib) -{ - global $RCMAIL, $OUTPUT; - - $target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC); - - $attrib += array('id' => "rcmImportForm"); - - $writable_books = $RCMAIL->get_address_sources(true, true); - - $upload = new html_inputfield(array( - 'type' => 'file', - 'name' => '_file[]', - 'id' => 'rcmimportfile', - 'size' => 40, - 'multiple' => 'multiple', - )); - $form = html::p(null, html::label('rcmimportfile', $RCMAIL->gettext('importfromfile')) . $upload->show()); - $table = new html_table(array('cols' => 2)); - - // addressbook selector - if (count($writable_books) > 1) { - $select = new html_select(array('name' => '_target', 'id' => 'rcmimporttarget', 'is_escaped' => true)); - - foreach ($writable_books as $book) { - $select->add($book['name'], $book['id']); - } - - $table->add('title', html::label('rcmimporttarget', $RCMAIL->gettext('importtarget'))); - $table->add(null, $select->show($target)); - } - else { - $abook = new html_hiddenfield(array('name' => '_target', 'value' => key($writable_books))); - $form .= $abook->show(); - } - - // selector for group import options - if (count($writable_books) >= 1 || $writable_books[0]->groups) { - $select = new html_select(array('name' => '_groups', 'id' => 'rcmimportgroups', 'is_escaped' => true)); - $select->add($RCMAIL->gettext('none'), '0'); - $select->add($RCMAIL->gettext('importgroupsall'), '1'); - $select->add($RCMAIL->gettext('importgroupsexisting'), '2'); - - $table->add('title', html::label('rcmimportgroups', $RCMAIL->gettext('importgroups'))); - $table->add(null, $select->show(rcube_utils::get_input_value('_groups', rcube_utils::INPUT_GPC))); - } - - // checkbox to replace the entire address book - $check_replace = new html_checkbox(array('name' => '_replace', 'value' => 1, 'id' => 'rcmimportreplace')); - $table->add('title', html::label('rcmimportreplace', $RCMAIL->gettext('importreplace'))); - $table->add(null, $check_replace->show(rcube_utils::get_input_value('_replace', rcube_utils::INPUT_GPC))); - - $form .= $table->show(array('id' => null) + $attrib); - - $OUTPUT->set_env('writable_source', !empty($writable_books)); - $OUTPUT->add_label('selectimportfile','importwait'); - $OUTPUT->add_gui_object('importform', $attrib['id']); - - $out = html::p(null, rcube::Q($RCMAIL->gettext('importdesc'), 'show')) - . $OUTPUT->form_tag(array( - 'action' => $RCMAIL->url('import'), - 'method' => 'post', - 'enctype' => 'multipart/form-data') + $attrib, - $form); - - return $out; -} - - -/** - * Render the confirmation page for the import process - */ -function rcmail_import_confirm($attrib) -{ - global $IMPORT_STATS, $RCMAIL; - - $vars = get_object_vars($IMPORT_STATS); - $vars['names'] = $vars['skipped_names'] = ''; - - $content = html::p(null, $RCMAIL->gettext(array( - 'name' => 'importconfirm', - 'nr' => $IMPORT_STATS->inserted, - 'vars' => $vars, - )) . ($IMPORT_STATS->names ? ':' : '.')); - - if ($IMPORT_STATS->names) { - $content .= html::p('em', join(', ', array_map('Q', $IMPORT_STATS->names))); - } - - if ($IMPORT_STATS->skipped) { - $content .= html::p(null, $RCMAIL->gettext(array( - 'name' => 'importconfirmskipped', - 'nr' => $IMPORT_STATS->skipped, - 'vars' => $vars, - )) . ':') - . html::p('em', join(', ', array_map('Q', $IMPORT_STATS->skipped_names))); - } - - return html::div($attrib, $content); -} - - -/** - * Create navigation buttons for the current import step - */ -function rcmail_import_buttons($attrib) -{ - global $IMPORT_STATS, $OUTPUT; - - $target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC); - - $attrib += array('type' => 'input'); - unset($attrib['name']); - - if (is_object($IMPORT_STATS)) { - $attrib['class'] = trim($attrib['class'] . ' mainaction'); - $out = $OUTPUT->button(array('command' => 'list', 'prop' => $target, 'label' => 'done') + $attrib); - } - else { - $out = $OUTPUT->button(array('command' => 'list', 'label' => 'cancel') + $attrib); - $out .= ' '; - $attrib['class'] = trim($attrib['class'] . ' mainaction'); - $out .= $OUTPUT->button(array('command' => 'import', 'label' => 'import') + $attrib); - } - - return $out; -} - - -/** - * Returns the matching group id. If group doesn't exist, it'll be created if allowed. - */ -function rcmail_import_group_id($group_name, $CONTACTS, $create, &$import_groups) -{ - $group_id = 0; - foreach ($import_groups as $key => $group) { - if (strtolower($group['name']) == strtolower($group_name)) { - $group_id = $group['ID']; - break; - } - } - - // create a new group - if (!$group_id && $create) { - $new_group = $CONTACTS->create_group($group_name); - if (!$new_group['ID']) - $new_group['ID'] = $new_group['id']; - $import_groups[] = $new_group; - $group_id = $new_group['ID']; - } - - return $group_id; -} - - /** The import process **/ $importstep = 'rcmail_import_form'; @@ -343,3 +185,159 @@ $OUTPUT->add_handlers(array( // render page $OUTPUT->send('importcontacts'); + + + +/** + * Handler function to display the import/upload form + */ +function rcmail_import_form($attrib) +{ + global $RCMAIL, $OUTPUT; + + $target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC); + + $attrib += array('id' => "rcmImportForm"); + + $writable_books = $RCMAIL->get_address_sources(true, true); + + $upload = new html_inputfield(array( + 'type' => 'file', + 'name' => '_file[]', + 'id' => 'rcmimportfile', + 'size' => 40, + 'multiple' => 'multiple', + )); + $form = html::p(null, html::label('rcmimportfile', $RCMAIL->gettext('importfromfile')) . $upload->show()); + $table = new html_table(array('cols' => 2)); + + // addressbook selector + if (count($writable_books) > 1) { + $select = new html_select(array('name' => '_target', 'id' => 'rcmimporttarget', 'is_escaped' => true)); + + foreach ($writable_books as $book) { + $select->add($book['name'], $book['id']); + } + + $table->add('title', html::label('rcmimporttarget', $RCMAIL->gettext('importtarget'))); + $table->add(null, $select->show($target)); + } + else { + $abook = new html_hiddenfield(array('name' => '_target', 'value' => key($writable_books))); + $form .= $abook->show(); + } + + // selector for group import options + if (count($writable_books) >= 1 || $writable_books[0]->groups) { + $select = new html_select(array('name' => '_groups', 'id' => 'rcmimportgroups', 'is_escaped' => true)); + $select->add($RCMAIL->gettext('none'), '0'); + $select->add($RCMAIL->gettext('importgroupsall'), '1'); + $select->add($RCMAIL->gettext('importgroupsexisting'), '2'); + + $table->add('title', html::label('rcmimportgroups', $RCMAIL->gettext('importgroups'))); + $table->add(null, $select->show(rcube_utils::get_input_value('_groups', rcube_utils::INPUT_GPC))); + } + + // checkbox to replace the entire address book + $check_replace = new html_checkbox(array('name' => '_replace', 'value' => 1, 'id' => 'rcmimportreplace')); + $table->add('title', html::label('rcmimportreplace', $RCMAIL->gettext('importreplace'))); + $table->add(null, $check_replace->show(rcube_utils::get_input_value('_replace', rcube_utils::INPUT_GPC))); + + $form .= $table->show(array('id' => null) + $attrib); + + $OUTPUT->set_env('writable_source', !empty($writable_books)); + $OUTPUT->add_label('selectimportfile','importwait'); + $OUTPUT->add_gui_object('importform', $attrib['id']); + + $out = html::p(null, rcube::Q($RCMAIL->gettext('importdesc'), 'show')) + . $OUTPUT->form_tag(array( + 'action' => $RCMAIL->url('import'), + 'method' => 'post', + 'enctype' => 'multipart/form-data') + $attrib, + $form); + + return $out; +} + +/** + * Render the confirmation page for the import process + */ +function rcmail_import_confirm($attrib) +{ + global $IMPORT_STATS, $RCMAIL; + + $vars = get_object_vars($IMPORT_STATS); + $vars['names'] = $vars['skipped_names'] = ''; + + $content = html::p(null, $RCMAIL->gettext(array( + 'name' => 'importconfirm', + 'nr' => $IMPORT_STATS->inserted, + 'vars' => $vars, + )) . ($IMPORT_STATS->names ? ':' : '.')); + + if ($IMPORT_STATS->names) { + $content .= html::p('em', join(', ', array_map('Q', $IMPORT_STATS->names))); + } + + if ($IMPORT_STATS->skipped) { + $content .= html::p(null, $RCMAIL->gettext(array( + 'name' => 'importconfirmskipped', + 'nr' => $IMPORT_STATS->skipped, + 'vars' => $vars, + )) . ':') + . html::p('em', join(', ', array_map('Q', $IMPORT_STATS->skipped_names))); + } + + return html::div($attrib, $content); +} + +/** + * Create navigation buttons for the current import step + */ +function rcmail_import_buttons($attrib) +{ + global $IMPORT_STATS, $OUTPUT; + + $target = rcube_utils::get_input_value('_target', rcube_utils::INPUT_GPC); + + $attrib += array('type' => 'input'); + unset($attrib['name']); + + if (is_object($IMPORT_STATS)) { + $attrib['class'] = trim($attrib['class'] . ' mainaction'); + $out = $OUTPUT->button(array('command' => 'list', 'prop' => $target, 'label' => 'done') + $attrib); + } + else { + $out = $OUTPUT->button(array('command' => 'list', 'label' => 'cancel') + $attrib); + $out .= ' '; + $attrib['class'] = trim($attrib['class'] . ' mainaction'); + $out .= $OUTPUT->button(array('command' => 'import', 'label' => 'import') + $attrib); + } + + return $out; +} + +/** + * Returns the matching group id. If group doesn't exist, it'll be created if allowed. + */ +function rcmail_import_group_id($group_name, $CONTACTS, $create, &$import_groups) +{ + $group_id = 0; + foreach ($import_groups as $key => $group) { + if (strtolower($group['name']) == strtolower($group_name)) { + $group_id = $group['ID']; + break; + } + } + + // create a new group + if (!$group_id && $create) { + $new_group = $CONTACTS->create_group($group_name); + if (!$new_group['ID']) + $new_group['ID'] = $new_group['id']; + $import_groups[] = $new_group; + $group_id = $new_group['ID']; + } + + return $group_id; +} diff --git a/program/steps/addressbook/mailto.inc b/program/steps/addressbook/mailto.inc index 7116e55b7..f5ff20bc0 100644 --- a/program/steps/addressbook/mailto.inc +++ b/program/steps/addressbook/mailto.inc @@ -5,7 +5,7 @@ | program/steps/addressbook/mailto.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2007, The Roundcube Dev Team | + | Copyright (C) 2007-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -19,24 +19,21 @@ +-----------------------------------------------------------------------+ */ -$cids = rcmail_get_cids(); -$mailto = array(); +$cids = rcmail_get_cids(); +$mailto = array(); $recipients = null; -foreach ($cids as $source => $cid) -{ +foreach ($cids as $source => $cid) { $CONTACTS = $RCMAIL->get_address_book($source); - if ($CONTACTS->ready) - { + if ($CONTACTS->ready) { $CONTACTS->set_page(1); $CONTACTS->set_pagesize(count($cid) + 2); // +2 to skip counting query $recipients = $CONTACTS->search($CONTACTS->primary_key, $cid, 0, true, true, 'email'); } } -if (!empty($_REQUEST['_gid']) && isset($_REQUEST['_source'])) -{ +if (!empty($_REQUEST['_gid']) && isset($_REQUEST['_source'])) { $source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC); $CONTACTS = $RCMAIL->get_address_book($source); @@ -55,16 +52,14 @@ if (!empty($_REQUEST['_gid']) && isset($_REQUEST['_source'])) } } -if ($recipients) -{ +if ($recipients) { while (is_object($recipients) && ($rec = $recipients->iterate())) { $emails = $CONTACTS->get_col_values('email', $rec, true); $mailto[] = format_email_recipient($emails[0], $rec['name']); } } -if (!empty($mailto)) -{ +if (!empty($mailto)) { $mailto_str = join(', ', $mailto); $mailto_id = substr(md5($mailto_str), 0, 16); $_SESSION['mailto'][$mailto_id] = urlencode($mailto_str); diff --git a/program/steps/addressbook/show.inc b/program/steps/addressbook/show.inc index e6a515bd6..f4224a3e2 100644 --- a/program/steps/addressbook/show.inc +++ b/program/steps/addressbook/show.inc @@ -5,7 +5,7 @@ | program/steps/addressbook/show.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2012, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -38,6 +38,15 @@ if ($cid && ($record = $CONTACTS->get_record($cid, true))) { // get address book name (for display) rcmail_set_sourcename($CONTACTS); +$OUTPUT->add_handlers(array( + 'contacthead' => 'rcmail_contact_head', + 'contactdetails' => 'rcmail_contact_details', + 'contactphoto' => 'rcmail_contact_photo', +)); + +$OUTPUT->send('contact'); + + function rcmail_contact_head($attrib) { @@ -183,12 +192,3 @@ function rcmail_contact_record_groups($contact_id) return $form_start . html::tag('fieldset', 'contactfieldgroup contactgroups', $table->show()) . $form_end; } - - -$OUTPUT->add_handlers(array( - 'contacthead' => 'rcmail_contact_head', - 'contactdetails' => 'rcmail_contact_details', - 'contactphoto' => 'rcmail_contact_photo', -)); - -$OUTPUT->send('contact'); diff --git a/program/steps/addressbook/undo.inc b/program/steps/addressbook/undo.inc index c23bd1cb6..ec3feb9c0 100644 --- a/program/steps/addressbook/undo.inc +++ b/program/steps/addressbook/undo.inc @@ -5,7 +5,7 @@ | program/steps/addressbook/undo.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2011, Kolab Systems AG | + | Copyright (C) 2011-2013, Kolab Systems AG | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -20,14 +20,14 @@ */ // process ajax requests only -if (!$OUTPUT->ajax_call) +if (!$OUTPUT->ajax_call) { return; +} $undo = $_SESSION['contact_undo']; $delcnt = 0; -foreach ((array)$undo['data'] as $source => $cid) -{ +foreach ((array)$undo['data'] as $source => $cid) { $CONTACTS = rcmail_contact_source($source); $plugin = $RCMAIL->plugins->exec_hook('contact_undelete', array( diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index ce70819fd..93496eb99 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -5,7 +5,7 @@ | program/steps/mail/compose.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2012, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -35,73 +35,74 @@ if ($COMPOSE_ID && $_SESSION['compose_data_'.$COMPOSE_ID]) // give replicated session storage some time to synchronize $retries = 0; while ($COMPOSE_ID && !is_array($COMPOSE) && $RCMAIL->db->is_replicated() && $retries++ < 5) { - usleep(500000); - $RCMAIL->session->reload(); - if ($_SESSION['compose_data_'.$COMPOSE_ID]) - $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; + usleep(500000); + $RCMAIL->session->reload(); + if ($_SESSION['compose_data_'.$COMPOSE_ID]) { + $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; + } } // Nothing below is called during message composition, only at "new/forward/reply/draft" initialization or // if a compose-ID is given (i.e. when the compose step is opened in a new window/tab). -if (!is_array($COMPOSE)) -{ - // Infinite redirect prevention in case of broken session (#1487028) - if ($COMPOSE_ID) - rcube::raise_error(array('code' => 500, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Invalid compose ID"), true, true); - - $COMPOSE_ID = uniqid(mt_rand()); - $_SESSION['compose_data_'.$COMPOSE_ID] = array( - 'id' => $COMPOSE_ID, - 'param' => rcube_utils::request2param(rcube_utils::INPUT_GET, 'task|action', true), - 'mailbox' => $RCMAIL->storage->get_folder(), - ); - $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; +if (!is_array($COMPOSE)) { + // Infinite redirect prevention in case of broken session (#1487028) + if ($COMPOSE_ID) { + rcube::raise_error(array('code' => 500, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Invalid compose ID"), true, true); + } - rcmail_process_compose_params($COMPOSE); - - // add attachments listed by message_compose hook - if (is_array($plugin['attachments'])) { - foreach ($plugin['attachments'] as $attach) { - // we have structured data - if (is_array($attach)) { - $attachment = $attach; - } - // only a file path is given - else { - $filename = basename($attach); - $attachment = array( - 'group' => $COMPOSE_ID, - 'name' => $filename, - 'mimetype' => rcube_mime::file_content_type($attach, $filename), - 'path' => $attach, - ); - } - - // save attachment if valid - if (($attachment['data'] && $attachment['name']) || ($attachment['path'] && file_exists($attachment['path']))) { - $attachment = rcmail::get_instance()->plugins->exec_hook('attachment_save', $attachment); - } - - if ($attachment['status'] && !$attachment['abort']) { - unset($attachment['data'], $attachment['status'], $attachment['abort']); - $COMPOSE['attachments'][$attachment['id']] = $attachment; - } - } - } - - // check if folder for saving sent messages exists and is subscribed (#1486802) - if ($sent_folder = $COMPOSE['param']['sent_mbox']) { - rcmail_check_sent_folder($sent_folder, true); - } - - // redirect to a unique URL with all parameters stored in session - $OUTPUT->redirect(array( - '_action' => 'compose', - '_id' => $COMPOSE['id'], - '_search' => $_REQUEST['_search'], - )); + $COMPOSE_ID = uniqid(mt_rand()); + $_SESSION['compose_data_'.$COMPOSE_ID] = array( + 'id' => $COMPOSE_ID, + 'param' => rcube_utils::request2param(rcube_utils::INPUT_GET, 'task|action', true), + 'mailbox' => $RCMAIL->storage->get_folder(), + ); + $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; + + rcmail_process_compose_params($COMPOSE); + + // add attachments listed by message_compose hook + if (is_array($plugin['attachments'])) { + foreach ($plugin['attachments'] as $attach) { + // we have structured data + if (is_array($attach)) { + $attachment = $attach; + } + // only a file path is given + else { + $filename = basename($attach); + $attachment = array( + 'group' => $COMPOSE_ID, + 'name' => $filename, + 'mimetype' => rcube_mime::file_content_type($attach, $filename), + 'path' => $attach, + ); + } + + // save attachment if valid + if (($attachment['data'] && $attachment['name']) || ($attachment['path'] && file_exists($attachment['path']))) { + $attachment = rcmail::get_instance()->plugins->exec_hook('attachment_save', $attachment); + } + + if ($attachment['status'] && !$attachment['abort']) { + unset($attachment['data'], $attachment['status'], $attachment['abort']); + $COMPOSE['attachments'][$attachment['id']] = $attachment; + } + } + } + + // check if folder for saving sent messages exists and is subscribed (#1486802) + if ($sent_folder = $COMPOSE['param']['sent_mbox']) { + rcmail_check_sent_folder($sent_folder, true); + } + + // redirect to a unique URL with all parameters stored in session + $OUTPUT->redirect(array( + '_action' => 'compose', + '_id' => $COMPOSE['id'], + '_search' => $_REQUEST['_search'], + )); } @@ -112,153 +113,162 @@ $OUTPUT->add_label('nosubject', 'nosenderwarning', 'norecipientwarning', 'nosubj 'fileuploaderror', 'sendmessage', 'savenewresponse', 'responsename', 'responsetext', 'save', 'savingresponse', 'restoresavedcomposedata', 'restoremessage', 'delete', 'restore', 'ignore'); -$OUTPUT->set_env('compose_id', $COMPOSE['id']); -$OUTPUT->set_env('session_id', session_id()); $OUTPUT->set_pagetitle($RCMAIL->gettext('compose')); -// add config parameters to client script -if (!empty($CONFIG['drafts_mbox'])) { - $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']); - $OUTPUT->set_env('draft_autosave', $CONFIG['draft_autosave']); -} -// set current mailbox in client environment +$OUTPUT->set_env('compose_id', $COMPOSE['id']); +$OUTPUT->set_env('session_id', session_id()); $OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder()); $OUTPUT->set_env('top_posting', intval($RCMAIL->config->get('reply_mode')) > 0); $OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ','))); +$drafts_mbox = $RCMAIL->config->get('drafts_mbox'); +$config_show_sig = $RCMAIL->config->get('show_sig', 1); + +// add config parameters to client script +if (strlen($drafts_mbox)) { + $OUTPUT->set_env('drafts_mailbox', $drafts_mbox); + $OUTPUT->set_env('draft_autosave', $RCMAIL->config->get('draft_autosave')); +} + // default font for HTML editor $font = rcmail::font_defs($RCMAIL->config->get('default_font')); if ($font && !is_array($font)) { - $OUTPUT->set_env('default_font', $font); + $OUTPUT->set_env('default_font', $font); } // default font size for HTML editor if ($font_size = $RCMAIL->config->get('default_font_size')) { - $OUTPUT->set_env('default_font_size', $font_size); + $OUTPUT->set_env('default_font_size', $font_size); } // get reference message and set compose mode if ($msg_uid = $COMPOSE['param']['draft_uid']) { - $compose_mode = RCUBE_COMPOSE_DRAFT; - $OUTPUT->set_env('draft_id', $msg_uid); - $RCMAIL->storage->set_folder($CONFIG['drafts_mbox']); + $compose_mode = RCUBE_COMPOSE_DRAFT; + $OUTPUT->set_env('draft_id', $msg_uid); + $RCMAIL->storage->set_folder($drafts_mbox); } else if ($msg_uid = $COMPOSE['param']['reply_uid']) { - $compose_mode = RCUBE_COMPOSE_REPLY; + $compose_mode = RCUBE_COMPOSE_REPLY; } else if ($msg_uid = $COMPOSE['param']['forward_uid']) { - $compose_mode = RCUBE_COMPOSE_FORWARD; - $COMPOSE['forward_uid'] = $msg_uid; - $COMPOSE['as_attachment'] = !empty($COMPOSE['param']['attachment']); + $compose_mode = RCUBE_COMPOSE_FORWARD; + $COMPOSE['forward_uid'] = $msg_uid; + $COMPOSE['as_attachment'] = !empty($COMPOSE['param']['attachment']); } else if ($msg_uid = $COMPOSE['param']['uid']) { - $compose_mode = RCUBE_COMPOSE_EDIT; + $compose_mode = RCUBE_COMPOSE_EDIT; } $COMPOSE['mode'] = $compose_mode; $OUTPUT->set_env('compose_mode', $compose_mode); -$config_show_sig = $RCMAIL->config->get('show_sig', 1); if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) { - // don't add signature in draft/edit mode, we'll also not remove the old-one - // but only on page display, later we should be able to change identity/sig (#1489229) - if ($config_show_sig == 1 || $config_show_sig == 2) - $OUTPUT->set_env('show_sig_later', true); + // don't add signature in draft/edit mode, we'll also not remove the old-one + // but only on page display, later we should be able to change identity/sig (#1489229) + if ($config_show_sig == 1 || $config_show_sig == 2) { + $OUTPUT->set_env('show_sig_later', true); + } } else if ($config_show_sig == 1) - $OUTPUT->set_env('show_sig', true); + $OUTPUT->set_env('show_sig', true); else if ($config_show_sig == 2 && empty($compose_mode)) - $OUTPUT->set_env('show_sig', true); + $OUTPUT->set_env('show_sig', true); else if ($config_show_sig == 3 && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD)) - $OUTPUT->set_env('show_sig', true); + $OUTPUT->set_env('show_sig', true); // set line length for body wrapping $LINE_LENGTH = $RCMAIL->config->get('line_length', 72); -if (!empty($msg_uid) && empty($COMPOSE['as_attachment'])) -{ - $mbox_name = $RCMAIL->storage->get_folder(); - - // set format before rcube_message construction - // use the same format as for the message view - if (isset($_SESSION['msg_formats'][$mbox_name.':'.$msg_uid])) { - $RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$msg_uid]); - } - else { - $prefer_html = $CONFIG['prefer_html'] || $CONFIG['htmleditor'] || $compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT; - $RCMAIL->config->set('prefer_html', $prefer_html); - } - - $MESSAGE = new rcube_message($msg_uid); - - // make sure message is marked as read - if ($MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN'])) - $RCMAIL->storage->set_flag($msg_uid, 'SEEN'); - - if (!empty($MESSAGE->headers->charset)) - $RCMAIL->storage->set_charset($MESSAGE->headers->charset); - - if (!$MESSAGE->headers) { - // error - } - else if ($compose_mode == RCUBE_COMPOSE_REPLY) { - $COMPOSE['reply_uid'] = $msg_uid; - $COMPOSE['reply_msgid'] = $MESSAGE->headers->messageID; - $COMPOSE['references'] = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID); - - if (!empty($COMPOSE['param']['all'])) - $MESSAGE->reply_all = $COMPOSE['param']['all']; - - // Save the sent message in the same folder of the message being replied to - if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $COMPOSE['mailbox']) - && rcmail_check_sent_folder($sent_folder, false) - ) { - $COMPOSE['param']['sent_mbox'] = $sent_folder; +if (!empty($msg_uid) && empty($COMPOSE['as_attachment'])) { + $mbox_name = $RCMAIL->storage->get_folder(); + + // set format before rcube_message construction + // use the same format as for the message view + if (isset($_SESSION['msg_formats'][$mbox_name.':'.$msg_uid])) { + $RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$msg_uid]); } - } - else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { - if ($compose_mode == RCUBE_COMPOSE_DRAFT) { - if ($draft_info = $MESSAGE->headers->get('x-draft-info')) { - // get reply_uid/forward_uid to flag the original message when sending - $info = rcmail_draftinfo_decode($draft_info); + else { + $prefer_html = $RCMAIL->config->get('prefer_html') || $RCMAIL->config->get('htmleditor') + || $compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT; - if ($info['type'] == 'reply') - $COMPOSE['reply_uid'] = $info['uid']; - else if ($info['type'] == 'forward') - $COMPOSE['forward_uid'] = $info['uid']; + $RCMAIL->config->set('prefer_html', $prefer_html); + } + + $MESSAGE = new rcube_message($msg_uid); - $COMPOSE['mailbox'] = $info['folder']; + // make sure message is marked as read + if ($MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN'])) { + $RCMAIL->storage->set_flag($msg_uid, 'SEEN'); + } + + if (!empty($MESSAGE->headers->charset)) { + $RCMAIL->storage->set_charset($MESSAGE->headers->charset); + } + + if (!$MESSAGE->headers) { + // error + } + else if ($compose_mode == RCUBE_COMPOSE_REPLY) { + $COMPOSE['reply_uid'] = $msg_uid; + $COMPOSE['reply_msgid'] = $MESSAGE->headers->messageID; + $COMPOSE['references'] = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID); + + if (!empty($COMPOSE['param']['all'])) { + $MESSAGE->reply_all = $COMPOSE['param']['all']; + } // Save the sent message in the same folder of the message being replied to - if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $info['folder']) - && rcmail_check_sent_folder($sent_folder, false) + if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $COMPOSE['mailbox']) + && rcmail_check_sent_folder($sent_folder, false) ) { - $COMPOSE['param']['sent_mbox'] = $sent_folder; + $COMPOSE['param']['sent_mbox'] = $sent_folder; } - } + } + else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { + if ($compose_mode == RCUBE_COMPOSE_DRAFT) { + if ($draft_info = $MESSAGE->headers->get('x-draft-info')) { + // get reply_uid/forward_uid to flag the original message when sending + $info = rcmail_draftinfo_decode($draft_info); + + if ($info['type'] == 'reply') + $COMPOSE['reply_uid'] = $info['uid']; + else if ($info['type'] == 'forward') + $COMPOSE['forward_uid'] = $info['uid']; + + $COMPOSE['mailbox'] = $info['folder']; + + // Save the sent message in the same folder of the message being replied to + if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $info['folder']) + && rcmail_check_sent_folder($sent_folder, false) + ) { + $COMPOSE['param']['sent_mbox'] = $sent_folder; + } + } - $COMPOSE['param']['message-id'] = $MESSAGE->headers->get('message-id'); + $COMPOSE['param']['message-id'] = $MESSAGE->headers->get('message-id'); - // use message UID as draft_id - $OUTPUT->set_env('draft_id', $msg_uid); - } + // use message UID as draft_id + $OUTPUT->set_env('draft_id', $msg_uid); + } - if ($in_reply_to = $MESSAGE->headers->get('in-reply-to')) - $COMPOSE['reply_msgid'] = '<' . $in_reply_to . '>'; + if ($in_reply_to = $MESSAGE->headers->get('in-reply-to')) { + $COMPOSE['reply_msgid'] = '<' . $in_reply_to . '>'; + } - $COMPOSE['references'] = $MESSAGE->headers->references; - } + $COMPOSE['references'] = $MESSAGE->headers->references; + } } else { - $MESSAGE = new stdClass(); - - // apply mailto: URL parameters - if (!empty($COMPOSE['param']['in-reply-to'])) { - $COMPOSE['reply_msgid'] = '<' . $COMPOSE['param']['in-reply-to'] . '>'; - } - if (!empty($COMPOSE['param']['references'])) { - $COMPOSE['references'] = $COMPOSE['param']['references']; - } + $MESSAGE = new stdClass(); + + // apply mailto: URL parameters + if (!empty($COMPOSE['param']['in-reply-to'])) { + $COMPOSE['reply_msgid'] = '<' . $COMPOSE['param']['in-reply-to'] . '>'; + } + + if (!empty($COMPOSE['param']['references'])) { + $COMPOSE['references'] = $COMPOSE['param']['references']; + } } $MESSAGE->compose = array(); @@ -268,16 +278,16 @@ $MESSAGE->identities = $RCMAIL->user->list_identities(null, true); // Set From field value if (!empty($_POST['_from'])) { - $MESSAGE->compose['from'] = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST); + $MESSAGE->compose['from'] = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST); } else if (!empty($COMPOSE['param']['from'])) { - $MESSAGE->compose['from'] = $COMPOSE['param']['from']; + $MESSAGE->compose['from'] = $COMPOSE['param']['from']; } else if (count($MESSAGE->identities)) { - $ident = rcmail_identity_select($MESSAGE, $MESSAGE->identities, $compose_mode); + $ident = rcmail_identity_select($MESSAGE, $MESSAGE->identities, $compose_mode); - $MESSAGE->compose['from_email'] = $ident['email']; - $MESSAGE->compose['from'] = $ident['identity_id']; + $MESSAGE->compose['from_email'] = $ident['email']; + $MESSAGE->compose['from'] = $ident['identity_id']; } // Set other headers @@ -286,124 +296,123 @@ $parts = array('to', 'cc', 'bcc', 'replyto', 'followupto'); $separator = trim($RCMAIL->config->get('recipients_separator', ',')) . ' '; foreach ($parts as $header) { - $fvalue = ''; - $decode_header = true; - - // we have a set of recipients stored is session - if ($header == 'to' && ($mailto_id = $COMPOSE['param']['mailto']) - && $_SESSION['mailto'][$mailto_id] - ) { - $fvalue = urldecode($_SESSION['mailto'][$mailto_id]); - $decode_header = false; - - // make session to not grow up too much - unset($_SESSION['mailto'][$mailto_id]); - $COMPOSE['param']['to'] = $fvalue; - } - else if (!empty($_POST['_'.$header])) { - $fvalue = rcube_utils::get_input_value('_'.$header, rcube_utils::INPUT_POST, TRUE); - } - else if (!empty($COMPOSE['param'][$header])) { - $fvalue = $COMPOSE['param'][$header]; - } - else if ($compose_mode == RCUBE_COMPOSE_REPLY) { - // get recipent address(es) out of the message headers - if ($header == 'to') { - $mailfollowup = $MESSAGE->headers->others['mail-followup-to']; - $mailreplyto = $MESSAGE->headers->others['mail-reply-to']; - - // Reply to mailing list... - if ($MESSAGE->reply_all == 'list' && $mailfollowup) - $fvalue = $mailfollowup; - else if ($MESSAGE->reply_all == 'list' - && preg_match('/<mailto:([^>]+)>/i', $MESSAGE->headers->others['list-post'], $m)) - $fvalue = $m[1]; - // Reply to... - else if ($MESSAGE->reply_all && $mailfollowup) - $fvalue = $mailfollowup; - else if ($mailreplyto) - $fvalue = $mailreplyto; - else if (!empty($MESSAGE->headers->replyto)) - $fvalue = $MESSAGE->headers->replyto; - else if (!empty($MESSAGE->headers->from)) - $fvalue = $MESSAGE->headers->from; - - // Reply to message sent by yourself (#1487074, #1489230) - if (!empty($ident) && in_array($ident['ident'], array($fvalue, $MESSAGE->headers->from))) { - $fvalue = $MESSAGE->headers->to; - } - } - // add recipient of original message if reply to all - else if ($header == 'cc' && !empty($MESSAGE->reply_all) && $MESSAGE->reply_all != 'list') { - if ($v = $MESSAGE->headers->to) - $fvalue .= $v; - if ($v = $MESSAGE->headers->cc) - $fvalue .= (!empty($fvalue) ? $separator : '') . $v; - // Use Sender header (#1489011) - if (($v = $MESSAGE->headers->get('Sender', false)) && strpos($v, '-bounces@') === false) - $fvalue .= (!empty($fvalue) ? $separator : '') . $v; - - // When To: and Reply-To: are the same we add From: address to the list (#1489037) - if ($v = $MESSAGE->headers->from) { - $from = rcube_mime::decode_address_list($v, null, false, $MESSAGE->headers->charset, true); - $to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, false, $MESSAGE->headers->charset, true); - $replyto = rcube_mime::decode_address_list($MESSAGE->headers->replyto, null, false, $MESSAGE->headers->charset, true); - - if (count($replyto) && !count(array_diff($to, $replyto)) && count(array_diff($from, $to))) { - $fvalue .= (!empty($fvalue) ? $separator : '') . $v; - } - } - } - } - else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { - // get drafted headers - if ($header=='to' && !empty($MESSAGE->headers->to)) - $fvalue = $MESSAGE->get_header('to', true); - else if ($header=='cc' && !empty($MESSAGE->headers->cc)) - $fvalue = $MESSAGE->get_header('cc', true); - else if ($header=='bcc' && !empty($MESSAGE->headers->bcc)) - $fvalue = $MESSAGE->get_header('bcc', true); - else if ($header=='replyto' && !empty($MESSAGE->headers->others['mail-reply-to'])) - $fvalue = $MESSAGE->get_header('mail-reply-to'); - else if ($header=='replyto' && !empty($MESSAGE->headers->replyto)) - $fvalue = $MESSAGE->get_header('reply-to'); - else if ($header=='followupto' && !empty($MESSAGE->headers->others['mail-followup-to'])) - $fvalue = $MESSAGE->get_header('mail-followup-to'); - } - - // split recipients and put them back together in a unique way - if (!empty($fvalue) && in_array($header, array('to', 'cc', 'bcc'))) { - $to_addresses = rcube_mime::decode_address_list($fvalue, null, $decode_header, $MESSAGE->headers->charset); - $fvalue = array(); - - foreach ($to_addresses as $addr_part) { - if (empty($addr_part['mailto'])) - continue; - - $mailto = format_email(rcube_utils::idn_to_utf8($addr_part['mailto'])); - - if (!in_array($mailto, $a_recipients) - && ( - $header == 'to' - || $compose_mode != RCUBE_COMPOSE_REPLY - || empty($MESSAGE->compose['from_email']) - || $mailto != $MESSAGE->compose['from_email'] - ) - ) { - if ($addr_part['name'] && $addr_part['mailto'] != $addr_part['name']) - $string = format_email_recipient($mailto, $addr_part['name']); - else - $string = $mailto; + $fvalue = ''; + $decode_header = true; + + // we have a set of recipients stored is session + if ($header == 'to' && ($mailto_id = $COMPOSE['param']['mailto']) + && $_SESSION['mailto'][$mailto_id] + ) { + $fvalue = urldecode($_SESSION['mailto'][$mailto_id]); + $decode_header = false; - $fvalue[] = $string; - $a_recipients[] = $addr_part['mailto']; - } + // make session to not grow up too much + unset($_SESSION['mailto'][$mailto_id]); + $COMPOSE['param']['to'] = $fvalue; + } + else if (!empty($_POST['_'.$header])) { + $fvalue = rcube_utils::get_input_value('_'.$header, rcube_utils::INPUT_POST, TRUE); + } + else if (!empty($COMPOSE['param'][$header])) { + $fvalue = $COMPOSE['param'][$header]; } + else if ($compose_mode == RCUBE_COMPOSE_REPLY) { + // get recipent address(es) out of the message headers + if ($header == 'to') { + $mailfollowup = $MESSAGE->headers->others['mail-followup-to']; + $mailreplyto = $MESSAGE->headers->others['mail-reply-to']; + + // Reply to mailing list... + if ($MESSAGE->reply_all == 'list' && $mailfollowup) + $fvalue = $mailfollowup; + else if ($MESSAGE->reply_all == 'list' + && preg_match('/<mailto:([^>]+)>/i', $MESSAGE->headers->others['list-post'], $m)) + $fvalue = $m[1]; + // Reply to... + else if ($MESSAGE->reply_all && $mailfollowup) + $fvalue = $mailfollowup; + else if ($mailreplyto) + $fvalue = $mailreplyto; + else if (!empty($MESSAGE->headers->replyto)) + $fvalue = $MESSAGE->headers->replyto; + else if (!empty($MESSAGE->headers->from)) + $fvalue = $MESSAGE->headers->from; + + // Reply to message sent by yourself (#1487074, #1489230) + if (!empty($ident) && in_array($ident['ident'], array($fvalue, $MESSAGE->headers->from))) { + $fvalue = $MESSAGE->headers->to; + } + } + // add recipient of original message if reply to all + else if ($header == 'cc' && !empty($MESSAGE->reply_all) && $MESSAGE->reply_all != 'list') { + if ($v = $MESSAGE->headers->to) + $fvalue .= $v; + if ($v = $MESSAGE->headers->cc) + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + // Use Sender header (#1489011) + if (($v = $MESSAGE->headers->get('Sender', false)) && strpos($v, '-bounces@') === false) + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + + // When To: and Reply-To: are the same we add From: address to the list (#1489037) + if ($v = $MESSAGE->headers->from) { + $from = rcube_mime::decode_address_list($v, null, false, $MESSAGE->headers->charset, true); + $to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, false, $MESSAGE->headers->charset, true); + $replyto = rcube_mime::decode_address_list($MESSAGE->headers->replyto, null, false, $MESSAGE->headers->charset, true); + + if (count($replyto) && !count(array_diff($to, $replyto)) && count(array_diff($from, $to))) { + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + } + } + } + } + else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { + // get drafted headers + if ($header=='to' && !empty($MESSAGE->headers->to)) + $fvalue = $MESSAGE->get_header('to', true); + else if ($header=='cc' && !empty($MESSAGE->headers->cc)) + $fvalue = $MESSAGE->get_header('cc', true); + else if ($header=='bcc' && !empty($MESSAGE->headers->bcc)) + $fvalue = $MESSAGE->get_header('bcc', true); + else if ($header=='replyto' && !empty($MESSAGE->headers->others['mail-reply-to'])) + $fvalue = $MESSAGE->get_header('mail-reply-to'); + else if ($header=='replyto' && !empty($MESSAGE->headers->replyto)) + $fvalue = $MESSAGE->get_header('reply-to'); + else if ($header=='followupto' && !empty($MESSAGE->headers->others['mail-followup-to'])) + $fvalue = $MESSAGE->get_header('mail-followup-to'); + } + + // split recipients and put them back together in a unique way + if (!empty($fvalue) && in_array($header, array('to', 'cc', 'bcc'))) { + $to_addresses = rcube_mime::decode_address_list($fvalue, null, $decode_header, $MESSAGE->headers->charset); + $fvalue = array(); - $fvalue = implode($separator, $fvalue); - } + foreach ($to_addresses as $addr_part) { + if (empty($addr_part['mailto'])) { + continue; + } - $MESSAGE->compose[$header] = $fvalue; + $mailto = format_email(rcube_utils::idn_to_utf8($addr_part['mailto'])); + + if (!in_array($mailto, $a_recipients) + && ($header == 'to' + || $compose_mode != RCUBE_COMPOSE_REPLY + || empty($MESSAGE->compose['from_email']) + || $mailto != $MESSAGE->compose['from_email']) + ) { + if ($addr_part['name'] && $addr_part['mailto'] != $addr_part['name']) + $string = format_email_recipient($mailto, $addr_part['name']); + else + $string = $mailto; + + $fvalue[] = $string; + $a_recipients[] = $addr_part['mailto']; + } + } + + $fvalue = implode($separator, $fvalue); + } + + $MESSAGE->compose[$header] = $fvalue; } unset($a_recipients); @@ -411,327 +420,354 @@ unset($a_recipients); $MESSAGE_BODY = rcmail_prepare_message_body(); +// register UI objects +$OUTPUT->add_handlers(array( + 'composeheaders' => 'rcmail_compose_headers', + 'composesubject' => 'rcmail_compose_subject', + 'composebody' => 'rcmail_compose_body', + 'composeattachmentlist' => 'rcmail_compose_attachment_list', + 'composeattachmentform' => 'rcmail_compose_attachment_form', + 'composeattachment' => 'rcmail_compose_attachment_field', + 'filedroparea' => 'compose_file_drop_area', + 'priorityselector' => 'rcmail_priority_selector', + 'editorselector' => 'rcmail_editor_selector', + 'receiptcheckbox' => 'rcmail_receipt_checkbox', + 'dsncheckbox' => 'rcmail_dsn_checkbox', + 'storetarget' => 'rcmail_store_target_selection', + 'addressbooks' => 'rcmail_addressbook_list', + 'addresslist' => 'rcmail_contacts_list', + 'responseslist' => 'rcmail_compose_responses_list', +)); + +$OUTPUT->send('compose'); + + /****** compose mode functions ********/ // process compose request parameters function rcmail_process_compose_params(&$COMPOSE) { - if ($COMPOSE['param']['to']) { - $mailto = explode('?', $COMPOSE['param']['to'], 2); + if ($COMPOSE['param']['to']) { + $mailto = explode('?', $COMPOSE['param']['to'], 2); - // #1486037: remove "mailto:" prefix - $COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $mailto[0]); + // #1486037: remove "mailto:" prefix + $COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $mailto[0]); - // Supported case-insensitive tokens in mailto URL - $url_tokens = array('to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'body'); + // Supported case-insensitive tokens in mailto URL + $url_tokens = array('to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'body'); - if (!empty($mailto[1])) { - parse_str($mailto[1], $query); - foreach ($query as $f => $val) { - if (($key = array_search(strtolower($f), $url_tokens)) !== false) { - $f = $url_tokens[$key]; - } + if (!empty($mailto[1])) { + parse_str($mailto[1], $query); + foreach ($query as $f => $val) { + if (($key = array_search(strtolower($f), $url_tokens)) !== false) { + $f = $url_tokens[$key]; + } - // merge mailto: addresses with addresses from 'to' parameter - if ($f == 'to' && !empty($COMPOSE['param']['to'])) { - $to_addresses = rcube_mime::decode_address_list($COMPOSE['param']['to'], null, true, null, true); - $add_addresses = rcube_mime::decode_address_list($val, null, true); - foreach ($add_addresses as $addr) { - if (!in_array($addr['mailto'], $to_addresses)) { - $to_addresses[] = $addr['mailto']; - $COMPOSE['param']['to'] = (!empty($to_addresses) ? ', ' : '') . $addr['string']; + // merge mailto: addresses with addresses from 'to' parameter + if ($f == 'to' && !empty($COMPOSE['param']['to'])) { + $to_addresses = rcube_mime::decode_address_list($COMPOSE['param']['to'], null, true, null, true); + $add_addresses = rcube_mime::decode_address_list($val, null, true); + + foreach ($add_addresses as $addr) { + if (!in_array($addr['mailto'], $to_addresses)) { + $to_addresses[] = $addr['mailto']; + $COMPOSE['param']['to'] = (!empty($to_addresses) ? ', ' : '') . $addr['string']; + } + } + } + else { + $COMPOSE['param'][$f] = $val; + } } - } - } - else { - $COMPOSE['param'][$f] = $val; } - } } - } - // clean HTML message body which can be submitted by URL - if ($COMPOSE['param']['body']) { - $COMPOSE['param']['body'] = rcmail_wash_html($COMPOSE['param']['body'], array('safe' => false, 'inline_html' => true), array()); - } + // clean HTML message body which can be submitted by URL + if (!empty($COMPOSE['param']['body'])) { + $COMPOSE['param']['body'] = rcmail_wash_html($COMPOSE['param']['body'], array('safe' => false, 'inline_html' => true), array()); + } - $RCMAIL = rcmail::get_instance(); + $RCMAIL = rcmail::get_instance(); - // select folder where to save the sent message - $COMPOSE['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox'); + // select folder where to save the sent message + $COMPOSE['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox'); - // pipe compose parameters thru plugins - $plugin = $RCMAIL->plugins->exec_hook('message_compose', $COMPOSE); - $COMPOSE['param'] = array_merge($COMPOSE['param'], $plugin['param']); + // pipe compose parameters thru plugins + $plugin = $RCMAIL->plugins->exec_hook('message_compose', $COMPOSE); + $COMPOSE['param'] = array_merge($COMPOSE['param'], $plugin['param']); } function rcmail_compose_headers($attrib) { - global $RCMAIL, $MESSAGE; + global $RCMAIL, $MESSAGE; - list($form_start,) = get_form_tags($attrib); + list($form_start,) = get_form_tags($attrib); - $out = ''; - $part = strtolower($attrib['part']); + $out = ''; + $part = strtolower($attrib['part']); - switch ($part) - { + switch ($part) { case 'from': - return $form_start . rcmail_compose_header_from($attrib); + return $form_start . rcmail_compose_header_from($attrib); case 'to': case 'cc': case 'bcc': - $fname = '_' . $part; - $header = $param = $part; + $fname = '_' . $part; + $header = $param = $part; - $allow_attrib = array('id', 'class', 'style', 'cols', 'rows', 'tabindex'); - $field_type = 'html_textarea'; - break; + $allow_attrib = array('id', 'class', 'style', 'cols', 'rows', 'tabindex'); + $field_type = 'html_textarea'; + break; case 'replyto': case 'reply-to': - $fname = '_replyto'; - $param = 'replyto'; - $header = 'reply-to'; + $fname = '_replyto'; + $param = 'replyto'; + $header = 'reply-to'; case 'followupto': case 'followup-to': - if (!$fname) { - $fname = '_followupto'; - $param = 'followupto'; - $header = 'mail-followup-to'; - } - - $allow_attrib = array('id', 'class', 'style', 'size', 'tabindex'); - $field_type = 'html_inputfield'; - break; - } - - if ($fname && $field_type) - { - // pass the following attributes to the form class - $field_attrib = array('name' => $fname, 'spellcheck' => 'false'); - foreach ($attrib as $attr => $value) - if (in_array($attr, $allow_attrib)) - $field_attrib[$attr] = $value; + if (!$fname) { + $fname = '_followupto'; + $param = 'followupto'; + $header = 'mail-followup-to'; + } + + $allow_attrib = array('id', 'class', 'style', 'size', 'tabindex'); + $field_type = 'html_inputfield'; + break; + } + + if ($fname && $field_type) { + // pass the following attributes to the form class + $field_attrib = array('name' => $fname, 'spellcheck' => 'false'); + foreach ($attrib as $attr => $value) { + if (in_array($attr, $allow_attrib)) { + $field_attrib[$attr] = $value; + } + } - // create teaxtarea object - $input = new $field_type($field_attrib); - $out = $input->show($MESSAGE->compose[$param]); - } + // create teaxtarea object + $input = new $field_type($field_attrib); + $out = $input->show($MESSAGE->compose[$param]); + } - if ($form_start) - $out = $form_start.$out; + if ($form_start) { + $out = $form_start . $out; + } - // configure autocompletion - $RCMAIL->autocomplete_init(); + // configure autocompletion + $RCMAIL->autocomplete_init(); - return $out; + return $out; } function rcmail_compose_header_from($attrib) { - global $MESSAGE, $OUTPUT, $RCMAIL, $COMPOSE, $compose_mode; - - // pass the following attributes to the form class - $field_attrib = array('name' => '_from'); - foreach ($attrib as $attr => $value) - if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex'))) - $field_attrib[$attr] = $value; - - if (count($MESSAGE->identities)) - { - $a_signatures = array(); - $identities = array(); - $separator = intval($RCMAIL->config->get('reply_mode')) > 0 - && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- '; - - $field_attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.".change_identity(this)"; - $select_from = new html_select($field_attrib); - - // create SELECT element - foreach ($MESSAGE->identities as $sql_arr) - { - $identity_id = $sql_arr['identity_id']; - $select_from->add(format_email_recipient($sql_arr['email'], $sql_arr['name']), $identity_id); - - // add signature to array - if (!empty($sql_arr['signature']) && empty($COMPOSE['param']['nosig'])) - { - $text = $html = $sql_arr['signature']; - - if ($sql_arr['html_signature']) { - $h2t = new rcube_html2text($sql_arr['signature'], false, false); - $text = trim($h2t->get_text()); - } - else { - $html = htmlentities($html, ENT_NOQUOTES, RCUBE_CHARSET); - } + global $MESSAGE, $OUTPUT, $RCMAIL, $COMPOSE, $compose_mode; - if (!preg_match('/^--[ -]\r?\n/m', $text)) { - $text = $separator . "\n" . $text; - $html = $separator . "<br>" . $html; + // pass the following attributes to the form class + $field_attrib = array('name' => '_from'); + foreach ($attrib as $attr => $value) { + if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex'))) { + $field_attrib[$attr] = $value; } + } - if (!$sql_arr['html_signature']) { - $html = "<pre>" . $html . "</pre>"; + if (count($MESSAGE->identities)) { + $a_signatures = array(); + $identities = array(); + $separator = intval($RCMAIL->config->get('reply_mode')) > 0 + && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- '; + + $field_attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.".change_identity(this)"; + $select_from = new html_select($field_attrib); + + // create SELECT element + foreach ($MESSAGE->identities as $sql_arr) { + $identity_id = $sql_arr['identity_id']; + $select_from->add(format_email_recipient($sql_arr['email'], $sql_arr['name']), $identity_id); + + // add signature to array + if (!empty($sql_arr['signature']) && empty($COMPOSE['param']['nosig'])) { + $text = $html = $sql_arr['signature']; + + if ($sql_arr['html_signature']) { + $h2t = new rcube_html2text($sql_arr['signature'], false, false); + $text = trim($h2t->get_text()); + } + else { + $html = htmlentities($html, ENT_NOQUOTES, RCUBE_CHARSET); + } + + if (!preg_match('/^--[ -]\r?\n/m', $text)) { + $text = $separator . "\n" . $text; + $html = $separator . "<br>" . $html; + } + + if (!$sql_arr['html_signature']) { + $html = "<pre>" . $html . "</pre>"; + } + + $a_signatures[$identity_id]['text'] = $text; + $a_signatures[$identity_id]['html'] = $html; + } + + // add bcc and reply-to + if (!empty($sql_arr['reply-to'])) { + $identities[$identity_id]['replyto'] = $sql_arr['reply-to']; + } + if (!empty($sql_arr['bcc'])) { + $identities[$identity_id]['bcc'] = $sql_arr['bcc']; + } } - $a_signatures[$identity_id]['text'] = $text; - $a_signatures[$identity_id]['html'] = $html; - } - - // add bcc and reply-to - if (!empty($sql_arr['reply-to'])) { - $identities[$identity_id]['replyto'] = $sql_arr['reply-to']; - } - if (!empty($sql_arr['bcc'])) { - $identities[$identity_id]['bcc'] = $sql_arr['bcc']; - } - } - - $out = $select_from->show($MESSAGE->compose['from']); - - // add signatures to client - $OUTPUT->set_env('signatures', $a_signatures); - $OUTPUT->set_env('identities', $identities); - } - // no identities, display text input field - else { - $field_attrib['class'] = 'from_address'; - $input_from = new html_inputfield($field_attrib); - $out = $input_from->show($MESSAGE->compose['from']); - } - - return $out; + $out = $select_from->show($MESSAGE->compose['from']); + + // add signatures to client + $OUTPUT->set_env('signatures', $a_signatures); + $OUTPUT->set_env('identities', $identities); + } + // no identities, display text input field + else { + $field_attrib['class'] = 'from_address'; + $input_from = new html_inputfield($field_attrib); + $out = $input_from->show($MESSAGE->compose['from']); + } + + return $out; } function rcmail_compose_editor_mode() { - global $RCMAIL, $compose_mode; - static $useHtml; + global $RCMAIL, $compose_mode; + static $useHtml; - if ($useHtml !== null) - return $useHtml; + if ($useHtml !== null) { + return $useHtml; + } - $html_editor = intval($RCMAIL->config->get('htmleditor')); - - if (isset($_POST['_is_html'])) { - $useHtml = !empty($_POST['_is_html']); - } - else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { - $useHtml = rcmail_message_is_html(); - } - else if ($compose_mode == RCUBE_COMPOSE_REPLY) { - $useHtml = ($html_editor == 1 || ($html_editor >= 2 && rcmail_message_is_html())); - } - else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { - $useHtml = ($html_editor == 1 || ($html_editor == 3 && rcmail_message_is_html())); - } - else { - $useHtml = ($html_editor == 1); - } - - return $useHtml; + $html_editor = intval($RCMAIL->config->get('htmleditor')); + + if (isset($_POST['_is_html'])) { + $useHtml = !empty($_POST['_is_html']); + } + else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { + $useHtml = rcmail_message_is_html(); + } + else if ($compose_mode == RCUBE_COMPOSE_REPLY) { + $useHtml = ($html_editor == 1 || ($html_editor >= 2 && rcmail_message_is_html())); + } + else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { + $useHtml = ($html_editor == 1 || ($html_editor == 3 && rcmail_message_is_html())); + } + else { + $useHtml = ($html_editor == 1); + } + + return $useHtml; } function rcmail_message_is_html() { global $RCMAIL, $MESSAGE; + return $RCMAIL->config->get('prefer_html') && ($MESSAGE instanceof rcube_message) && $MESSAGE->has_html_part(true); } function rcmail_prepare_message_body() { - global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $HTML_MODE; - - // use posted message body - if (!empty($_POST['_message'])) { - $body = rcube_utils::get_input_value('_message', rcube_utils::INPUT_POST, true); - $isHtml = (bool) rcube_utils::get_input_value('_is_html', rcube_utils::INPUT_POST); - } - else if ($COMPOSE['param']['body']) { - $body = $COMPOSE['param']['body']; - $isHtml = (bool) $COMPOSE['param']['html']; - } - // forward as attachment - else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $COMPOSE['as_attachment']) { - $isHtml = rcmail_compose_editor_mode(); - $body = ''; - rcmail_write_forward_attachments(); - } - // reply/edit/draft/forward - else if ($compose_mode && ($compose_mode != RCUBE_COMPOSE_REPLY || intval($RCMAIL->config->get('reply_mode')) != -1)) { - $isHtml = rcmail_compose_editor_mode(); - $messages = array(); + global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $HTML_MODE; - if (!empty($MESSAGE->parts)) { - // collect IDs of message/rfc822 parts - if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) { - foreach ($MESSAGE->attachments as $part) { - if ($part->mimetype == 'message/rfc822') { - $messages[] = $part->mime_id; - } - } - } + // use posted message body + if (!empty($_POST['_message'])) { + $body = rcube_utils::get_input_value('_message', rcube_utils::INPUT_POST, true); + $isHtml = (bool) rcube_utils::get_input_value('_is_html', rcube_utils::INPUT_POST); + } + else if ($COMPOSE['param']['body']) { + $body = $COMPOSE['param']['body']; + $isHtml = (bool) $COMPOSE['param']['html']; + } + // forward as attachment + else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $COMPOSE['as_attachment']) { + $isHtml = rcmail_compose_editor_mode(); + $body = ''; - foreach ($MESSAGE->parts as $part) { - // skip no-content and attachment parts (#1488557) - if ($part->type != 'content' || !$part->size || $MESSAGE->is_attachment($part)) { - continue; - } + rcmail_write_forward_attachments(); + } + // reply/edit/draft/forward + else if ($compose_mode && ($compose_mode != RCUBE_COMPOSE_REPLY || intval($RCMAIL->config->get('reply_mode')) != -1)) { + $isHtml = rcmail_compose_editor_mode(); + $messages = array(); + + if (!empty($MESSAGE->parts)) { + // collect IDs of message/rfc822 parts + if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) { + foreach ($MESSAGE->attachments as $part) { + if ($part->mimetype == 'message/rfc822') { + $messages[] = $part->mime_id; + } + } + } + + foreach ($MESSAGE->parts as $part) { + // skip no-content and attachment parts (#1488557) + if ($part->type != 'content' || !$part->size || $MESSAGE->is_attachment($part)) { + continue; + } + + // skip all content parts inside the message/rfc822 part in DRAFT/EDIT mode + foreach ($messages as $mimeid) { + if (strpos($part->mime_id, $mimeid . '.') === 0) { + continue 2; + } + } - // skip all content parts inside the message/rfc822 part in DRAFT/EDIT mode - foreach ($messages as $mimeid) { - if (strpos($part->mime_id, $mimeid . '.') === 0) { - continue 2; - } + if ($part_body = rcmail_compose_part_body($part, $isHtml)) { + $body .= ($body ? ($isHtml ? '<br/>' : "\n") : '') . $part_body; + } + } + } + else { + $body = rcmail_compose_part_body($MESSAGE, $isHtml); } - if ($part_body = rcmail_compose_part_body($part, $isHtml)) { - $body .= ($body ? ($isHtml ? '<br/>' : "\n") : '') . $part_body; + // compose reply-body + if ($compose_mode == RCUBE_COMPOSE_REPLY) + $body = rcmail_create_reply_body($body, $isHtml); + // forward message body inline + else if ($compose_mode == RCUBE_COMPOSE_FORWARD) + $body = rcmail_create_forward_body($body, $isHtml); + // load draft message body + else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) + $body = rcmail_create_draft_body($body, $isHtml); + } + else { // new message + $isHtml = rcmail_compose_editor_mode(); + } + + $plugin = $RCMAIL->plugins->exec_hook('message_compose_body', + array('body' => $body, 'html' => $isHtml, 'mode' => $compose_mode)); + + $body = $plugin['body']; + unset($plugin); + + // add blocked.gif attachment (#1486516) + if ($isHtml && preg_match('#<img src="\./program/resources/blocked\.gif"#', $body)) { + if ($attachment = rcmail_save_image('program/resources/blocked.gif', 'image/gif')) { + $COMPOSE['attachments'][$attachment['id']] = $attachment; + $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', + $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); + $body = preg_replace('#\./program/resources/blocked\.gif#', $url, $body); } - } } - else { - $body = rcmail_compose_part_body($MESSAGE, $isHtml); - } - - // compose reply-body - if ($compose_mode == RCUBE_COMPOSE_REPLY) - $body = rcmail_create_reply_body($body, $isHtml); - // forward message body inline - else if ($compose_mode == RCUBE_COMPOSE_FORWARD) - $body = rcmail_create_forward_body($body, $isHtml); - // load draft message body - else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) - $body = rcmail_create_draft_body($body, $isHtml); - } - else { // new message - $isHtml = rcmail_compose_editor_mode(); - } - - $plugin = $RCMAIL->plugins->exec_hook('message_compose_body', - array('body' => $body, 'html' => $isHtml, 'mode' => $compose_mode)); - $body = $plugin['body']; - unset($plugin); - - // add blocked.gif attachment (#1486516) - if ($isHtml && preg_match('#<img src="\./program/resources/blocked\.gif"#', $body)) { - if ($attachment = rcmail_save_image('program/resources/blocked.gif', 'image/gif')) { - $COMPOSE['attachments'][$attachment['id']] = $attachment; - $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', - $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); - $body = preg_replace('#\./program/resources/blocked\.gif#', $url, $body); - } - } - - $HTML_MODE = $isHtml; - - return $body; + + $HTML_MODE = $isHtml; + + return $body; } function rcmail_compose_part_body($part, $isHtml = false) @@ -817,882 +853,903 @@ function rcmail_compose_part_body($part, $isHtml = false) function rcmail_compose_body($attrib) { - global $RCMAIL, $CONFIG, $OUTPUT, $HTML_MODE, $MESSAGE_BODY; - - list($form_start, $form_end) = get_form_tags($attrib); - unset($attrib['form']); - - if (empty($attrib['id'])) - $attrib['id'] = 'rcmComposeBody'; - - $attrib['name'] = '_message'; - - $isHtml = $HTML_MODE; - - $out = $form_start ? "$form_start\n" : ''; - - $saveid = new html_hiddenfield(array('name' => '_draft_saveid', 'value' => $RCMAIL->output->get_env('draft_id'))); - $out .= $saveid->show(); - - $drafttoggle = new html_hiddenfield(array('name' => '_draft', 'value' => 'yes')); - $out .= $drafttoggle->show(); - - $msgtype = new html_hiddenfield(array('name' => '_is_html', 'value' => ($isHtml?"1":"0"))); - $out .= $msgtype->show(); - - $framed = new html_hiddenfield(array('name' => '_framed', 'value' => '1')); - $out .= $framed->show(); - - // If desired, set this textarea to be editable by TinyMCE - if ($isHtml) { - $MESSAGE_BODY = htmlentities($MESSAGE_BODY, ENT_NOQUOTES, RCUBE_CHARSET); - $attrib['class'] = 'mce_editor'; - $attrib['is_escaped'] = true; - $textarea = new html_textarea($attrib); - $out .= $textarea->show($MESSAGE_BODY); - } - else { - $textarea = new html_textarea($attrib); - $out .= $textarea->show(''); - // quote plain text, inject into textarea - $table = get_html_translation_table(HTML_SPECIALCHARS); - $MESSAGE_BODY = strtr($MESSAGE_BODY, $table); - $out = substr($out, 0, -11) . $MESSAGE_BODY . '</textarea>'; - } - - $out .= $form_end ? "\n$form_end" : ''; - - $OUTPUT->set_env('composebody', $attrib['id']); - - // include HTML editor - $RCMAIL->html_editor(); - - // Set language list - if (!empty($CONFIG['enable_spellcheck'])) { - $engine = new rcube_spellchecker(); - $dictionary = (bool) $RCMAIL->config->get('spellcheck_dictionary'); - $spellcheck_langs = $engine->languages(); - $lang = $_SESSION['language']; - - // if not found in the list, try with two-letter code - if (!$spellcheck_langs[$lang]) - $lang = strtolower(substr($lang, 0, 2)); - - if (!$spellcheck_langs[$lang]) - $lang = 'en'; - - $OUTPUT->set_env('spell_langs', $spellcheck_langs); - $OUTPUT->set_env('spell_lang', $lang); - - $editor_lang_set = array(); - foreach ($spellcheck_langs as $key => $name) { - $editor_lang_set[] = ($key == $lang ? '+' : '') . rcube::JQ($name).'='.rcube::JQ($key); - } - - // include GoogieSpell - $OUTPUT->include_script('googiespell.js'); - $OUTPUT->add_script(sprintf( - "var googie = new GoogieSpell('%s/images/googiespell/','%s&lang=', %s);\n". - "googie.lang_chck_spell = \"%s\";\n". - "googie.lang_rsm_edt = \"%s\";\n". - "googie.lang_close = \"%s\";\n". - "googie.lang_revert = \"%s\";\n". - "googie.lang_no_error_found = \"%s\";\n". - "googie.lang_learn_word = \"%s\";\n". - "googie.setLanguages(%s);\n". - "googie.setCurrentLanguage('%s');\n". - "googie.setDecoration(false);\n". - "googie.decorateTextarea('%s');\n". - "%s.set_env('spellcheck', googie);", - $RCMAIL->output->get_skin_path(), - $RCMAIL->url(array('_task' => 'utils', '_action' => 'spell', '_remote' => 1)), - !empty($dictionary) ? 'true' : 'false', - rcube::JQ(rcube::Q($RCMAIL->gettext('checkspelling'))), - rcube::JQ(rcube::Q($RCMAIL->gettext('resumeediting'))), - rcube::JQ(rcube::Q($RCMAIL->gettext('close'))), - rcube::JQ(rcube::Q($RCMAIL->gettext('revertto'))), - rcube::JQ(rcube::Q($RCMAIL->gettext('nospellerrors'))), - rcube::JQ(rcube::Q($RCMAIL->gettext('addtodict'))), - rcube_output::json_serialize($spellcheck_langs), - $lang, - $attrib['id'], - rcmail_output::JS_OBJECT_NAME), 'foot'); - - $OUTPUT->add_label('checking'); - $OUTPUT->set_env('spellcheck_langs', join(',', $editor_lang_set)); - } - - $out .= "\n".'<iframe name="savetarget" src="program/resources/blank.gif" style="width:0;height:0;border:none;visibility:hidden;"></iframe>'; - - return $out; + global $RCMAIL, $OUTPUT, $HTML_MODE, $MESSAGE_BODY; + + list($form_start, $form_end) = get_form_tags($attrib); + unset($attrib['form']); + + if (empty($attrib['id'])) + $attrib['id'] = 'rcmComposeBody'; + + $attrib['name'] = '_message'; + + $isHtml = $HTML_MODE; + + $out = $form_start ? "$form_start\n" : ''; + + $saveid = new html_hiddenfield(array('name' => '_draft_saveid', 'value' => $RCMAIL->output->get_env('draft_id'))); + $out .= $saveid->show(); + + $drafttoggle = new html_hiddenfield(array('name' => '_draft', 'value' => 'yes')); + $out .= $drafttoggle->show(); + + $msgtype = new html_hiddenfield(array('name' => '_is_html', 'value' => ($isHtml ? "1" : "0"))); + $out .= $msgtype->show(); + + $framed = new html_hiddenfield(array('name' => '_framed', 'value' => '1')); + $out .= $framed->show(); + + // If desired, set this textarea to be editable by TinyMCE + if ($isHtml) { + $MESSAGE_BODY = htmlentities($MESSAGE_BODY, ENT_NOQUOTES, RCUBE_CHARSET); + $attrib['class'] = 'mce_editor'; + $attrib['is_escaped'] = true; + $textarea = new html_textarea($attrib); + $out .= $textarea->show($MESSAGE_BODY); + } + else { + $textarea = new html_textarea($attrib); + $out .= $textarea->show(''); + + // quote plain text, inject into textarea + $table = get_html_translation_table(HTML_SPECIALCHARS); + $MESSAGE_BODY = strtr($MESSAGE_BODY, $table); + $out = substr($out, 0, -11) . $MESSAGE_BODY . '</textarea>'; + } + + $out .= $form_end ? "\n$form_end" : ''; + + $OUTPUT->set_env('composebody', $attrib['id']); + + // include HTML editor + $RCMAIL->html_editor(); + + // Set language list + if ($RCMAIL->config->get('enable_spellcheck')) { + $engine = new rcube_spellchecker(); + $dictionary = (bool) $RCMAIL->config->get('spellcheck_dictionary'); + $spellcheck_langs = $engine->languages(); + $lang = $_SESSION['language']; + + // if not found in the list, try with two-letter code + if (!$spellcheck_langs[$lang]) { + $lang = strtolower(substr($lang, 0, 2)); + } + + if (!$spellcheck_langs[$lang]) { + $lang = 'en'; + } + + $OUTPUT->set_env('spell_langs', $spellcheck_langs); + $OUTPUT->set_env('spell_lang', $lang); + + $editor_lang_set = array(); + foreach ($spellcheck_langs as $key => $name) { + $editor_lang_set[] = ($key == $lang ? '+' : '') . rcube::JQ($name).'='.rcube::JQ($key); + } + + // include GoogieSpell + $OUTPUT->include_script('googiespell.js'); + $OUTPUT->add_script(sprintf( + "var googie = new GoogieSpell('%s/images/googiespell/','%s&lang=', %s);\n". + "googie.lang_chck_spell = \"%s\";\n". + "googie.lang_rsm_edt = \"%s\";\n". + "googie.lang_close = \"%s\";\n". + "googie.lang_revert = \"%s\";\n". + "googie.lang_no_error_found = \"%s\";\n". + "googie.lang_learn_word = \"%s\";\n". + "googie.setLanguages(%s);\n". + "googie.setCurrentLanguage('%s');\n". + "googie.setDecoration(false);\n". + "googie.decorateTextarea('%s');\n". + "%s.set_env('spellcheck', googie);", + $RCMAIL->output->get_skin_path(), + $RCMAIL->url(array('_task' => 'utils', '_action' => 'spell', '_remote' => 1)), + !empty($dictionary) ? 'true' : 'false', + rcube::JQ(rcube::Q($RCMAIL->gettext('checkspelling'))), + rcube::JQ(rcube::Q($RCMAIL->gettext('resumeediting'))), + rcube::JQ(rcube::Q($RCMAIL->gettext('close'))), + rcube::JQ(rcube::Q($RCMAIL->gettext('revertto'))), + rcube::JQ(rcube::Q($RCMAIL->gettext('nospellerrors'))), + rcube::JQ(rcube::Q($RCMAIL->gettext('addtodict'))), + rcube_output::json_serialize($spellcheck_langs), + $lang, + $attrib['id'], + rcmail_output::JS_OBJECT_NAME), 'foot'); + + $OUTPUT->add_label('checking'); + $OUTPUT->set_env('spellcheck_langs', join(',', $editor_lang_set)); + } + + $out .= "\n".'<iframe name="savetarget" src="program/resources/blank.gif" style="width:0;height:0;border:none;visibility:hidden;"></iframe>'; + + return $out; } function rcmail_create_reply_body($body, $bodyIsHtml) { - global $RCMAIL, $MESSAGE, $LINE_LENGTH; - - // build reply prefix - $from = array_pop(rcube_mime::decode_address_list($MESSAGE->get_header('from'), 1, false, $MESSAGE->headers->charset)); - $prefix = $RCMAIL->gettext(array( - 'name' => 'mailreplyintro', - 'vars' => array( - 'date' => $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')), - 'sender' => $from['name'] ? $from['name'] : rcube_utils::idn_to_utf8($from['mailto']), - ) - )); - - if (!$bodyIsHtml) { - $body = preg_replace('/\r?\n/', "\n", $body); - $body = trim($body, "\n"); - - // soft-wrap and quote message text - $body = rcmail_wrap_and_quote($body, $LINE_LENGTH); - - $prefix .= "\n"; - $suffix = ''; - - if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting - $prefix = "\n\n\n" . $prefix; - } - } - else { - // save inline images to files - $cid_map = rcmail_write_inline_attachments($MESSAGE); - // set is_safe flag (we need this for html body washing) - rcmail_check_safe($MESSAGE); - // clean up html tags - $body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map); - - // build reply (quote content) - $prefix = '<p>' . rcube::Q($prefix) . "</p>\n"; - $prefix .= '<blockquote>'; - - if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting - $prefix = '<br>' . $prefix; - $suffix = '</blockquote>'; + global $RCMAIL, $MESSAGE, $LINE_LENGTH; + + // build reply prefix + $from = array_pop(rcube_mime::decode_address_list($MESSAGE->get_header('from'), 1, false, $MESSAGE->headers->charset)); + $prefix = $RCMAIL->gettext(array( + 'name' => 'mailreplyintro', + 'vars' => array( + 'date' => $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')), + 'sender' => $from['name'] ? $from['name'] : rcube_utils::idn_to_utf8($from['mailto']), + ) + )); + + if (!$bodyIsHtml) { + $body = preg_replace('/\r?\n/', "\n", $body); + $body = trim($body, "\n"); + + // soft-wrap and quote message text + $body = rcmail_wrap_and_quote($body, $LINE_LENGTH); + + $prefix .= "\n"; + $suffix = ''; + + if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting + $prefix = "\n\n\n" . $prefix; + } } else { - $suffix = '</blockquote><p></p>'; + // save inline images to files + $cid_map = rcmail_write_inline_attachments($MESSAGE); + // set is_safe flag (we need this for html body washing) + rcmail_check_safe($MESSAGE); + // clean up html tags + $body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map); + + // build reply (quote content) + $prefix = '<p>' . rcube::Q($prefix) . "</p>\n"; + $prefix .= '<blockquote>'; + + if (intval($RCMAIL->config->get('reply_mode')) > 0) { // top-posting + $prefix = '<br>' . $prefix; + $suffix = '</blockquote>'; + } + else { + $suffix = '</blockquote><p></p>'; + } } - } - return $prefix.$body.$suffix; + return $prefix . $body . $suffix; } function rcmail_create_forward_body($body, $bodyIsHtml) { - global $RCMAIL, $MESSAGE, $COMPOSE; - - // add attachments - if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts)) - $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml); - - $date = $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); - - if (!$bodyIsHtml) { - $prefix = "\n\n\n-------- " . $RCMAIL->gettext('originalmessage') . " --------\n"; - $prefix .= $RCMAIL->gettext('subject') . ': ' . $MESSAGE->subject . "\n"; - $prefix .= $RCMAIL->gettext('date') . ': ' . $date . "\n"; - $prefix .= $RCMAIL->gettext('from') . ': ' . $MESSAGE->get_header('from') . "\n"; - $prefix .= $RCMAIL->gettext('to') . ': ' . $MESSAGE->get_header('to') . "\n"; - - if ($cc = $MESSAGE->headers->get('cc')) - $prefix .= $RCMAIL->gettext('cc') . ': ' . $cc . "\n"; - if (($replyto = $MESSAGE->headers->get('reply-to')) && $replyto != $MESSAGE->get_header('from')) - $prefix .= $RCMAIL->gettext('replyto') . ': ' . $replyto . "\n"; - - $prefix .= "\n"; - $body = trim($body, "\r\n"); - } - else { - // set is_safe flag (we need this for html body washing) - rcmail_check_safe($MESSAGE); - // clean up html tags - $body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map); - - $prefix = sprintf( - "<br /><p>-------- " . $RCMAIL->gettext('originalmessage') . " --------</p>" . - "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody>" . - "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" . - "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" . - "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" . - "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", - $RCMAIL->gettext('subject'), rcube::Q($MESSAGE->subject), - $RCMAIL->gettext('date'), rcube::Q($date), - $RCMAIL->gettext('from'), rcube::Q($MESSAGE->get_header('from'), 'replace'), - $RCMAIL->gettext('to'), rcube::Q($MESSAGE->get_header('to'), 'replace')); - - if ($cc = $MESSAGE->headers->get('cc')) - $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", - $RCMAIL->gettext('cc'), rcube::Q($cc, 'replace')); - - if (($replyto = $MESSAGE->headers->get('reply-to')) && $replyto != $MESSAGE->get_header('from')) - $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", - $RCMAIL->gettext('replyto'), rcube::Q($replyto, 'replace')); - - $prefix .= "</tbody></table><br>"; - } - - return $prefix.$body; + global $RCMAIL, $MESSAGE, $COMPOSE; + + // add attachments + if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts)) { + $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml); + } + + $date = $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); + + if (!$bodyIsHtml) { + $prefix = "\n\n\n-------- " . $RCMAIL->gettext('originalmessage') . " --------\n"; + $prefix .= $RCMAIL->gettext('subject') . ': ' . $MESSAGE->subject . "\n"; + $prefix .= $RCMAIL->gettext('date') . ': ' . $date . "\n"; + $prefix .= $RCMAIL->gettext('from') . ': ' . $MESSAGE->get_header('from') . "\n"; + $prefix .= $RCMAIL->gettext('to') . ': ' . $MESSAGE->get_header('to') . "\n"; + + if ($cc = $MESSAGE->headers->get('cc')) { + $prefix .= $RCMAIL->gettext('cc') . ': ' . $cc . "\n"; + } + if (($replyto = $MESSAGE->headers->get('reply-to')) && $replyto != $MESSAGE->get_header('from')) { + $prefix .= $RCMAIL->gettext('replyto') . ': ' . $replyto . "\n"; + } + + $prefix .= "\n"; + $body = trim($body, "\r\n"); + } + else { + // set is_safe flag (we need this for html body washing) + rcmail_check_safe($MESSAGE); + + // clean up html tags + $body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map); + + $prefix = sprintf( + "<br /><p>-------- " . $RCMAIL->gettext('originalmessage') . " --------</p>" . + "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody>" . + "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" . + "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" . + "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" . + "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", + $RCMAIL->gettext('subject'), rcube::Q($MESSAGE->subject), + $RCMAIL->gettext('date'), rcube::Q($date), + $RCMAIL->gettext('from'), rcube::Q($MESSAGE->get_header('from'), 'replace'), + $RCMAIL->gettext('to'), rcube::Q($MESSAGE->get_header('to'), 'replace')); + + if ($cc = $MESSAGE->headers->get('cc')) + $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", + $RCMAIL->gettext('cc'), rcube::Q($cc, 'replace')); + + if (($replyto = $MESSAGE->headers->get('reply-to')) && $replyto != $MESSAGE->get_header('from')) + $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", + $RCMAIL->gettext('replyto'), rcube::Q($replyto, 'replace')); + + $prefix .= "</tbody></table><br>"; + } + + return $prefix . $body; } function rcmail_create_draft_body($body, $bodyIsHtml) { - global $MESSAGE, $COMPOSE; + global $MESSAGE, $COMPOSE; - /** - * add attachments - * sizeof($MESSAGE->mime_parts can be 1 - e.g. attachment, but no text! - */ - if (empty($COMPOSE['forward_attachments']) - && is_array($MESSAGE->mime_parts) - && count($MESSAGE->mime_parts) > 0) - { - $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml); - } + // add attachments + // sizeof($MESSAGE->mime_parts can be 1 - e.g. attachment, but no text! + if (empty($COMPOSE['forward_attachments']) + && is_array($MESSAGE->mime_parts) + && count($MESSAGE->mime_parts) > 0 + ) { + $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml); + } - // clean up HTML tags - XSS prevention (#1489251) - if ($bodyIsHtml) { - $body = rcmail_wash_html($body, array('safe' => 1), $cid_map); + // clean up HTML tags - XSS prevention (#1489251) + if ($bodyIsHtml) { + $body = rcmail_wash_html($body, array('safe' => 1), $cid_map); - // remove comments (produced by washtml) - $body = preg_replace('/<!--[^>]+-->/', '', $body); + // remove comments (produced by washtml) + $body = preg_replace('/<!--[^>]+-->/', '', $body); - // replace cid with href in inline images links - if (!empty($cid_map)) { - $body = str_replace(array_keys($cid_map), array_values($cid_map), $body); + // replace cid with href in inline images links + if (!empty($cid_map)) { + $body = str_replace(array_keys($cid_map), array_values($cid_map), $body); + } } - } - return $body; + return $body; } function rcmail_remove_signature($body) { - global $RCMAIL; + global $RCMAIL; - $body = str_replace("\r\n", "\n", $body); - $len = strlen($body); - $sig_max_lines = $RCMAIL->config->get('sig_max_lines', 15); + $body = str_replace("\r\n", "\n", $body); + $len = strlen($body); + $sig_max_lines = $RCMAIL->config->get('sig_max_lines', 15); - while (($sp = strrpos($body, "-- \n", $sp ? -$len+$sp-1 : 0)) !== false) { - if ($sp == 0 || $body[$sp-1] == "\n") { - // do not touch blocks with more that X lines - if (substr_count($body, "\n", $sp) < $sig_max_lines) { - $body = substr($body, 0, max(0, $sp-1)); - } - break; + while (($sp = strrpos($body, "-- \n", $sp ? -$len+$sp-1 : 0)) !== false) { + if ($sp == 0 || $body[$sp-1] == "\n") { + // do not touch blocks with more that X lines + if (substr_count($body, "\n", $sp) < $sig_max_lines) { + $body = substr($body, 0, max(0, $sp-1)); + } + break; + } } - } - return $body; + return $body; } function rcmail_write_compose_attachments(&$message, $bodyIsHtml) { - global $RCMAIL, $COMPOSE, $compose_mode; - - $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $attachment) { - $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; - } - - $cid_map = array(); - $messages = array(); - - foreach ((array)$message->mime_parts as $pid => $part) - { - if ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) { - // skip parts that aren't valid attachments - if ($part->ctype_primary == 'multipart' || $part->mimetype == 'application/ms-tnef') { - continue; - } - // skip message attachments in reply mode - if ($part->ctype_primary == 'message' && $compose_mode == RCUBE_COMPOSE_REPLY) { - continue; - } - // skip inline images when forwarding in text mode - if ($part->content_id && $part->disposition == 'inline' && !$bodyIsHtml && $compose_mode == RCUBE_COMPOSE_FORWARD) { - continue; - } - - // skip message/rfc822 attachments on forwards (#1489214) - // Thunderbird when forwarding in inline mode displays such attachments - // and skips any attachments from inside of such part, this however - // skipped e.g. images used in HTML body or other attachments. So, - // better to skip .eml attachments but not their content (included files). - if ($part->mimetype == 'message/rfc822') { - if ($compose_mode == RCUBE_COMPOSE_FORWARD) { - continue; - } - $messages[] = $part->mime_id; - } - else if ($compose_mode != RCUBE_COMPOSE_FORWARD) { - // skip attachments included in message/rfc822 attachment (#1486487) - foreach ($messages as $mimeid) - if (strpos($part->mime_id, $mimeid . '.') === 0) { - continue 2; - } - } - - if (($attachment = $loaded_attachments[rcmail_attachment_name($part) . $part->mimetype]) - || ($attachment = rcmail_save_attachment($message, $pid))) { - $COMPOSE['attachments'][$attachment['id']] = $attachment; - if ($bodyIsHtml && ($part->content_id || $part->content_location)) { - $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', - $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); - if ($part->content_id) - $cid_map['cid:'.$part->content_id] = $url; - else - $cid_map[$part->content_location] = $url; + global $RCMAIL, $COMPOSE, $compose_mode; + + $loaded_attachments = array(); + foreach ((array)$COMPOSE['attachments'] as $attachment) { + $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; + } + + $cid_map = array(); + $messages = array(); + + foreach ((array)$message->mime_parts as $pid => $part) { + if ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) { + // skip parts that aren't valid attachments + if ($part->ctype_primary == 'multipart' || $part->mimetype == 'application/ms-tnef') { + continue; + } + + // skip message attachments in reply mode + if ($part->ctype_primary == 'message' && $compose_mode == RCUBE_COMPOSE_REPLY) { + continue; + } + + // skip inline images when forwarding in text mode + if ($part->content_id && $part->disposition == 'inline' && !$bodyIsHtml && $compose_mode == RCUBE_COMPOSE_FORWARD) { + continue; + } + + // skip message/rfc822 attachments on forwards (#1489214) + // Thunderbird when forwarding in inline mode displays such attachments + // and skips any attachments from inside of such part, this however + // skipped e.g. images used in HTML body or other attachments. So, + // better to skip .eml attachments but not their content (included files). + if ($part->mimetype == 'message/rfc822') { + if ($compose_mode == RCUBE_COMPOSE_FORWARD) { + continue; + } + $messages[] = $part->mime_id; + } + else if ($compose_mode != RCUBE_COMPOSE_FORWARD) { + // skip attachments included in message/rfc822 attachment (#1486487) + foreach ($messages as $mimeid) { + if (strpos($part->mime_id, $mimeid . '.') === 0) { + continue 2; + } + } + } + + if (($attachment = $loaded_attachments[rcmail_attachment_name($part) . $part->mimetype]) + || ($attachment = rcmail_save_attachment($message, $pid)) + ) { + $COMPOSE['attachments'][$attachment['id']] = $attachment; + + if ($bodyIsHtml && ($part->content_id || $part->content_location)) { + $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', + $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); + + if ($part->content_id) + $cid_map['cid:'.$part->content_id] = $url; + else + $cid_map[$part->content_location] = $url; + } + } } - } } - } - $COMPOSE['forward_attachments'] = true; + $COMPOSE['forward_attachments'] = true; - return $cid_map; + return $cid_map; } function rcmail_write_inline_attachments(&$message) { - global $RCMAIL, $COMPOSE; - - $cid_map = array(); - foreach ((array)$message->mime_parts as $pid => $part) { - if (($part->content_id || $part->content_location) && $part->filename) { - if ($attachment = rcmail_save_attachment($message, $pid)) { - $COMPOSE['attachments'][$attachment['id']] = $attachment; - $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', - $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); - if ($part->content_id) - $cid_map['cid:'.$part->content_id] = $url; - else - $cid_map[$part->content_location] = $url; - } + global $RCMAIL, $COMPOSE; + + $cid_map = array(); + foreach ((array)$message->mime_parts as $pid => $part) { + if (($part->content_id || $part->content_location) && $part->filename) { + if ($attachment = rcmail_save_attachment($message, $pid)) { + $COMPOSE['attachments'][$attachment['id']] = $attachment; + $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', + $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); + + if ($part->content_id) + $cid_map['cid:'.$part->content_id] = $url; + else + $cid_map[$part->content_location] = $url; + } + } } - } - return $cid_map; + return $cid_map; } // Creates attachment(s) from the forwarded message(s) function rcmail_write_forward_attachments() { - global $RCMAIL, $COMPOSE, $MESSAGE; + global $RCMAIL, $COMPOSE, $MESSAGE; - $storage = $RCMAIL->get_storage(); - $mem_limit = parse_bytes(ini_get('memory_limit')); - $curr_mem = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB - $names = array(); + $storage = $RCMAIL->get_storage(); + $names = array(); - $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $attachment) { - $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; - } + $loaded_attachments = array(); + foreach ((array)$COMPOSE['attachments'] as $attachment) { + $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; + } - if ($COMPOSE['forward_uid'] == '*') { - $index = $storage->index(null, rcmail_sort_column(), rcmail_sort_order()); - $COMPOSE['forward_uid'] = $index->get(); - } - else { - $COMPOSE['forward_uid'] = explode(',', $COMPOSE['forward_uid']); - } + if ($COMPOSE['forward_uid'] == '*') { + $index = $storage->index(null, rcmail_sort_column(), rcmail_sort_order()); + $COMPOSE['forward_uid'] = $index->get(); + } + else { + $COMPOSE['forward_uid'] = explode(',', $COMPOSE['forward_uid']); + } - foreach ((array)$COMPOSE['forward_uid'] as $uid) { - $message = new rcube_message($uid); + foreach ((array)$COMPOSE['forward_uid'] as $uid) { + $message = new rcube_message($uid); - if (empty($message->headers)) { - continue; - } + if (empty($message->headers)) { + continue; + } - if (!empty($message->headers->charset)) { - $storage->set_charset($message->headers->charset); - } + if (!empty($message->headers->charset)) { + $storage->set_charset($message->headers->charset); + } - if (empty($MESSAGE->subject)) { - $MESSAGE->subject = $message->subject; - } + if (empty($MESSAGE->subject)) { + $MESSAGE->subject = $message->subject; + } - // generate (unique) attachment name - $name = strlen($message->subject) ? mb_substr($message->subject, 0, 64) : 'message_rfc822'; - if (!empty($names[$name])) { - $names[$name]++; - $name .= '_' . $names[$name]; - } - $names[$name] = 1; - $name .= '.eml'; + // generate (unique) attachment name + $name = strlen($message->subject) ? mb_substr($message->subject, 0, 64) : 'message_rfc822'; + if (!empty($names[$name])) { + $names[$name]++; + $name .= '_' . $names[$name]; + } + $names[$name] = 1; + $name .= '.eml'; + + $data = $path = null; - $data = $path = null; + if (!empty($loaded_attachments[$name . 'message/rfc822'])) { + continue; + } + + // don't load too big attachments into memory + if (!rcube_utils::mem_check($message->size)) { + $temp_dir = unslashify($RCMAIL->config->get('temp_dir')); + $path = tempnam($temp_dir, 'rcmAttmnt'); + if ($fp = fopen($path, 'w')) { + $storage->get_raw_body($message->uid, $fp); + fclose($fp); + } + else { + return false; + } + } + else { + $data = $storage->get_raw_body($message->uid); + $curr_mem += $message->size; + } + + $attachment = array( + 'group' => $COMPOSE['id'], + 'name' => $name, + 'mimetype' => 'message/rfc822', + 'data' => $data, + 'path' => $path, + 'size' => $path ? filesize($path) : strlen($data), + ); + + $attachment = $RCMAIL->plugins->exec_hook('attachment_save', $attachment); - if (!empty($loaded_attachments[$name . 'message/rfc822'])) { - continue; + if ($attachment['status']) { + unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); + $COMPOSE['attachments'][$attachment['id']] = $attachment; + } + else if ($path) { + @unlink($path); + } } +} + + +function rcmail_save_attachment(&$message, $pid) +{ + global $COMPOSE; + + $rcmail = rcmail::get_instance(); + $part = $message->mime_parts[$pid]; + $data = $path = null; // don't load too big attachments into memory - if ($mem_limit > 0 && $message->size > $mem_limit - $curr_mem) { - $temp_dir = unslashify($RCMAIL->config->get('temp_dir')); - $path = tempnam($temp_dir, 'rcmAttmnt'); - if ($fp = fopen($path, 'w')) { - $storage->get_raw_body($message->uid, $fp); - fclose($fp); - } - else { - return false; - } + if (!rcube_utils::mem_check($part->size)) { + $temp_dir = unslashify($rcmail->config->get('temp_dir')); + $path = tempnam($temp_dir, 'rcmAttmnt'); + + if ($fp = fopen($path, 'w')) { + $message->get_part_content($pid, $fp, true, 0, false); + fclose($fp); + } + else { + return false; + } } else { - $data = $storage->get_raw_body($message->uid); - $curr_mem += $message->size; + $data = $message->get_part_content($pid, null, true, 0, false); } + $mimetype = $part->ctype_primary . '/' . $part->ctype_secondary; + $filename = rcmail_attachment_name($part); + $attachment = array( - 'group' => $COMPOSE['id'], - 'name' => $name, - 'mimetype' => 'message/rfc822', - 'data' => $data, - 'path' => $path, - 'size' => $path ? filesize($path) : strlen($data), + 'group' => $COMPOSE['id'], + 'name' => $filename, + 'mimetype' => $mimetype, + 'content_id' => $part->content_id, + 'data' => $data, + 'path' => $path, + 'size' => $path ? filesize($path) : strlen($data), ); - $attachment = $RCMAIL->plugins->exec_hook('attachment_save', $attachment); + $attachment = $rcmail->plugins->exec_hook('attachment_save', $attachment); if ($attachment['status']) { - unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); - $COMPOSE['attachments'][$attachment['id']] = $attachment; + unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); + return $attachment; } else if ($path) { - @unlink($path); + @unlink($path); } - } -} - -function rcmail_save_attachment(&$message, $pid) -{ - global $COMPOSE; - - $rcmail = rcmail::get_instance(); - $part = $message->mime_parts[$pid]; - $mem_limit = parse_bytes(ini_get('memory_limit')); - $curr_mem = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB - $data = $path = null; - - // don't load too big attachments into memory - if ($mem_limit > 0 && $part->size > $mem_limit - $curr_mem) { - $temp_dir = unslashify($rcmail->config->get('temp_dir')); - $path = tempnam($temp_dir, 'rcmAttmnt'); - if ($fp = fopen($path, 'w')) { - $message->get_part_content($pid, $fp, true, 0, false); - fclose($fp); - } else - return false; - } else { - $data = $message->get_part_content($pid, null, true, 0, false); - } - - $mimetype = $part->ctype_primary . '/' . $part->ctype_secondary; - $filename = rcmail_attachment_name($part); - - $attachment = array( - 'group' => $COMPOSE['id'], - 'name' => $filename, - 'mimetype' => $mimetype, - 'content_id' => $part->content_id, - 'data' => $data, - 'path' => $path, - 'size' => $path ? filesize($path) : strlen($data), - ); - - $attachment = $rcmail->plugins->exec_hook('attachment_save', $attachment); - - if ($attachment['status']) { - unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); - return $attachment; - } else if ($path) { - @unlink($path); - } - - return false; + return false; } function rcmail_save_image($path, $mimetype='') { - global $COMPOSE; + global $COMPOSE; - // handle attachments in memory - $data = file_get_contents($path); - $name = rcmail_basename($path); + // handle attachments in memory + $data = file_get_contents($path); + $name = rcmail_basename($path); - $attachment = array( - 'group' => $COMPOSE['id'], - 'name' => $name, - 'mimetype' => $mimetype ? $mimetype : rcube_mime::file_content_type($path, $name), - 'data' => $data, - 'size' => strlen($data), - ); + $attachment = array( + 'group' => $COMPOSE['id'], + 'name' => $name, + 'mimetype' => $mimetype ? $mimetype : rcube_mime::file_content_type($path, $name), + 'data' => $data, + 'size' => strlen($data), + ); - $attachment = rcmail::get_instance()->plugins->exec_hook('attachment_save', $attachment); + $attachment = rcmail::get_instance()->plugins->exec_hook('attachment_save', $attachment); - if ($attachment['status']) { - unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); - return $attachment; - } + if ($attachment['status']) { + unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); + return $attachment; + } - return false; + return false; } function rcmail_basename($filename) { - // basename() is not unicode safe and locale dependent - if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) { - return preg_replace('/^.*[\\\\\\/]/', '', $filename); - } else { - return preg_replace('/^.*[\/]/', '', $filename); - } + // basename() is not unicode safe and locale dependent + if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) { + return preg_replace('/^.*[\\\\\\/]/', '', $filename); + } + else { + return preg_replace('/^.*[\/]/', '', $filename); + } } function rcmail_compose_subject($attrib) { - global $MESSAGE, $COMPOSE, $compose_mode; + global $MESSAGE, $COMPOSE, $compose_mode; - list($form_start, $form_end) = get_form_tags($attrib); - unset($attrib['form']); + list($form_start, $form_end) = get_form_tags($attrib); + unset($attrib['form']); - $attrib['name'] = '_subject'; - $attrib['spellcheck'] = 'true'; - $textfield = new html_inputfield($attrib); + $attrib['name'] = '_subject'; + $attrib['spellcheck'] = 'true'; - $subject = ''; + $textfield = new html_inputfield($attrib); + $subject = ''; - // use subject from post - if (isset($_POST['_subject'])) { - $subject = rcube_utils::get_input_value('_subject', rcube_utils::INPUT_POST, TRUE); - } - // create a reply-subject - else if ($compose_mode == RCUBE_COMPOSE_REPLY) { - if (preg_match('/^re:/i', $MESSAGE->subject)) - $subject = $MESSAGE->subject; - else - $subject = 'Re: '.$MESSAGE->subject; - } - // create a forward-subject - else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { - if (preg_match('/^fwd:/i', $MESSAGE->subject)) - $subject = $MESSAGE->subject; - else - $subject = 'Fwd: '.$MESSAGE->subject; - } - // creeate a draft-subject - else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { - $subject = $MESSAGE->subject; - } - else if (!empty($COMPOSE['param']['subject'])) { - $subject = $COMPOSE['param']['subject']; - } - - $out = $form_start ? "$form_start\n" : ''; - $out .= $textfield->show($subject); - $out .= $form_end ? "\n$form_end" : ''; - - return $out; + // use subject from post + if (isset($_POST['_subject'])) { + $subject = rcube_utils::get_input_value('_subject', rcube_utils::INPUT_POST, TRUE); + } + // create a reply-subject + else if ($compose_mode == RCUBE_COMPOSE_REPLY) { + if (preg_match('/^re:/i', $MESSAGE->subject)) + $subject = $MESSAGE->subject; + else + $subject = 'Re: '.$MESSAGE->subject; + } + // create a forward-subject + else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { + if (preg_match('/^fwd:/i', $MESSAGE->subject)) + $subject = $MESSAGE->subject; + else + $subject = 'Fwd: '.$MESSAGE->subject; + } + // creeate a draft-subject + else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { + $subject = $MESSAGE->subject; + } + else if (!empty($COMPOSE['param']['subject'])) { + $subject = $COMPOSE['param']['subject']; + } + + $out = $form_start ? "$form_start\n" : ''; + $out .= $textfield->show($subject); + $out .= $form_end ? "\n$form_end" : ''; + + return $out; } function rcmail_compose_attachment_list($attrib) { - global $RCMAIL, $OUTPUT, $CONFIG, $COMPOSE; - - // add ID if not given - if (!$attrib['id']) - $attrib['id'] = 'rcmAttachmentList'; - - $out = "\n"; - $jslist = array(); - $button = ''; - - if (is_array($COMPOSE['attachments'])) { - if ($attrib['deleteicon']) { - $button = html::img(array( - 'src' => $CONFIG['skin_path'] . $attrib['deleteicon'], - 'alt' => $RCMAIL->gettext('delete') - )); - } - else if (rcube_utils::get_boolean($attrib['textbuttons'])) { - $button = rcube::Q($RCMAIL->gettext('delete')); - } - - foreach ($COMPOSE['attachments'] as $id => $a_prop) { - if (empty($a_prop)) - continue; - - $out .= html::tag('li', - array( - 'id' => 'rcmfile'.$id, - 'class' => rcube_utils::file2class($a_prop['mimetype'], $a_prop['name']), - 'onmouseover' => "rcube_webmail.long_subject_title_ex(this, 0)", - ), - html::a(array( - 'href' => "#delete", - 'title' => $RCMAIL->gettext('delete'), - 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", rcmail_output::JS_OBJECT_NAME, $id), - 'class' => 'delete' - ), - $button - ) . rcube::Q($a_prop['name']) - ); - - $jslist['rcmfile'.$id] = array('name' => $a_prop['name'], 'complete' => true, 'mimetype' => $a_prop['mimetype']); - } - } - - if ($attrib['deleteicon']) - $COMPOSE['deleteicon'] = $CONFIG['skin_path'] . $attrib['deleteicon']; - else if (rcube_utils::get_boolean($attrib['textbuttons'])) - $COMPOSE['textbuttons'] = true; - if ($attrib['cancelicon']) - $OUTPUT->set_env('cancelicon', $CONFIG['skin_path'] . $attrib['cancelicon']); - if ($attrib['loadingicon']) - $OUTPUT->set_env('loadingicon', $CONFIG['skin_path'] . $attrib['loadingicon']); - - $OUTPUT->set_env('attachments', $jslist); - $OUTPUT->add_gui_object('attachmentlist', $attrib['id']); - - return html::tag('ul', $attrib, $out, html::$common_attrib); + global $RCMAIL, $OUTPUT, $COMPOSE; + + // add ID if not given + if (!$attrib['id']) + $attrib['id'] = 'rcmAttachmentList'; + + $out = "\n"; + $jslist = array(); + $button = ''; + $skin_path = $RCMAIL->config->get('skin_path'); + + if (is_array($COMPOSE['attachments'])) { + if ($attrib['deleteicon']) { + $button = html::img(array( + 'src' => $skin_path . $attrib['deleteicon'], + 'alt' => $RCMAIL->gettext('delete') + )); + } + else if (rcube_utils::get_boolean($attrib['textbuttons'])) { + $button = rcube::Q($RCMAIL->gettext('delete')); + } + + foreach ($COMPOSE['attachments'] as $id => $a_prop) { + if (empty($a_prop)) { + continue; + } + + $out .= html::tag('li', array( + 'id' => 'rcmfile'.$id, + 'class' => rcube_utils::file2class($a_prop['mimetype'], $a_prop['name']), + 'onmouseover' => "rcube_webmail.long_subject_title_ex(this, 0)", + ), + html::a(array( + 'href' => "#delete", + 'title' => $RCMAIL->gettext('delete'), + 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", rcmail_output::JS_OBJECT_NAME, $id), + 'class' => 'delete' + ), + $button + ) . rcube::Q($a_prop['name']) + ); + + $jslist['rcmfile'.$id] = array( + 'name' => $a_prop['name'], + 'complete' => true, + 'mimetype' => $a_prop['mimetype'] + ); + } + } + + if ($attrib['deleteicon']) + $COMPOSE['deleteicon'] = $skin_path . $attrib['deleteicon']; + else if (rcube_utils::get_boolean($attrib['textbuttons'])) + $COMPOSE['textbuttons'] = true; + if ($attrib['cancelicon']) + $OUTPUT->set_env('cancelicon', $skin_path . $attrib['cancelicon']); + if ($attrib['loadingicon']) + $OUTPUT->set_env('loadingicon', $skin_path . $attrib['loadingicon']); + + $OUTPUT->set_env('attachments', $jslist); + $OUTPUT->add_gui_object('attachmentlist', $attrib['id']); + + return html::tag('ul', $attrib, $out, html::$common_attrib); } function rcmail_compose_attachment_form($attrib) { - global $OUTPUT, $RCMAIL; + global $OUTPUT, $RCMAIL; + + // set defaults + $attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes'); - // set defaults - $attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes'); + // Get filesize, enable upload progress bar + $max_filesize = $RCMAIL->upload_init(); - // Get filesize, enable upload progress bar - $max_filesize = $RCMAIL->upload_init(); + $button = new html_inputfield(array('type' => 'button')); + $content = html::div(null, rcmail_compose_attachment_field()) + . html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))); + + if (rcube_utils::get_boolean($attrib['buttons'])) { + $content .= html::div('buttons', + $button->show($RCMAIL->gettext('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' . + $button->show($RCMAIL->gettext('upload'), array('class' => 'button mainaction', 'onclick' => rcmail_output::JS_OBJECT_NAME . ".command('send-attachment', this.form)")) + ); + } - $button = new html_inputfield(array('type' => 'button')); + $out = html::div($attrib, $OUTPUT->form_tag(array( + 'id' => $attrib['id'] . 'Frm', + 'name' => 'uploadform', + 'method' => 'post', + 'enctype' => 'multipart/form-data' + ), $content + )); - $out = html::div($attrib, - $OUTPUT->form_tag(array('id' => $attrib['id'].'Frm', 'name' => 'uploadform', 'method' => 'post', 'enctype' => 'multipart/form-data'), - html::div(null, rcmail_compose_attachment_field()) . - html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) . - (rcube_utils::get_boolean($attrib['buttons']) ? html::div('buttons', - $button->show($RCMAIL->gettext('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' . - $button->show($RCMAIL->gettext('upload'), array('class' => 'button mainaction', 'onclick' => rcmail_output::JS_OBJECT_NAME . ".command('send-attachment', this.form)")) - ) : '') - ) - ); + $OUTPUT->add_gui_object('uploadform', $attrib['id'] . 'Frm'); - $OUTPUT->add_gui_object('uploadform', $attrib['id'].'Frm'); - return $out; + return $out; } function rcmail_compose_attachment_field($attrib = array()) { - $attrib['type'] = 'file'; - $attrib['name'] = '_attachments[]'; - $attrib['multiple'] = 'multiple'; + $attrib['type'] = 'file'; + $attrib['name'] = '_attachments[]'; + $attrib['multiple'] = 'multiple'; - $field = new html_inputfield($attrib); - return $field->show(); + $field = new html_inputfield($attrib); + + return $field->show(); } function rcmail_priority_selector($attrib) { - global $RCMAIL, $MESSAGE; + global $RCMAIL, $MESSAGE; - list($form_start, $form_end) = get_form_tags($attrib); - unset($attrib['form']); + list($form_start, $form_end) = get_form_tags($attrib); + unset($attrib['form']); - $attrib['name'] = '_priority'; - $selector = new html_select($attrib); + $attrib['name'] = '_priority'; + $prio_list = array( + $RCMAIL->gettext('lowest') => 5, + $RCMAIL->gettext('low') => 4, + $RCMAIL->gettext('normal') => 0, + $RCMAIL->gettext('high') => 2, + $RCMAIL->gettext('highest') => 1, + ); - $selector->add(array($RCMAIL->gettext('lowest'), - $RCMAIL->gettext('low'), - $RCMAIL->gettext('normal'), - $RCMAIL->gettext('high'), - $RCMAIL->gettext('highest')), - array('5', '4', '0', '2', '1')); + $selector = new html_select($attrib); + $selector->add(array_keys($prio_list), array_values($prio_list)); - if (isset($_POST['_priority'])) - $sel = $_POST['_priority']; - else if (isset($MESSAGE->headers->priority) && intval($MESSAGE->headers->priority) != 3) - $sel = $MESSAGE->headers->priority; - else - $sel = 0; + if (isset($_POST['_priority'])) + $sel = $_POST['_priority']; + else if (isset($MESSAGE->headers->priority) && intval($MESSAGE->headers->priority) != 3) + $sel = $MESSAGE->headers->priority; + else + $sel = 0; - $out = $form_start ? "$form_start\n" : ''; - $out .= $selector->show(strval($sel)); - $out .= $form_end ? "\n$form_end" : ''; + $out = $form_start ? "$form_start\n" : ''; + $out .= $selector->show((int) $sel); + $out .= $form_end ? "\n$form_end" : ''; - return $out; + return $out; } function rcmail_receipt_checkbox($attrib) { - global $RCMAIL, $MESSAGE, $compose_mode; + global $RCMAIL, $MESSAGE, $compose_mode; - list($form_start, $form_end) = get_form_tags($attrib); - unset($attrib['form']); + list($form_start, $form_end) = get_form_tags($attrib); + unset($attrib['form']); - if (!isset($attrib['id'])) - $attrib['id'] = 'receipt'; + if (!isset($attrib['id'])) + $attrib['id'] = 'receipt'; - $attrib['name'] = '_receipt'; - $attrib['value'] = '1'; - $checkbox = new html_checkbox($attrib); + $attrib['name'] = '_receipt'; + $attrib['value'] = '1'; - if (isset($_POST['_receipt'])) - $mdn_default = $_POST['_receipt']; - else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) - $mdn_default = (bool) $MESSAGE->headers->mdn_to; - else - $mdn_default = $RCMAIL->config->get('mdn_default'); + $checkbox = new html_checkbox($attrib); - $out = $form_start ? "$form_start\n" : ''; - $out .= $checkbox->show($mdn_default); - $out .= $form_end ? "\n$form_end" : ''; + if (isset($_POST['_receipt'])) + $mdn_default = $_POST['_receipt']; + else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) + $mdn_default = (bool) $MESSAGE->headers->mdn_to; + else + $mdn_default = $RCMAIL->config->get('mdn_default'); - return $out; + $out = $form_start ? "$form_start\n" : ''; + $out .= $checkbox->show($mdn_default); + $out .= $form_end ? "\n$form_end" : ''; + + return $out; } function rcmail_dsn_checkbox($attrib) { - global $RCMAIL; + global $RCMAIL; + + list($form_start, $form_end) = get_form_tags($attrib); + unset($attrib['form']); - list($form_start, $form_end) = get_form_tags($attrib); - unset($attrib['form']); + if (!isset($attrib['id'])) + $attrib['id'] = 'dsn'; - if (!isset($attrib['id'])) - $attrib['id'] = 'dsn'; + $attrib['name'] = '_dsn'; + $attrib['value'] = '1'; - $attrib['name'] = '_dsn'; - $attrib['value'] = '1'; - $checkbox = new html_checkbox($attrib); + $checkbox = new html_checkbox($attrib); - if (isset($_POST['_dsn'])) - $dsn_value = $_POST['_dsn']; - else - $dsn_value = $RCMAIL->config->get('dsn_default'); + if (isset($_POST['_dsn'])) + $dsn_value = (int) $_POST['_dsn']; + else + $dsn_value = $RCMAIL->config->get('dsn_default'); - $out = $form_start ? "$form_start\n" : ''; - $out .= $checkbox->show($dsn_value); - $out .= $form_end ? "\n$form_end" : ''; + $out = $form_start ? "$form_start\n" : ''; + $out .= $checkbox->show($dsn_value); + $out .= $form_end ? "\n$form_end" : ''; - return $out; + return $out; } function rcmail_editor_selector($attrib) { - global $RCMAIL; + global $RCMAIL; - // determine whether HTML or plain text should be checked - $useHtml = rcmail_compose_editor_mode(); + // determine whether HTML or plain text should be checked + $useHtml = rcmail_compose_editor_mode(); - if (empty($attrib['editorid'])) - $attrib['editorid'] = 'rcmComposeBody'; + if (empty($attrib['editorid'])) + $attrib['editorid'] = 'rcmComposeBody'; - if (empty($attrib['name'])) - $attrib['name'] = 'editorSelect'; + if (empty($attrib['name'])) + $attrib['name'] = 'editorSelect'; - $attrib['onchange'] = "return rcmail_toggle_editor(this, '".$attrib['editorid']."', '_is_html')"; + $attrib['onchange'] = "return rcmail_toggle_editor(this, '".$attrib['editorid']."', '_is_html')"; - $select = new html_select($attrib); + $select = new html_select($attrib); - $select->add(rcube::Q($RCMAIL->gettext('htmltoggle')), 'html'); - $select->add(rcube::Q($RCMAIL->gettext('plaintoggle')), 'plain'); + $select->add(rcube::Q($RCMAIL->gettext('htmltoggle')), 'html'); + $select->add(rcube::Q($RCMAIL->gettext('plaintoggle')), 'plain'); - return $select->show($useHtml ? 'html' : 'plain'); -/* - foreach ($choices as $value => $text) { - $attrib['id'] = '_' . $value; - $attrib['value'] = $value; - $selector .= $radio->show($chosenvalue, $attrib) . html::label($attrib['id'], rcube::Q($RCMAIL->gettext($text))); - } - - return $selector; -*/ + return $select->show($useHtml ? 'html' : 'plain'); } function rcmail_store_target_selection($attrib) { - global $COMPOSE, $RCMAIL; - - $attrib['name'] = '_store_target'; - $select = $RCMAIL->folder_selector(array_merge($attrib, array( - 'noselection' => '- ' . $RCMAIL->gettext('dontsave') . ' -', - 'folder_filter' => 'mail', - 'folder_rights' => 'w', - ))); - return $select->show(isset($_POST['_store_target']) ? $_POST['_store_target'] : $COMPOSE['param']['sent_mbox'], $attrib); + global $COMPOSE, $RCMAIL; + + $attrib['name'] = '_store_target'; + $select = $RCMAIL->folder_selector(array_merge($attrib, array( + 'noselection' => '- ' . $RCMAIL->gettext('dontsave') . ' -', + 'folder_filter' => 'mail', + 'folder_rights' => 'w', + ))); + + return $select->show(isset($_POST['_store_target']) ? $_POST['_store_target'] : $COMPOSE['param']['sent_mbox'], $attrib); } function rcmail_check_sent_folder($folder, $create=false) { - global $RCMAIL; + global $RCMAIL; - // we'll not save the message, so it doesn't matter - if ($RCMAIL->config->get('no_save_sent_messages')) { - return true; - } + // we'll not save the message, so it doesn't matter + if ($RCMAIL->config->get('no_save_sent_messages')) { + return true; + } - if ($RCMAIL->storage->folder_exists($folder, true)) { - return true; - } + if ($RCMAIL->storage->folder_exists($folder, true)) { + return true; + } - // folder may exist but isn't subscribed (#1485241) - if ($create) { - if (!$RCMAIL->storage->folder_exists($folder)) - return $RCMAIL->storage->create_folder($folder, true); - else - return $RCMAIL->storage->subscribe($folder); - } + // folder may exist but isn't subscribed (#1485241) + if ($create) { + if (!$RCMAIL->storage->folder_exists($folder)) + return $RCMAIL->storage->create_folder($folder, true); + else + return $RCMAIL->storage->subscribe($folder); + } - return false; + return false; } function get_form_tags($attrib) { - global $RCMAIL, $MESSAGE_FORM, $COMPOSE; + global $RCMAIL, $MESSAGE_FORM, $COMPOSE; - $form_start = ''; - if (!$MESSAGE_FORM) - { - $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $RCMAIL->task)); - $hiddenfields->add(array('name' => '_action', 'value' => 'send')); - $hiddenfields->add(array('name' => '_id', 'value' => $COMPOSE['id'])); - $hiddenfields->add(array('name' => '_attachments')); + $form_start = ''; + if (!$MESSAGE_FORM) { + $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $RCMAIL->task)); + $hiddenfields->add(array('name' => '_action', 'value' => 'send')); + $hiddenfields->add(array('name' => '_id', 'value' => $COMPOSE['id'])); + $hiddenfields->add(array('name' => '_attachments')); - $form_start = empty($attrib['form']) ? $RCMAIL->output->form_tag(array('name' => "form", 'method' => "post")) : ''; - $form_start .= $hiddenfields->show(); - } + $form_start = empty($attrib['form']) ? $RCMAIL->output->form_tag(array('name' => "form", 'method' => "post")) : ''; + $form_start .= $hiddenfields->show(); + } - $form_end = ($MESSAGE_FORM && !strlen($attrib['form'])) ? '</form>' : ''; - $form_name = !empty($attrib['form']) ? $attrib['form'] : 'form'; + $form_end = ($MESSAGE_FORM && !strlen($attrib['form'])) ? '</form>' : ''; + $form_name = !empty($attrib['form']) ? $attrib['form'] : 'form'; - if (!$MESSAGE_FORM) - $RCMAIL->output->add_gui_object('messageform', $form_name); + if (!$MESSAGE_FORM) + $RCMAIL->output->add_gui_object('messageform', $form_name); - $MESSAGE_FORM = $form_name; + $MESSAGE_FORM = $form_name; - return array($form_start, $form_end); + return array($form_start, $form_end); } @@ -1791,25 +1848,3 @@ function rcmail_compose_responses_list($attrib) return $list->show(); } - - -// register UI objects -$OUTPUT->add_handlers(array( - 'composeheaders' => 'rcmail_compose_headers', - 'composesubject' => 'rcmail_compose_subject', - 'composebody' => 'rcmail_compose_body', - 'composeattachmentlist' => 'rcmail_compose_attachment_list', - 'composeattachmentform' => 'rcmail_compose_attachment_form', - 'composeattachment' => 'rcmail_compose_attachment_field', - 'filedroparea' => 'compose_file_drop_area', - 'priorityselector' => 'rcmail_priority_selector', - 'editorselector' => 'rcmail_editor_selector', - 'receiptcheckbox' => 'rcmail_receipt_checkbox', - 'dsncheckbox' => 'rcmail_dsn_checkbox', - 'storetarget' => 'rcmail_store_target_selection', - 'addressbooks' => 'rcmail_addressbook_list', - 'addresslist' => 'rcmail_contacts_list', - 'responseslist' => 'rcmail_compose_responses_list', -)); - -$OUTPUT->send('compose'); diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 00d66a0d0..0211fabc4 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -5,7 +5,7 @@ | program/steps/mail/func.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2012, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -16,44 +16,45 @@ | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli <roundcube@gmail.com> | + | Author: Aleksander Machniak <alec@alec.pl> | +-----------------------------------------------------------------------+ */ -// setup some global vars used by mail steps -$SENT_MBOX = $RCMAIL->config->get('sent_mbox'); -$DRAFTS_MBOX = $RCMAIL->config->get('drafts_mbox'); -$SEARCH_MODS_DEFAULT = array( - '*' => array('subject'=>1, 'from'=>1), - $SENT_MBOX => array('subject'=>1, 'to'=>1), - $DRAFTS_MBOX => array('subject'=>1, 'to'=>1) -); - // always instantiate storage object (but not connect to server yet) $RCMAIL->storage_init(); // set imap properties and session vars -if (strlen(trim($mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)))) - $RCMAIL->storage->set_folder(($_SESSION['mbox'] = $mbox)); -else if ($RCMAIL->storage) - $_SESSION['mbox'] = $RCMAIL->storage->get_folder(); +if (strlen(trim($mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)))) { + $RCMAIL->storage->set_folder(($_SESSION['mbox'] = $mbox)); +} +else if ($RCMAIL->storage) { + $_SESSION['mbox'] = $RCMAIL->storage->get_folder(); +} -if (!empty($_GET['_page'])) - $RCMAIL->storage->set_page(($_SESSION['page'] = intval($_GET['_page']))); +if (!empty($_GET['_page'])) { + $RCMAIL->storage->set_page(($_SESSION['page'] = intval($_GET['_page']))); +} + +$a_threading = $RCMAIL->config->get('message_threading', array()); +$message_sort_col = $RCMAIL->config->get('message_sort_col'); +$message_sort_order = $RCMAIL->config->get('message_sort_col'); // set default sort col/order to session -if (!isset($_SESSION['sort_col'])) - $_SESSION['sort_col'] = !empty($CONFIG['message_sort_col']) ? $CONFIG['message_sort_col'] : ''; -if (!isset($_SESSION['sort_order'])) - $_SESSION['sort_order'] = strtoupper($CONFIG['message_sort_order']) == 'ASC' ? 'ASC' : 'DESC'; +if (!isset($_SESSION['sort_col'])) { + $_SESSION['sort_col'] = $message_sort_col ? $message_sort_col : ''; +} +if (!isset($_SESSION['sort_order'])) { + $_SESSION['sort_order'] = strtoupper($message_sort_order) == 'ASC' ? 'ASC' : 'DESC'; +} // set threads mode -$a_threading = $RCMAIL->config->get('message_threading', array()); if (isset($_GET['_threads'])) { - if ($_GET['_threads']) - $a_threading[$_SESSION['mbox']] = true; - else - unset($a_threading[$_SESSION['mbox']]); - $RCMAIL->user->save_prefs(array('message_threading' => $a_threading)); + if ($_GET['_threads']) + $a_threading[$_SESSION['mbox']] = true; + else + unset($a_threading[$_SESSION['mbox']]); + + $RCMAIL->user->save_prefs(array('message_threading' => $a_threading)); } $RCMAIL->storage->set_threading($a_threading[$_SESSION['mbox']]); @@ -61,88 +62,91 @@ $RCMAIL->storage->set_threading($a_threading[$_SESSION['mbox']]); if (!empty($_REQUEST['_search']) && isset($_SESSION['search']) && $_SESSION['search_request'] == $_REQUEST['_search'] ) { - $RCMAIL->storage->set_search_set($_SESSION['search']); - $OUTPUT->set_env('search_request', $_REQUEST['_search']); - $OUTPUT->set_env('search_text', $_SESSION['last_text_search']); + $RCMAIL->storage->set_search_set($_SESSION['search']); + + $OUTPUT->set_env('search_request', $_REQUEST['_search']); + $OUTPUT->set_env('search_text', $_SESSION['last_text_search']); } // set main env variables, labels and page title if (empty($RCMAIL->action) || $RCMAIL->action == 'list') { - // connect to storage server and trigger error on failure - $RCMAIL->storage_connect(); - - $mbox_name = $RCMAIL->storage->get_folder(); - - if (empty($RCMAIL->action)) { - // initialize searching result if search_filter is used - if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') { - $search_request = md5($mbox_name.$_SESSION['search_filter']); - - $RCMAIL->storage->search($mbox_name, $_SESSION['search_filter'], RCUBE_CHARSET, rcmail_sort_column()); - $_SESSION['search'] = $RCMAIL->storage->get_search_set(); - $_SESSION['search_request'] = $search_request; - $OUTPUT->set_env('search_request', $search_request); - } - - $search_mods = $RCMAIL->config->get('search_mods', $SEARCH_MODS_DEFAULT); - $OUTPUT->set_env('search_mods', $search_mods); - } - - $threading = (bool) $RCMAIL->storage->get_threading(); - $delimiter = $RCMAIL->storage->get_hierarchy_delimiter(); - - // set current mailbox and some other vars in client environment - $OUTPUT->set_env('mailbox', $mbox_name); - $OUTPUT->set_env('pagesize', $RCMAIL->storage->get_pagesize()); - $OUTPUT->set_env('delimiter', $delimiter); - $OUTPUT->set_env('threading', $threading); - $OUTPUT->set_env('threads', $threading || $RCMAIL->storage->get_capability('THREAD')); - $OUTPUT->set_env('reply_all_mode', (int) $RCMAIL->config->get('reply_all_mode')); - $OUTPUT->set_env('preview_pane_mark_read', $RCMAIL->config->get('preview_pane_mark_read', 0)); - if ($RCMAIL->storage->get_capability('QUOTA')) { - $OUTPUT->set_env('quota', true); - } - - foreach (array('delete_junk','flag_for_deletion','read_when_deleted','skip_deleted','display_next','message_extwin','compose_extwin','forward_attachment') as $prop) { - if ($CONFIG[$prop]) - $OUTPUT->set_env($prop, true); - } - - if ($CONFIG['trash_mbox']) - $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']); - if ($CONFIG['drafts_mbox']) - $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']); - if ($CONFIG['junk_mbox']) - $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']); - - if (!empty($_SESSION['browser_caps'])) - $OUTPUT->set_env('browser_capabilities', $_SESSION['browser_caps']); - - if (!$OUTPUT->ajax_call) - $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', - 'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage', - 'copy', 'move', 'quota', 'replyall', 'replylist', 'importwait'); - - $pagetitle = $RCMAIL->localize_foldername($RCMAIL->storage->mod_folder($mbox_name), true); - $pagetitle = str_replace($delimiter, " \xC2\xBB ", $pagetitle); - - $OUTPUT->set_pagetitle($pagetitle); + // connect to storage server and trigger error on failure + $RCMAIL->storage_connect(); + + $mbox_name = $RCMAIL->storage->get_folder(); + + if (empty($RCMAIL->action)) { + // initialize searching result if search_filter is used + if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') { + $RCMAIL->storage->search($mbox_name, $_SESSION['search_filter'], RCUBE_CHARSET, rcmail_sort_column()); + + $search_request = md5($mbox_name.$_SESSION['search_filter']); + $_SESSION['search'] = $RCMAIL->storage->get_search_set(); + $_SESSION['search_request'] = $search_request; + + $OUTPUT->set_env('search_request', $search_request); + } + + $OUTPUT->set_env('search_mods', rcmail_search_mods()); + } + + $threading = (bool) $RCMAIL->storage->get_threading(); + $delimiter = $RCMAIL->storage->get_hierarchy_delimiter(); + + // set current mailbox and some other vars in client environment + $OUTPUT->set_env('mailbox', $mbox_name); + $OUTPUT->set_env('pagesize', $RCMAIL->storage->get_pagesize()); + $OUTPUT->set_env('delimiter', $delimiter); + $OUTPUT->set_env('threading', $threading); + $OUTPUT->set_env('threads', $threading || $RCMAIL->storage->get_capability('THREAD')); + $OUTPUT->set_env('reply_all_mode', (int) $RCMAIL->config->get('reply_all_mode')); + $OUTPUT->set_env('preview_pane_mark_read', $RCMAIL->config->get('preview_pane_mark_read', 0)); + + if ($RCMAIL->storage->get_capability('QUOTA')) { + $OUTPUT->set_env('quota', true); + } + + // set special folders + foreach (array('drafts', 'trash', 'junk') as $mbox) { + if ($folder = $RCMAIL->config->get($mbox . '_mbox')) { + $OUTPUT->set_env($mbox . '_mailbox', $folder); + } + } + + // set configuration + $RCMAIL->set_env_config(array('delete_junk', 'flag_for_deletion', 'read_when_deleted', + 'skip_deleted', 'display_next', 'message_extwin', 'compose_extwin', 'forward_attachment')); + + if (!empty($_SESSION['browser_caps'])) { + $OUTPUT->set_env('browser_capabilities', $_SESSION['browser_caps']); + } + + if (!$OUTPUT->ajax_call) { + $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', + 'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage', + 'copy', 'move', 'quota', 'replyall', 'replylist', 'importwait'); + } + + $pagetitle = $RCMAIL->localize_foldername($RCMAIL->storage->mod_folder($mbox_name), true); + $pagetitle = str_replace($delimiter, " \xC2\xBB ", $pagetitle); + + $OUTPUT->set_pagetitle($pagetitle); } // register UI objects $OUTPUT->add_handlers(array( - 'mailboxlist' => array($RCMAIL, 'folder_list'), - 'messages' => 'rcmail_message_list', - 'messagecountdisplay' => 'rcmail_messagecount_display', - 'quotadisplay' => array($RCMAIL, 'quota_display'), - 'mailboxname' => 'rcmail_mailbox_name_display', - 'messageheaders' => 'rcmail_message_headers', - 'messagefullheaders' => 'rcmail_message_full_headers', - 'messagebody' => 'rcmail_message_body', - 'messagecontentframe' => 'rcmail_messagecontent_frame', - 'messageimportform' => 'rcmail_message_import_form', - 'searchfilter' => 'rcmail_search_filter', - 'searchform' => array($OUTPUT, 'search_form'), + 'mailboxlist' => array($RCMAIL, 'folder_list'), + 'quotadisplay' => array($RCMAIL, 'quota_display'), + 'messages' => 'rcmail_message_list', + 'messagecountdisplay' => 'rcmail_messagecount_display', + 'mailboxname' => 'rcmail_mailbox_name_display', + 'messageheaders' => 'rcmail_message_headers', + 'messagefullheaders' => 'rcmail_message_full_headers', + 'messagebody' => 'rcmail_message_body', + 'messagecontentframe' => 'rcmail_messagecontent_frame', + 'messageimportform' => 'rcmail_message_import_form', + 'searchfilter' => 'rcmail_search_filter', + 'searchform' => array($OUTPUT, 'search_form'), )); // register action aliases @@ -164,6 +168,28 @@ $RCMAIL->register_action_map(array( /** + * Returns default search mods + */ +function rcmail_search_mods() +{ + global $RCMAIL; + + $mods = $RCMAIL->config->get('search_mods'); + + if (empty($mods)) { + $mods = array('*' => array('subject' => 1, 'from' => 1)); + + foreach (array('sent', 'drafts') as $mbox) { + if ($mbox = $RCMAIL->config->get($mbox . '_mbox')) { + $mods[$mbox] = array('subject' => 1, 'to' => 1); + } + } + } + + return $mods; +} + +/** * Returns 'to' if current folder is configured Sent or Drafts * or their subfolders, otherwise returns 'from'. * @@ -171,20 +197,20 @@ $RCMAIL->register_action_map(array( */ function rcmail_message_list_smart_column_name() { - global $RCMAIL; + global $RCMAIL; - $delim = $RCMAIL->storage->get_hierarchy_delimiter(); - $mbox = $RCMAIL->storage->get_folder(); - $sent_mbox = $RCMAIL->config->get('sent_mbox'); - $drafts_mbox = $RCMAIL->config->get('drafts_mbox'); + $delim = $RCMAIL->storage->get_hierarchy_delimiter(); + $mbox = $RCMAIL->storage->get_folder(); + $sent_mbox = $RCMAIL->config->get('sent_mbox'); + $drafts_mbox = $RCMAIL->config->get('drafts_mbox'); - if ((strpos($mbox.$delim, $sent_mbox.$delim) === 0 || strpos($mbox.$delim, $drafts_mbox.$delim) === 0) - && strtoupper($mbox) != 'INBOX' - ) { - return 'to'; - } + if ((strpos($mbox.$delim, $sent_mbox.$delim) === 0 || strpos($mbox.$delim, $drafts_mbox.$delim) === 0) + && strtoupper($mbox) != 'INBOX' + ) { + return 'to'; + } - return 'from'; + return 'from'; } /** @@ -196,21 +222,21 @@ function rcmail_message_list_smart_column_name() */ function rcmail_sort_column() { - global $RCMAIL; + global $RCMAIL; - if (isset($_SESSION['sort_col'])) { - $column = $_SESSION['sort_col']; - } - else { - $column = $RCMAIL->config->get('message_sort_col'); - } + if (isset($_SESSION['sort_col'])) { + $column = $_SESSION['sort_col']; + } + else { + $column = $RCMAIL->config->get('message_sort_col'); + } - // get name of smart From/To column in folder context - if ($column == 'fromto') { - $column = rcmail_message_list_smart_column_name(); - } + // get name of smart From/To column in folder context + if ($column == 'fromto') { + $column = rcmail_message_list_smart_column_name(); + } - return $column; + return $column; } /** @@ -220,13 +246,13 @@ function rcmail_sort_column() */ function rcmail_sort_order() { - global $RCMAIL; + global $RCMAIL; - if (isset($_SESSION['sort_order'])) { - return $_SESSION['sort_order']; - } + if (isset($_SESSION['sort_order'])) { + return $_SESSION['sort_order']; + } - return $RCMAIL->config->get('message_sort_order'); + return $RCMAIL->config->get('message_sort_order'); } /** @@ -234,390 +260,396 @@ function rcmail_sort_order() */ function rcmail_message_list($attrib) { - global $CONFIG, $OUTPUT; - - // add some labels to client - $OUTPUT->add_label('from', 'to'); - - // add id to message list table if not specified - if (!strlen($attrib['id'])) - $attrib['id'] = 'rcubemessagelist'; - - // define list of cols to be displayed based on parameter or config - if (empty($attrib['columns'])) { - $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject'); - $OUTPUT->set_env('col_movable', !in_array('list_cols', (array)$CONFIG['dont_override'])); - } - else { - $a_show_cols = preg_split('/[\s,;]+/', str_replace(array("'", '"'), '', $attrib['columns'])); - $attrib['columns'] = $a_show_cols; - } - - // save some variables for use in ajax list - $_SESSION['list_attrib'] = $attrib; - // make sure 'threads' and 'subject' columns are present - if (!in_array('subject', $a_show_cols)) - array_unshift($a_show_cols, 'subject'); - if (!in_array('threads', $a_show_cols)) - array_unshift($a_show_cols, 'threads'); - - $_SESSION['skin_path'] = $CONFIG['skin_path']; - - // set client env - $OUTPUT->add_gui_object('messagelist', $attrib['id']); - $OUTPUT->set_env('autoexpand_threads', intval($CONFIG['autoexpand_threads'])); - $OUTPUT->set_env('sort_col', $_SESSION['sort_col']); - $OUTPUT->set_env('sort_order', $_SESSION['sort_order']); - $OUTPUT->set_env('messages', array()); - $OUTPUT->set_env('coltypes', $a_show_cols); - - $OUTPUT->include_script('list.js'); - - $table = new html_table($attrib); - if (!$attrib['noheader']) { - foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell) - $table->add_header(array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']); - } - - return $table->show(); -} + global $RCMAIL, $OUTPUT; + + // add some labels to client + $OUTPUT->add_label('from', 'to'); + + // add id to message list table if not specified + if (!strlen($attrib['id'])) + $attrib['id'] = 'rcubemessagelist'; + + // define list of cols to be displayed based on parameter or config + if (empty($attrib['columns'])) { + $list_cols = $RCMAIL->config->get('list_cols'); + $a_show_cols = !empty($list_cols) && is_array($list_cols) ? $list_cols : array('subject'); + + $OUTPUT->set_env('col_movable', !in_array('list_cols', (array)$RCMAIL->config->get('dont_override'))); + } + else { + $a_show_cols = preg_split('/[\s,;]+/', str_replace(array("'", '"'), '', $attrib['columns'])); + $attrib['columns'] = $a_show_cols; + } + + // save some variables for use in ajax list + $_SESSION['list_attrib'] = $attrib; + + // make sure 'threads' and 'subject' columns are present + if (!in_array('subject', $a_show_cols)) + array_unshift($a_show_cols, 'subject'); + if (!in_array('threads', $a_show_cols)) + array_unshift($a_show_cols, 'threads'); + + $_SESSION['skin_path'] = $RCMAIL->config->get('skin_path'); + // set client env + $OUTPUT->add_gui_object('messagelist', $attrib['id']); + $OUTPUT->set_env('autoexpand_threads', intval($RCMAIL->config->get('autoexpand_threads'))); + $OUTPUT->set_env('sort_col', $_SESSION['sort_col']); + $OUTPUT->set_env('sort_order', $_SESSION['sort_order']); + $OUTPUT->set_env('messages', array()); + $OUTPUT->set_env('coltypes', $a_show_cols); + + $OUTPUT->include_script('list.js'); + + $table = new html_table($attrib); + + if (!$attrib['noheader']) { + foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell) + $table->add_header(array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']); + } + + return $table->show(); +} /** * return javascript commands to add rows to the message list */ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null) { - global $CONFIG, $RCMAIL, $OUTPUT; + global $RCMAIL, $OUTPUT; - if (empty($a_show_cols)) { - if (!empty($_SESSION['list_attrib']['columns'])) - $a_show_cols = $_SESSION['list_attrib']['columns']; - else - $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject'); - } - else { - if (!is_array($a_show_cols)) - $a_show_cols = preg_split('/[\s,;]+/', str_replace(array("'", '"'), '', $a_show_cols)); - $head_replace = true; - } + if (empty($a_show_cols)) { + if (!empty($_SESSION['list_attrib']['columns'])) + $a_show_cols = $_SESSION['list_attrib']['columns']; + else { + $list_cols = $RCMAIL->config->get('list_cols'); + $a_show_cols = !empty($list_cols) && is_array($list_cols) ? $list_cols : array('subject'); + } + } + else { + if (!is_array($a_show_cols)) { + $a_show_cols = preg_split('/[\s,;]+/', str_replace(array("'", '"'), '', $a_show_cols)); + } + $head_replace = true; + } - $mbox = $RCMAIL->storage->get_folder(); + $mbox = $RCMAIL->storage->get_folder(); - // make sure 'threads' and 'subject' columns are present - if (!in_array('subject', $a_show_cols)) - array_unshift($a_show_cols, 'subject'); - if (!in_array('threads', $a_show_cols)) - array_unshift($a_show_cols, 'threads'); + // make sure 'threads' and 'subject' columns are present + if (!in_array('subject', $a_show_cols)) + array_unshift($a_show_cols, 'subject'); + if (!in_array('threads', $a_show_cols)) + array_unshift($a_show_cols, 'threads'); - $_SESSION['list_attrib']['columns'] = $a_show_cols; + $_SESSION['list_attrib']['columns'] = $a_show_cols; - // Make sure there are no duplicated columns (#1486999) - $a_show_cols = array_unique($a_show_cols); + // Make sure there are no duplicated columns (#1486999) + $a_show_cols = array_unique($a_show_cols); - // Plugins may set header's list_cols/list_flags and other rcube_message_header variables - // and list columns - $plugin = $RCMAIL->plugins->exec_hook('messages_list', - array('messages' => $a_headers, 'cols' => $a_show_cols)); + // Plugins may set header's list_cols/list_flags and other rcube_message_header variables + // and list columns + $plugin = $RCMAIL->plugins->exec_hook('messages_list', + array('messages' => $a_headers, 'cols' => $a_show_cols)); - $a_show_cols = $plugin['cols']; - $a_headers = $plugin['messages']; + $a_show_cols = $plugin['cols']; + $a_headers = $plugin['messages']; - $thead = $head_replace ? rcmail_message_list_head($_SESSION['list_attrib'], $a_show_cols) : NULL; + $thead = $head_replace ? rcmail_message_list_head($_SESSION['list_attrib'], $a_show_cols) : NULL; - // get name of smart From/To column in folder context - if (array_search('fromto', $a_show_cols) !== false) { - $smart_col = rcmail_message_list_smart_column_name(); - } + // get name of smart From/To column in folder context + if (array_search('fromto', $a_show_cols) !== false) { + $smart_col = rcmail_message_list_smart_column_name(); + } - $OUTPUT->command('set_message_coltypes', $a_show_cols, $thead, $smart_col); + $OUTPUT->command('set_message_coltypes', $a_show_cols, $thead, $smart_col); - if (empty($a_headers)) - return; + if (empty($a_headers)) { + return; + } - // remove 'threads', 'attachment', 'flag', 'status' columns, we don't need them here - foreach (array('threads', 'attachment', 'flag', 'status', 'priority') as $col) { - if (($key = array_search($col, $a_show_cols)) !== FALSE) - unset($a_show_cols[$key]); - } + // remove 'threads', 'attachment', 'flag', 'status' columns, we don't need them here + foreach (array('threads', 'attachment', 'flag', 'status', 'priority') as $col) { + if (($key = array_search($col, $a_show_cols)) !== FALSE) { + unset($a_show_cols[$key]); + } + } - // loop through message headers - foreach ($a_headers as $header) { - if (empty($header)) - continue; + // loop through message headers + foreach ($a_headers as $header) { + if (empty($header)) + continue; - $a_msg_cols = array(); - $a_msg_flags = array(); + $a_msg_cols = array(); + $a_msg_flags = array(); - // format each col; similar as in rcmail_message_list() - foreach ($a_show_cols as $col) { - $col_name = $col == 'fromto' ? $smart_col : $col; - - if (in_array($col_name, array('from', 'to', 'cc', 'replyto'))) - $cont = rcmail_address_string($header->$col_name, 3, false, null, $header->charset); - else if ($col == 'subject') { - $cont = trim(rcube_mime::decode_header($header->$col, $header->charset)); - if (!$cont) $cont = $RCMAIL->gettext('nosubject'); - $cont = rcube::Q($cont); - } - else if ($col == 'size') - $cont = show_bytes($header->$col); - else if ($col == 'date') - $cont = $RCMAIL->format_date($header->date); - else - $cont = rcube::Q($header->$col); - - $a_msg_cols[$col] = $cont; - } - - $a_msg_flags = array_change_key_case(array_map('intval', (array) $header->flags)); - if ($header->depth) - $a_msg_flags['depth'] = $header->depth; - else if ($header->has_children) - $roots[] = $header->uid; - if ($header->parent_uid) - $a_msg_flags['parent_uid'] = $header->parent_uid; - if ($header->has_children) - $a_msg_flags['has_children'] = $header->has_children; - if ($header->unread_children) - $a_msg_flags['unread_children'] = $header->unread_children; - if ($header->others['list-post']) - $a_msg_flags['ml'] = 1; - if ($header->priority) - $a_msg_flags['prio'] = (int) $header->priority; - - $a_msg_flags['ctype'] = rcube::Q($header->ctype); - $a_msg_flags['mbox'] = $mbox; - - // merge with plugin result (Deprecated, use $header->flags) - if (!empty($header->list_flags) && is_array($header->list_flags)) - $a_msg_flags = array_merge($a_msg_flags, $header->list_flags); - if (!empty($header->list_cols) && is_array($header->list_cols)) - $a_msg_cols = array_merge($a_msg_cols, $header->list_cols); - - $OUTPUT->command('add_message_row', - $header->uid, - $a_msg_cols, - $a_msg_flags, - $insert_top); - } - - if ($RCMAIL->storage->get_threading()) { - $OUTPUT->command('init_threads', (array) $roots, $mbox); - } -} + // format each col; similar as in rcmail_message_list() + foreach ($a_show_cols as $col) { + $col_name = $col == 'fromto' ? $smart_col : $col; + if (in_array($col_name, array('from', 'to', 'cc', 'replyto'))) + $cont = rcmail_address_string($header->$col_name, 3, false, null, $header->charset); + else if ($col == 'subject') { + $cont = trim(rcube_mime::decode_header($header->$col, $header->charset)); + if (!$cont) $cont = $RCMAIL->gettext('nosubject'); + $cont = rcube::Q($cont); + } + else if ($col == 'size') + $cont = show_bytes($header->$col); + else if ($col == 'date') + $cont = $RCMAIL->format_date($header->date); + else + $cont = rcube::Q($header->$col); + + $a_msg_cols[$col] = $cont; + } + + $a_msg_flags = array_change_key_case(array_map('intval', (array) $header->flags)); + if ($header->depth) + $a_msg_flags['depth'] = $header->depth; + else if ($header->has_children) + $roots[] = $header->uid; + if ($header->parent_uid) + $a_msg_flags['parent_uid'] = $header->parent_uid; + if ($header->has_children) + $a_msg_flags['has_children'] = $header->has_children; + if ($header->unread_children) + $a_msg_flags['unread_children'] = $header->unread_children; + if ($header->others['list-post']) + $a_msg_flags['ml'] = 1; + if ($header->priority) + $a_msg_flags['prio'] = (int) $header->priority; + + $a_msg_flags['ctype'] = rcube::Q($header->ctype); + $a_msg_flags['mbox'] = $mbox; + + // merge with plugin result (Deprecated, use $header->flags) + if (!empty($header->list_flags) && is_array($header->list_flags)) + $a_msg_flags = array_merge($a_msg_flags, $header->list_flags); + if (!empty($header->list_cols) && is_array($header->list_cols)) + $a_msg_cols = array_merge($a_msg_cols, $header->list_cols); + + $OUTPUT->command('add_message_row', + $header->uid, + $a_msg_cols, + $a_msg_flags, + $insert_top); + } + + if ($RCMAIL->storage->get_threading()) { + $OUTPUT->command('init_threads', (array) $roots, $mbox); + } +} /* * Creates <THEAD> for message list table */ function rcmail_message_list_head($attrib, $a_show_cols) { - global $RCMAIL; - - $skin_path = $_SESSION['skin_path']; + global $RCMAIL; - // check to see if we have some settings for sorting - $sort_col = $_SESSION['sort_col']; - $sort_order = $_SESSION['sort_order']; + $skin_path = $_SESSION['skin_path']; - $dont_override = (array)$RCMAIL->config->get('dont_override'); - $disabled_sort = in_array('message_sort_col', $dont_override); - $disabled_order = in_array('message_sort_order', $dont_override); + // check to see if we have some settings for sorting + $sort_col = $_SESSION['sort_col']; + $sort_order = $_SESSION['sort_order']; - $RCMAIL->output->set_env('disabled_sort_col', $disabled_sort); - $RCMAIL->output->set_env('disabled_sort_order', $disabled_order); + $dont_override = (array) $RCMAIL->config->get('dont_override'); + $disabled_sort = in_array('message_sort_col', $dont_override); + $disabled_order = in_array('message_sort_order', $dont_override); - // define sortable columns - if ($disabled_sort) - $a_sort_cols = $sort_col && !$disabled_order ? array($sort_col) : array(); - else - $a_sort_cols = array('subject', 'date', 'from', 'to', 'fromto', 'size', 'cc'); + $RCMAIL->output->set_env('disabled_sort_col', $disabled_sort); + $RCMAIL->output->set_env('disabled_sort_order', $disabled_order); - if (!empty($attrib['optionsmenuicon'])) { - $onclick = 'return ' . rcmail_output::JS_OBJECT_NAME . ".command('menu-open', 'messagelistmenu')"; - if ($attrib['optionsmenuicon'] === true || $attrib['optionsmenuicon'] == 'true') - $list_menu = html::div(array('onclick' => $onclick, 'class' => 'listmenu', - 'id' => 'listmenulink', 'title' => $RCMAIL->gettext('listoptions'))); + // define sortable columns + if ($disabled_sort) + $a_sort_cols = $sort_col && !$disabled_order ? array($sort_col) : array(); else - $list_menu = html::a(array('href' => '#', 'onclick' => $onclick), - html::img(array('src' => $skin_path . $attrib['optionsmenuicon'], - 'id' => 'listmenulink', 'title' => $RCMAIL->gettext('listoptions'))) - ); - } - else - $list_menu = ''; - - $cells = array(); - - // get name of smart From/To column in folder context - if (array_search('fromto', $a_show_cols) !== false) { - $smart_col = rcmail_message_list_smart_column_name(); - } - - foreach ($a_show_cols as $col) { - // get column name - switch ($col) { - case 'flag': - $col_name = '<span class="flagged"> </span>'; - break; - case 'attachment': - case 'priority': - case 'status': - $col_name = '<span class="' . $col .'"> </span>'; - break; - case 'threads': - $col_name = $list_menu; - break; - case 'fromto': - $col_name = rcube::Q($RCMAIL->gettext($smart_col)); - break; - default: - $col_name = rcube::Q($RCMAIL->gettext($col)); + $a_sort_cols = array('subject', 'date', 'from', 'to', 'fromto', 'size', 'cc'); + + if (!empty($attrib['optionsmenuicon'])) { + $onclick = 'return ' . rcmail_output::JS_OBJECT_NAME . ".command('menu-open', 'messagelistmenu')"; + if ($attrib['optionsmenuicon'] === true || $attrib['optionsmenuicon'] == 'true') + $list_menu = html::div(array('onclick' => $onclick, 'class' => 'listmenu', + 'id' => 'listmenulink', 'title' => $RCMAIL->gettext('listoptions'))); + else + $list_menu = html::a(array('href' => '#', 'onclick' => $onclick), + html::img(array('src' => $skin_path . $attrib['optionsmenuicon'], + 'id' => 'listmenulink', 'title' => $RCMAIL->gettext('listoptions')))); + } + else { + $list_menu = ''; } - // make sort links - if (in_array($col, $a_sort_cols)) - $col_name = html::a(array('href'=>"./#sort", 'onclick' => 'return '.rcmail_output::JS_OBJECT_NAME.".command('sort','".$col."',this)", 'title' => $RCMAIL->gettext('sortby')), $col_name); - else if ($col_name[0] != '<') - $col_name = '<span class="' . $col .'">' . $col_name . '</span>'; + $cells = array(); - $sort_class = $col == $sort_col && !$disabled_order ? " sorted$sort_order" : ''; - $class_name = $col.$sort_class; + // get name of smart From/To column in folder context + if (array_search('fromto', $a_show_cols) !== false) { + $smart_col = rcmail_message_list_smart_column_name(); + } - // put it all together - $cells[] = array('className' => $class_name, 'id' => "rcm$col", 'html' => $col_name); - } + foreach ($a_show_cols as $col) { + // get column name + switch ($col) { + case 'flag': + $col_name = '<span class="flagged"> </span>'; + break; + case 'attachment': + case 'priority': + case 'status': + $col_name = '<span class="' . $col .'"> </span>'; + break; + case 'threads': + $col_name = $list_menu; + break; + case 'fromto': + $col_name = rcube::Q($RCMAIL->gettext($smart_col)); + break; + default: + $col_name = rcube::Q($RCMAIL->gettext($col)); + } - return $cells; -} + // make sort links + if (in_array($col, $a_sort_cols)) { + $col_name = html::a(array( + 'href' => "./#sort", + 'onclick' => 'return '.rcmail_output::JS_OBJECT_NAME.".command('sort','".$col."',this)", + 'title' => $RCMAIL->gettext('sortby') + ), $col_name); + } + else if ($col_name[0] != '<') { + $col_name = '<span class="' . $col .'">' . $col_name . '</span>'; + } + $sort_class = $col == $sort_col && !$disabled_order ? " sorted$sort_order" : ''; + $class_name = $col.$sort_class; + + // put it all together + $cells[] = array('className' => $class_name, 'id' => "rcm$col", 'html' => $col_name); + } + + return $cells; +} /** * return an HTML iframe for loading mail content */ function rcmail_messagecontent_frame($attrib) { - global $OUTPUT, $RCMAIL; + global $OUTPUT, $RCMAIL; - if (empty($attrib['id'])) - $attrib['id'] = 'rcmailcontentwindow'; + if (empty($attrib['id'])) + $attrib['id'] = 'rcmailcontentwindow'; - $attrib['name'] = $attrib['id']; + $attrib['name'] = $attrib['id']; - if ($RCMAIL->config->get('preview_pane')) - $OUTPUT->set_env('contentframe', $attrib['id']); - $OUTPUT->set_env('blankpage', $attrib['src'] ? $OUTPUT->abs_url($attrib['src']) : 'program/resources/blank.gif'); + if ($RCMAIL->config->get('preview_pane')) { + $OUTPUT->set_env('contentframe', $attrib['id']); + } - return $OUTPUT->frame($attrib, true); -} + $OUTPUT->set_env('blankpage', $attrib['src'] ? $OUTPUT->abs_url($attrib['src']) : 'program/resources/blank.gif'); + return $OUTPUT->frame($attrib, true); +} function rcmail_messagecount_display($attrib) { - global $RCMAIL; + global $RCMAIL; - if (!$attrib['id']) - $attrib['id'] = 'rcmcountdisplay'; + if (!$attrib['id']) + $attrib['id'] = 'rcmcountdisplay'; - $RCMAIL->output->add_gui_object('countdisplay', $attrib['id']); + $RCMAIL->output->add_gui_object('countdisplay', $attrib['id']); - $content = $RCMAIL->action != 'show' ? rcmail_get_messagecount_text() : $RCMAIL->gettext('loading'); + $content = $RCMAIL->action != 'show' ? rcmail_get_messagecount_text() : $RCMAIL->gettext('loading'); - return html::span($attrib, $content); + return html::span($attrib, $content); } - -function rcmail_get_messagecount_text($count=NULL, $page=NULL) +function rcmail_get_messagecount_text($count = null, $page = null) { - global $RCMAIL; + global $RCMAIL; - if ($page === NULL) { - $page = $RCMAIL->storage->get_page(); - } + if ($page === null) { + $page = $RCMAIL->storage->get_page(); + } - $page_size = $RCMAIL->storage->get_pagesize(); - $start_msg = ($page-1) * $page_size + 1; + $page_size = $RCMAIL->storage->get_pagesize(); + $start_msg = ($page-1) * $page_size + 1; - if ($count!==NULL) - $max = $count; - else if ($RCMAIL->action) - $max = $RCMAIL->storage->count(NULL, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'); + if ($count !== null) + $max = $count; + else if ($RCMAIL->action) + $max = $RCMAIL->storage->count(NULL, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'); - if ($max==0) - $out = $RCMAIL->gettext('mailboxempty'); - else - $out = $RCMAIL->gettext(array('name' => $RCMAIL->storage->get_threading() ? 'threadsfromto' : 'messagesfromto', + if ($max == 0) + $out = $RCMAIL->gettext('mailboxempty'); + else + $out = $RCMAIL->gettext(array('name' => $RCMAIL->storage->get_threading() ? 'threadsfromto' : 'messagesfromto', 'vars' => array('from' => $start_msg, 'to' => min($max, $start_msg + $page_size - 1), 'count' => $max))); - return rcube::Q($out); + return rcube::Q($out); } - function rcmail_mailbox_name_display($attrib) { - global $RCMAIL; + global $RCMAIL; - if (!$attrib['id']) - $attrib['id'] = 'rcmmailboxname'; + if (!$attrib['id']) + $attrib['id'] = 'rcmmailboxname'; - $RCMAIL->output->add_gui_object('mailboxname', $attrib['id']); + $RCMAIL->output->add_gui_object('mailboxname', $attrib['id']); - return html::span($attrib, rcmail_get_mailbox_name_text()); + return html::span($attrib, rcmail_get_mailbox_name_text()); } - function rcmail_get_mailbox_name_text() { - global $RCMAIL; - return $RCMAIL->localize_foldername($RCMAIL->storage->get_folder()); + global $RCMAIL; + return $RCMAIL->localize_foldername($RCMAIL->storage->get_folder()); } - function rcmail_send_unread_count($mbox_name, $force=false, $count=null, $mark='') { - global $RCMAIL; + global $RCMAIL; - $old_unseen = rcmail_get_unseen_count($mbox_name); + $old_unseen = rcmail_get_unseen_count($mbox_name); - if ($count === null) - $unseen = $RCMAIL->storage->count($mbox_name, 'UNSEEN', $force); - else - $unseen = $count; + if ($count === null) + $unseen = $RCMAIL->storage->count($mbox_name, 'UNSEEN', $force); + else + $unseen = $count; - if ($unseen != $old_unseen || ($mbox_name == 'INBOX')) - $RCMAIL->output->command('set_unread_count', $mbox_name, $unseen, - ($mbox_name == 'INBOX'), $unseen && $mark ? $mark : ''); + if ($unseen != $old_unseen || ($mbox_name == 'INBOX')) + $RCMAIL->output->command('set_unread_count', $mbox_name, $unseen, + ($mbox_name == 'INBOX'), $unseen && $mark ? $mark : ''); - rcmail_set_unseen_count($mbox_name, $unseen); + rcmail_set_unseen_count($mbox_name, $unseen); - return $unseen; + return $unseen; } - function rcmail_set_unseen_count($mbox_name, $count) { - // @TODO: this data is doubled (session and cache tables) if caching is enabled + // @TODO: this data is doubled (session and cache tables) if caching is enabled - // Make sure we have an array here (#1487066) - if (!is_array($_SESSION['unseen_count'])) - $_SESSION['unseen_count'] = array(); + // Make sure we have an array here (#1487066) + if (!is_array($_SESSION['unseen_count'])) { + $_SESSION['unseen_count'] = array(); + } - $_SESSION['unseen_count'][$mbox_name] = $count; + $_SESSION['unseen_count'][$mbox_name] = $count; } - function rcmail_get_unseen_count($mbox_name) { - if (is_array($_SESSION['unseen_count']) && array_key_exists($mbox_name, $_SESSION['unseen_count'])) - return $_SESSION['unseen_count'][$mbox_name]; - else - return null; + if (is_array($_SESSION['unseen_count']) && array_key_exists($mbox_name, $_SESSION['unseen_count'])) { + return $_SESSION['unseen_count'][$mbox_name]; + } } - /** * Sets message is_safe flag according to 'show_images' option value * @@ -625,35 +657,34 @@ function rcmail_get_unseen_count($mbox_name) */ function rcmail_check_safe(&$message) { - global $RCMAIL; - - if (!$message->is_safe - && ($show_images = $RCMAIL->config->get('show_images')) - && $message->has_html_part() - ) { - switch ($show_images) { - case 1: // known senders only - // get default addressbook, like in addcontact.inc - $CONTACTS = $RCMAIL->get_address_book(-1, true); - - if ($CONTACTS) { - $result = $CONTACTS->search('email', $message->sender['mailto'], 1, false); - if ($result->count) { - $message->set_safe(true); - } - } + global $RCMAIL; - $RCMAIL->plugins->exec_hook('message_check_safe', array('message' => $message)); - break; + if (!$message->is_safe + && ($show_images = $RCMAIL->config->get('show_images')) + && $message->has_html_part() + ) { + switch ($show_images) { + case 1: // known senders only + // get default addressbook, like in addcontact.inc + $CONTACTS = $RCMAIL->get_address_book(-1, true); + + if ($CONTACTS) { + $result = $CONTACTS->search('email', $message->sender['mailto'], 1, false); + if ($result->count) { + $message->set_safe(true); + } + } - case 2: // always - $message->set_safe(true); - break; + $RCMAIL->plugins->exec_hook('message_check_safe', array('message' => $message)); + break; + + case 2: // always + $message->set_safe(true); + break; + } } - } } - /** * Cleans up the given message HTML Body (for displaying) * @@ -664,66 +695,67 @@ function rcmail_check_safe(&$message) */ function rcmail_wash_html($html, $p, $cid_replaces) { - global $REMOTE_OBJECTS; - - $p += array('safe' => false, 'inline_html' => true); - - // charset was converted to UTF-8 in rcube_storage::get_message_part(), - // change/add charset specification in HTML accordingly, - // washtml cannot work without that - $meta = '<meta http-equiv="Content-Type" content="text/html; charset='.RCUBE_CHARSET.'" />'; - - // remove old meta tag and add the new one, making sure - // that it is placed in the head (#1488093) - $html = preg_replace('/<meta[^>]+charset=[a-z0-9-_]+[^>]*>/Ui', '', $html); - $html = preg_replace('/(<head[^>]*>)/Ui', '\\1'.$meta, $html, -1, $rcount); - if (!$rcount) { - $html = '<head>' . $meta . '</head>' . $html; - } - - // clean HTML with washhtml by Frederic Motte - $wash_opts = array( - 'show_washed' => false, - 'allow_remote' => $p['safe'], - 'blocked_src' => "./program/resources/blocked.gif", - 'charset' => RCUBE_CHARSET, - 'cid_map' => $cid_replaces, - 'html_elements' => array('body'), - ); - - if (!$p['inline_html']) { - $wash_opts['html_elements'] = array('html','head','title','body'); - } - if ($p['safe']) { - $wash_opts['html_elements'][] = 'link'; - $wash_opts['html_attribs'] = array('rel','type'); - } - - // overwrite washer options with options from plugins - if (isset($p['html_elements'])) - $wash_opts['html_elements'] = $p['html_elements']; - if (isset($p['html_attribs'])) - $wash_opts['html_attribs'] = $p['html_attribs']; - - // initialize HTML washer - $washer = new rcube_washtml($wash_opts); - - if (!$p['skip_washer_form_callback']) - $washer->add_callback('form', 'rcmail_washtml_callback'); - - // allow CSS styles, will be sanitized by rcmail_washtml_callback() - if (!$p['skip_washer_style_callback']) - $washer->add_callback('style', 'rcmail_washtml_callback'); - - // Remove non-UTF8 characters (#1487813) - $html = rcube_charset::clean($html); - - $html = $washer->wash($html); - $REMOTE_OBJECTS = $washer->extlinks; - - return $html; -} + global $REMOTE_OBJECTS; + + $p += array('safe' => false, 'inline_html' => true); + + // charset was converted to UTF-8 in rcube_storage::get_message_part(), + // change/add charset specification in HTML accordingly, + // washtml cannot work without that + $meta = '<meta http-equiv="Content-Type" content="text/html; charset='.RCUBE_CHARSET.'" />'; + + // remove old meta tag and add the new one, making sure + // that it is placed in the head (#1488093) + $html = preg_replace('/<meta[^>]+charset=[a-z0-9-_]+[^>]*>/Ui', '', $html); + $html = preg_replace('/(<head[^>]*>)/Ui', '\\1'.$meta, $html, -1, $rcount); + if (!$rcount) { + $html = '<head>' . $meta . '</head>' . $html; + } + + // clean HTML with washhtml by Frederic Motte + $wash_opts = array( + 'show_washed' => false, + 'allow_remote' => $p['safe'], + 'blocked_src' => "./program/resources/blocked.gif", + 'charset' => RCUBE_CHARSET, + 'cid_map' => $cid_replaces, + 'html_elements' => array('body'), + ); + + if (!$p['inline_html']) { + $wash_opts['html_elements'] = array('html','head','title','body'); + } + if ($p['safe']) { + $wash_opts['html_elements'][] = 'link'; + $wash_opts['html_attribs'] = array('rel','type'); + } + + // overwrite washer options with options from plugins + if (isset($p['html_elements'])) + $wash_opts['html_elements'] = $p['html_elements']; + if (isset($p['html_attribs'])) + $wash_opts['html_attribs'] = $p['html_attribs']; + + // initialize HTML washer + $washer = new rcube_washtml($wash_opts); + + if (!$p['skip_washer_form_callback']) { + $washer->add_callback('form', 'rcmail_washtml_callback'); + } + + // allow CSS styles, will be sanitized by rcmail_washtml_callback() + if (!$p['skip_washer_style_callback']) { + $washer->add_callback('style', 'rcmail_washtml_callback'); + } + + // Remove non-UTF8 characters (#1487813) + $html = rcube_charset::clean($html); + + $html = $washer->wash($html); + $REMOTE_OBJECTS = $washer->extlinks; + return $html; +} /** * Convert the given message part to proper HTML @@ -735,58 +767,58 @@ function rcmail_wash_html($html, $p, $cid_replaces) */ function rcmail_print_body($part, $p = array()) { - global $RCMAIL; - - // trigger plugin hook - $data = $RCMAIL->plugins->exec_hook('message_part_before', - array('type' => $part->ctype_secondary, 'body' => $part->body, 'id' => $part->mime_id) - + $p + array('safe' => false, 'plain' => false, 'inline_html' => true)); - - // convert html to text/plain - if ($data['plain'] && ($data['type'] == 'html' || $data['type'] == 'enriched')) { - if ($data['type'] == 'enriched') { - $data['body'] = rcube_enriched::to_html($data['body']); - } - $txt = new rcube_html2text($data['body'], false, true); - $body = $txt->get_text(); - $part->ctype_secondary = 'plain'; - } - // text/html - else if ($data['type'] == 'html') { - $body = rcmail_wash_html($data['body'], $data, $part->replaces); - $part->ctype_secondary = $data['type']; - } - // text/enriched - else if ($data['type'] == 'enriched') { - $body = rcube_enriched::to_html($data['body']); - $body = rcmail_wash_html($body, $data, $part->replaces); - $part->ctype_secondary = 'html'; - } - else { - // assert plaintext - $body = $part->body; - $part->ctype_secondary = $data['type'] = 'plain'; - } - - // free some memory (hopefully) - unset($data['body']); - - // plaintext postprocessing - if ($part->ctype_secondary == 'plain') { - if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { - $body = rcube_mime::unfold_flowed($body); - } - - $body = rcmail_plain_body($body); - } - - // allow post-processing of the message body - $data = $RCMAIL->plugins->exec_hook('message_part_after', - array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id) + $data); - - return $data['type'] == 'html' ? $data['body'] : html::tag('pre', array(), $data['body']); -} + global $RCMAIL; + + // trigger plugin hook + $data = $RCMAIL->plugins->exec_hook('message_part_before', + array('type' => $part->ctype_secondary, 'body' => $part->body, 'id' => $part->mime_id) + + $p + array('safe' => false, 'plain' => false, 'inline_html' => true)); + + // convert html to text/plain + if ($data['plain'] && ($data['type'] == 'html' || $data['type'] == 'enriched')) { + if ($data['type'] == 'enriched') { + $data['body'] = rcube_enriched::to_html($data['body']); + } + + $txt = new rcube_html2text($data['body'], false, true); + $body = $txt->get_text(); + $part->ctype_secondary = 'plain'; + } + // text/html + else if ($data['type'] == 'html') { + $body = rcmail_wash_html($data['body'], $data, $part->replaces); + $part->ctype_secondary = $data['type']; + } + // text/enriched + else if ($data['type'] == 'enriched') { + $body = rcube_enriched::to_html($data['body']); + $body = rcmail_wash_html($body, $data, $part->replaces); + $part->ctype_secondary = 'html'; + } + else { + // assert plaintext + $body = $part->body; + $part->ctype_secondary = $data['type'] = 'plain'; + } + + // free some memory (hopefully) + unset($data['body']); + // plaintext postprocessing + if ($part->ctype_secondary == 'plain') { + if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { + $body = rcube_mime::unfold_flowed($body); + } + + $body = rcmail_plain_body($body); + } + + // allow post-processing of the message body + $data = $RCMAIL->plugins->exec_hook('message_part_after', + array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id) + $data); + + return $data['type'] == 'html' ? $data['body'] : html::tag('pre', array(), $data['body']); +} /** * Handle links and citation marks in plain text message @@ -797,232 +829,245 @@ function rcmail_print_body($part, $p = array()) */ function rcmail_plain_body($body) { - global $RCMAIL; - - // make links and email-addresses clickable - $attribs = array('link_attribs' => array('rel' => 'noreferrer', 'target' => '_blank')); - $replacer = new rcmail_string_replacer($attribs); - - // search for patterns like links and e-mail addresses and replace with tokens - $body = $replacer->replace($body); - - // split body into single lines - $body = preg_split('/\r?\n/', $body); - $quote_level = 0; - $last = -1; - - // find/mark quoted lines... - for ($n=0, $cnt=count($body); $n < $cnt; $n++) { - if ($body[$n][0] == '>' && preg_match('/^(>+ {0,1})+/', $body[$n], $regs)) { - $q = substr_count($regs[0], '>'); - $body[$n] = substr($body[$n], strlen($regs[0])); - - if ($q > $quote_level) { - $body[$n] = $replacer->get_replacement($replacer->add( - str_repeat('<blockquote>', $q - $quote_level))) . $body[$n]; - $last = $n; - } - else if ($q < $quote_level) { - $body[$n] = $replacer->get_replacement($replacer->add( - str_repeat('</blockquote>', $quote_level - $q))) . $body[$n]; - $last = $n; - } - } - else { - $q = 0; - if ($quote_level > 0) - $body[$n] = $replacer->get_replacement($replacer->add( - str_repeat('</blockquote>', $quote_level))) . $body[$n]; + global $RCMAIL; + + // make links and email-addresses clickable + $attribs = array('link_attribs' => array('rel' => 'noreferrer', 'target' => '_blank')); + $replacer = new rcmail_string_replacer($attribs); + + // search for patterns like links and e-mail addresses and replace with tokens + $body = $replacer->replace($body); + + // split body into single lines + $body = preg_split('/\r?\n/', $body); + $quote_level = 0; + $last = -1; + + // find/mark quoted lines... + for ($n=0, $cnt=count($body); $n < $cnt; $n++) { + if ($body[$n][0] == '>' && preg_match('/^(>+ {0,1})+/', $body[$n], $regs)) { + $q = substr_count($regs[0], '>'); + $body[$n] = substr($body[$n], strlen($regs[0])); + + if ($q > $quote_level) { + $body[$n] = $replacer->get_replacement($replacer->add( + str_repeat('<blockquote>', $q - $quote_level))) . $body[$n]; + $last = $n; + } + else if ($q < $quote_level) { + $body[$n] = $replacer->get_replacement($replacer->add( + str_repeat('</blockquote>', $quote_level - $q))) . $body[$n]; + $last = $n; + } + } + else { + $q = 0; + if ($quote_level > 0) + $body[$n] = $replacer->get_replacement($replacer->add( + str_repeat('</blockquote>', $quote_level))) . $body[$n]; + } + + $quote_level = $q; } - $quote_level = $q; - } + $body = join("\n", $body); - $body = join("\n", $body); + // quote plain text (don't use rcube::Q() here, to display entities "as is") + $table = get_html_translation_table(HTML_SPECIALCHARS); + unset($table['?']); + $body = strtr($body, $table); - // quote plain text (don't use rcube::Q() here, to display entities "as is") - $table = get_html_translation_table(HTML_SPECIALCHARS); - unset($table['?']); - $body = strtr($body, $table); + // colorize signature (up to <sig_max_lines> lines) + $len = strlen($body); + $sig_max_lines = $RCMAIL->config->get('sig_max_lines', 15); - // colorize signature (up to <sig_max_lines> lines) - $len = strlen($body); - $sig_max_lines = $RCMAIL->config->get('sig_max_lines', 15); - while (($sp = strrpos($body, "-- \n", $sp ? -$len+$sp-1 : 0)) !== false) { - if ($sp == 0 || $body[$sp-1] == "\n") { - // do not touch blocks with more that X lines - if (substr_count($body, "\n", $sp) < $sig_max_lines) - $body = substr($body, 0, max(0, $sp)) - .'<span class="sig">'.substr($body, $sp).'</span>'; - break; + while (($sp = strrpos($body, "-- \n", $sp ? -$len+$sp-1 : 0)) !== false) { + if ($sp == 0 || $body[$sp-1] == "\n") { + // do not touch blocks with more that X lines + if (substr_count($body, "\n", $sp) < $sig_max_lines) { + $body = substr($body, 0, max(0, $sp)) + . '<span class="sig">'.substr($body, $sp).'</span>'; + } + + break; + } } - } - // insert url/mailto links and citation tags - $body = $replacer->resolve($body); + // insert url/mailto links and citation tags + $body = $replacer->resolve($body); - return $body; + return $body; } - /** * Callback function for washtml cleaning class */ function rcmail_washtml_callback($tagname, $attrib, $content, $washtml) { - switch ($tagname) { + switch ($tagname) { case 'form': - $out = html::div('form', $content); - break; + $out = html::div('form', $content); + break; case 'style': - // decode all escaped entities and reduce to ascii strings - $stripped = preg_replace('/[^a-zA-Z\(:;]/', '', rcube_utils::xss_entity_decode($content)); - - // now check for evil strings like expression, behavior or url() - if (!preg_match('/expression|behavior|javascript:|import[^a]/i', $stripped)) { - if (!$washtml->get_config('allow_remote') && stripos($stripped, 'url(')) - $washtml->extlinks = true; - else - $out = html::tag('style', array('type' => 'text/css'), $content); - break; - } + // decode all escaped entities and reduce to ascii strings + $stripped = preg_replace('/[^a-zA-Z\(:;]/', '', rcube_utils::xss_entity_decode($content)); + + // now check for evil strings like expression, behavior or url() + if (!preg_match('/expression|behavior|javascript:|import[^a]/i', $stripped)) { + if (!$washtml->get_config('allow_remote') && stripos($stripped, 'url(')) + $washtml->extlinks = true; + else + $out = html::tag('style', array('type' => 'text/css'), $content); + break; + } default: - $out = ''; - } + $out = ''; + } - return $out; + return $out; } - /** * return table with message headers */ function rcmail_message_headers($attrib, $headers=null) { - global $MESSAGE, $PRINT_MODE, $RCMAIL; - static $sa_attrib; - - // keep header table attrib - if (is_array($attrib) && !$sa_attrib && !$attrib['valueof']) - $sa_attrib = $attrib; - else if (!is_array($attrib) && is_array($sa_attrib)) - $attrib = $sa_attrib; - - if (!isset($MESSAGE)) - return FALSE; - - // get associative array of headers object - if (!$headers) { - $headers_obj = $MESSAGE->headers; - $headers = get_object_vars($MESSAGE->headers); - } - else if (is_object($headers)) { - $headers_obj = $headers; - $headers = get_object_vars($headers_obj); - } - else { - $headers_obj = rcube_message_header::from_array($headers); - } - - // show these headers - $standard_headers = array('subject', 'from', 'sender', 'to', 'cc', 'bcc', 'replyto', - 'mail-reply-to', 'mail-followup-to', 'date', 'priority'); - $exclude_headers = $attrib['exclude'] ? explode(',', $attrib['exclude']) : array(); - $output_headers = array(); - - foreach ($standard_headers as $hkey) { - $ishtml = false; - - if ($headers[$hkey]) - $value = $headers[$hkey]; - else if ($headers['others'][$hkey]) - $value = $headers['others'][$hkey]; - else if (!$attrib['valueof']) - continue; - - if (in_array($hkey, $exclude_headers)) - continue; - - $header_title = $RCMAIL->gettext(preg_replace('/(^mail-|-)/', '', $hkey)); - - if ($hkey == 'date') { - if ($PRINT_MODE) - $header_value = $RCMAIL->format_date($value, $RCMAIL->config->get('date_long', 'x')); - else - $header_value = $RCMAIL->format_date($value); - } - else if ($hkey == 'priority') { - if ($value) { - $header_value = html::span('prio' . $value, rcmail_localized_priority($value)); - } - else - continue; - } - else if ($hkey == 'replyto') { - if ($headers['replyto'] != $headers['from']) { - $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); - $ishtml = true; - } - else - continue; - } - else if ($hkey == 'mail-reply-to') { - if ($headers['mail-replyto'] != $headers['reply-to'] - && $headers['reply-to'] != $headers['from'] - ) { - $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); - $ishtml = true; - } - else - continue; - } - else if ($hkey == 'sender') { - if ($headers['sender'] != $headers['from']) { - $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); - $ishtml = true; - } - else - continue; - } - else if ($hkey == 'mail-followup-to') { - $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); - $ishtml = true; - } - else if (in_array($hkey, array('from', 'to', 'cc', 'bcc'))) { - $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); - $ishtml = true; - } - else if ($hkey == 'subject' && empty($value)) - $header_value = $RCMAIL->gettext('nosubject'); - else - $header_value = trim(rcube_mime::decode_header($value, $headers['charset'])); + global $MESSAGE, $PRINT_MODE, $RCMAIL; + static $sa_attrib; - $output_headers[$hkey] = array( - 'title' => $header_title, - 'value' => $header_value, - 'raw' => $value, - 'html' => $ishtml, - ); - } + // keep header table attrib + if (is_array($attrib) && !$sa_attrib && !$attrib['valueof']) + $sa_attrib = $attrib; + else if (!is_array($attrib) && is_array($sa_attrib)) + $attrib = $sa_attrib; + + if (!isset($MESSAGE)) { + return false; + } + + // get associative array of headers object + if (!$headers) { + $headers_obj = $MESSAGE->headers; + $headers = get_object_vars($MESSAGE->headers); + } + else if (is_object($headers)) { + $headers_obj = $headers; + $headers = get_object_vars($headers_obj); + } + else { + $headers_obj = rcube_message_header::from_array($headers); + } - $plugin = $RCMAIL->plugins->exec_hook('message_headers_output', - array('output' => $output_headers, 'headers' => $headers_obj, 'exclude' => $exclude_headers)); + // show these headers + $standard_headers = array('subject', 'from', 'sender', 'to', 'cc', 'bcc', 'replyto', + 'mail-reply-to', 'mail-followup-to', 'date', 'priority'); + $exclude_headers = $attrib['exclude'] ? explode(',', $attrib['exclude']) : array(); + $output_headers = array(); - // single header value is requested - if (!empty($attrib['valueof'])) - return rcube::Q($plugin['output'][$attrib['valueof']]['value'], ($attrib['valueof'] == 'subject' ? 'strict' : 'show')); + foreach ($standard_headers as $hkey) { + $ishtml = false; - // compose html table - $table = new html_table(array('cols' => 2)); + if ($headers[$hkey]) + $value = $headers[$hkey]; + else if ($headers['others'][$hkey]) + $value = $headers['others'][$hkey]; + else if (!$attrib['valueof']) + continue; - foreach ($plugin['output'] as $hkey => $row) { - $table->add(array('class' => 'header-title'), rcube::Q($row['title'])); - $table->add(array('class' => 'header '.$hkey), $row['html'] ? $row['value'] : rcube::Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show'))); - } + if (in_array($hkey, $exclude_headers)) + continue; - return $table->show($attrib); + $header_title = $RCMAIL->gettext(preg_replace('/(^mail-|-)/', '', $hkey)); + + if ($hkey == 'date') { + if ($PRINT_MODE) + $header_value = $RCMAIL->format_date($value, $RCMAIL->config->get('date_long', 'x')); + else + $header_value = $RCMAIL->format_date($value); + } + else if ($hkey == 'priority') { + if ($value) { + $header_value = html::span('prio' . $value, rcmail_localized_priority($value)); + } + else + continue; + } + else if ($hkey == 'replyto') { + if ($headers['replyto'] != $headers['from']) { + $header_value = rcmail_address_string($value, $attrib['max'], true, + $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else + continue; + } + else if ($hkey == 'mail-reply-to') { + if ($headers['mail-replyto'] != $headers['reply-to'] + && $headers['reply-to'] != $headers['from'] + ) { + $header_value = rcmail_address_string($value, $attrib['max'], true, + $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else + continue; + } + else if ($hkey == 'sender') { + if ($headers['sender'] != $headers['from']) { + $header_value = rcmail_address_string($value, $attrib['max'], true, + $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else + continue; + } + else if ($hkey == 'mail-followup-to') { + $header_value = rcmail_address_string($value, $attrib['max'], true, + $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else if (in_array($hkey, array('from', 'to', 'cc', 'bcc'))) { + $header_value = rcmail_address_string($value, $attrib['max'], true, + $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else if ($hkey == 'subject' && empty($value)) + $header_value = $RCMAIL->gettext('nosubject'); + else + $header_value = trim(rcube_mime::decode_header($value, $headers['charset'])); + + $output_headers[$hkey] = array( + 'title' => $header_title, + 'value' => $header_value, + 'raw' => $value, + 'html' => $ishtml, + ); + } + + $plugin = $RCMAIL->plugins->exec_hook('message_headers_output', array( + 'output' => $output_headers, + 'headers' => $headers_obj, + 'exclude' => $exclude_headers + )); + + // single header value is requested + if (!empty($attrib['valueof'])) { + return rcube::Q($plugin['output'][$attrib['valueof']]['value'], ($attrib['valueof'] == 'subject' ? 'strict' : 'show')); + } + + // compose html table + $table = new html_table(array('cols' => 2)); + + foreach ($plugin['output'] as $hkey => $row) { + $val = $row['html'] ? $row['value'] : rcube::Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show')); + + $table->add(array('class' => 'header-title'), rcube::Q($row['title'])); + $table->add(array('class' => 'header '.$hkey), $val); + } + + return $table->show($attrib); } /** @@ -1030,20 +1075,21 @@ function rcmail_message_headers($attrib, $headers=null) */ function rcmail_localized_priority($value) { - global $RCMAIL; + global $RCMAIL; - $labels_map = array( - '1' => 'highest', - '2' => 'high', - '3' => 'normal', - '4' => 'low', - '5' => 'lowest', - ); + $labels_map = array( + '1' => 'highest', + '2' => 'high', + '3' => 'normal', + '4' => 'low', + '5' => 'lowest', + ); - if ($value && $labels_map[$value]) - return $RCMAIL->gettext($labels_map[$value]); + if ($value && $labels_map[$value]) { + return $RCMAIL->gettext($labels_map[$value]); + } - return ''; + return ''; } /** @@ -1051,18 +1097,21 @@ function rcmail_localized_priority($value) */ function rcmail_message_full_headers($attrib, $headers=NULL) { - global $OUTPUT, $RCMAIL; + global $OUTPUT, $RCMAIL; - $html = html::div(array('id' => "all-headers", 'class' => "all", 'style' => 'display:none'), html::div(array('id' => 'headers-source'), '')); - $html .= html::div(array('class' => "more-headers show-headers", 'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('show-headers','',this)", 'title' => $RCMAIL->gettext('togglefullheaders')), ''); + $html = html::div(array('id' => "all-headers", 'class' => "all", 'style' => 'display:none'), html::div(array('id' => 'headers-source'), '')); + $html .= html::div(array( + 'class' => "more-headers show-headers", + 'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('show-headers','',this)", + 'title' => $RCMAIL->gettext('togglefullheaders') + ), ''); - $OUTPUT->add_gui_object('all_headers_row', 'all-headers'); - $OUTPUT->add_gui_object('all_headers_box', 'headers-source'); + $OUTPUT->add_gui_object('all_headers_row', 'all-headers'); + $OUTPUT->add_gui_object('all_headers_box', 'headers-source'); - return html::div($attrib, $html); + return html::div($attrib, $html); } - /** * Handler for the 'messagebody' GUI object * @@ -1071,518 +1120,530 @@ function rcmail_message_full_headers($attrib, $headers=NULL) */ function rcmail_message_body($attrib) { - global $CONFIG, $OUTPUT, $MESSAGE, $RCMAIL, $REMOTE_OBJECTS; + global $OUTPUT, $MESSAGE, $RCMAIL, $REMOTE_OBJECTS; - if (!is_array($MESSAGE->parts) && empty($MESSAGE->body)) - return ''; + if (!is_array($MESSAGE->parts) && empty($MESSAGE->body)) { + return ''; + } - if (!$attrib['id']) - $attrib['id'] = 'rcmailMsgBody'; - - $safe_mode = $MESSAGE->is_safe || intval($_GET['_safe']); - $out = ''; - - $header_attrib = array(); - foreach ($attrib as $attr => $value) - if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs)) - $header_attrib[$regs[1]] = $value; - - if (!empty($MESSAGE->parts)) { - foreach ($MESSAGE->parts as $part) { - if ($part->type == 'headers') { - $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); - } - else if ($part->type == 'content') { - // unsupported (e.g. encrypted) - if ($part->realtype) { - if ($part->realtype == 'multipart/encrypted' || $part->realtype == 'application/pkcs7-mime') { - $out .= html::span('part-notice', $RCMAIL->gettext('encryptedmessage')); - } - continue; - } - else if (!$part->size) { - continue; - } - // Check if we have enough memory to handle the message in it - // #1487424: we need up to 10x more memory than the body - else if (!rcube_utils::mem_check($part->size * 10)) { - $out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' ' - . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id - .'&_mbox='. urlencode($RCMAIL->storage->get_folder()), $RCMAIL->gettext('download'))); - continue; + if (!$attrib['id']) + $attrib['id'] = 'rcmailMsgBody'; + + $safe_mode = $MESSAGE->is_safe || intval($_GET['_safe']); + $out = ''; + + $header_attrib = array(); + foreach ($attrib as $attr => $value) { + if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs)) { + $header_attrib[$regs[1]] = $value; } + } - if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset'])) - $part->ctype_parameters['charset'] = $MESSAGE->headers->charset; + if (!empty($MESSAGE->parts)) { + foreach ($MESSAGE->parts as $part) { + if ($part->type == 'headers') { + $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); + } + else if ($part->type == 'content') { + // unsupported (e.g. encrypted) + if ($part->realtype) { + if ($part->realtype == 'multipart/encrypted' || $part->realtype == 'application/pkcs7-mime') { + $out .= html::span('part-notice', $RCMAIL->gettext('encryptedmessage')); + } + continue; + } + else if (!$part->size) { + continue; + } - // fetch part if not available - if (!isset($part->body)) - $part->body = $MESSAGE->get_part_content($part->mime_id); + // Check if we have enough memory to handle the message in it + // #1487424: we need up to 10x more memory than the body + else if (!rcube_utils::mem_check($part->size * 10)) { + $out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' ' + . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id + .'&_mbox='. urlencode($RCMAIL->storage->get_folder()), $RCMAIL->gettext('download'))); + continue; + } - // extract headers from message/rfc822 parts - if ($part->mimetype == 'message/rfc822') { - $msgpart = rcube_mime::parse_message($part->body); - if (!empty($msgpart->headers)) { - $part = $msgpart; - $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); - } - } + if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset'])) { + $part->ctype_parameters['charset'] = $MESSAGE->headers->charset; + } - // message is cached but not exists (#1485443), or other error - if ($part->body === false) { - rcmail_message_error($MESSAGE->uid); - } + // fetch part if not available + if (!isset($part->body)) { + $part->body = $MESSAGE->get_part_content($part->mime_id); + } - $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', array( - 'part' => $part, 'prefix' => '')); + // extract headers from message/rfc822 parts + if ($part->mimetype == 'message/rfc822') { + $msgpart = rcube_mime::parse_message($part->body); + if (!empty($msgpart->headers)) { + $part = $msgpart; + $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); + } + } - $body = rcmail_print_body($part, array('safe' => $safe_mode, 'plain' => !$CONFIG['prefer_html'])); + // message is cached but not exists (#1485443), or other error + if ($part->body === false) { + rcmail_message_error($MESSAGE->uid); + } - if ($part->ctype_secondary == 'html') { - $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs, $safe_mode); - $div_attr = array('class' => 'message-htmlpart'); - $style = array(); + $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', + array('part' => $part, 'prefix' => '')); - if (!empty($attrs)) { - foreach ($attrs as $a_idx => $a_val) - $style[] = $a_idx . ': ' . $a_val; - if (!empty($style)) - $div_attr['style'] = implode('; ', $style); - } + $body = rcmail_print_body($part, array('safe' => $safe_mode, 'plain' => !$RCMAIL->config->get('prefer_html'))); - $out .= html::div($div_attr, $plugin['prefix'] . $body); + if ($part->ctype_secondary == 'html') { + $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs, $safe_mode); + $div_attr = array('class' => 'message-htmlpart'); + $style = array(); + + if (!empty($attrs)) { + foreach ($attrs as $a_idx => $a_val) + $style[] = $a_idx . ': ' . $a_val; + if (!empty($style)) + $div_attr['style'] = implode('; ', $style); + } + + $out .= html::div($div_attr, $plugin['prefix'] . $body); + } + else + $out .= html::div('message-part', $plugin['prefix'] . $body); + } } - else - $out .= html::div('message-part', $plugin['prefix'] . $body); - } - } - } - else { - // Check if we have enough memory to handle the message in it - // #1487424: we need up to 10x more memory than the body - if (!rcube_utils::mem_check(strlen($MESSAGE->body) * 10)) { - $out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' ' - . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part=0' - .'&_mbox='. urlencode($RCMAIL->storage->get_folder()), $RCMAIL->gettext('download'))); } else { - $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', array( - 'part' => $MESSAGE, 'prefix' => '')); - - $out .= html::div('message-part', $plugin['prefix'] . html::tag('pre', array(), - rcmail_plain_body(rcube::Q($MESSAGE->body, 'strict', false)))); - } - } - - // list images after mail body - if ($RCMAIL->config->get('inline_images', true) && !empty($MESSAGE->attachments)) { - $thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240); - $client_mimetypes = (array)$RCMAIL->config->get('client_mimetypes'); - - foreach ($MESSAGE->attachments as $attach_prop) { - // skip inline images - if ($attach_prop->content_id && $attach_prop->disposition == 'inline') { - continue; - } - - // Content-Type: image/*... - if ($mimetype = rcmail_part_image_type($attach_prop)) { - // display thumbnails - if ($thumbnail_size) { - $show_link = array( - 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), - 'onclick' => sprintf( - 'return %s.command(\'load-attachment\',\'%s\',this)', - rcmail_output::JS_OBJECT_NAME, - $attach_prop->mime_id) - ); - $out .= html::p('image-attachment', - html::a($show_link + array('class' => 'image-link', 'style' => sprintf('width:%dpx', $thumbnail_size)), - html::img(array( - 'class' => 'image-thumbnail', - 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image') . '&_thumb=1', - 'title' => $attach_prop->filename, - 'alt' => $attach_prop->filename, - 'style' => sprintf('max-width:%dpx; max-height:%dpx', $thumbnail_size, $thumbnail_size), - )) - ) . - html::span('image-filename', rcube::Q($attach_prop->filename)) . - html::span('image-filesize', rcube::Q($RCMAIL->message_part_size($attach_prop))) . - html::span('attachment-links', - (in_array($mimetype, $client_mimetypes) ? html::a($show_link, $RCMAIL->gettext('showattachment')) . ' ' : '') . - html::a($show_link['href'] . '&_download=1', $RCMAIL->gettext('download')) - ) . - html::br(array('style' => 'clear:both')) - ); + // Check if we have enough memory to handle the message in it + // #1487424: we need up to 10x more memory than the body + if (!rcube_utils::mem_check(strlen($MESSAGE->body) * 10)) { + $out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' ' + . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part=0' + .'&_mbox='. urlencode($RCMAIL->storage->get_folder()), $RCMAIL->gettext('download'))); } else { - $out .= html::tag('fieldset', 'image-attachment', - html::tag('legend', 'image-filename', rcube::Q($attach_prop->filename)) . - html::p(array('align' => "center"), - html::img(array( - 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image'), - 'title' => $attach_prop->filename, - 'alt' => $attach_prop->filename, - ))) - ); + $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', + array('part' => $MESSAGE, 'prefix' => '')); + + $out .= html::div('message-part', $plugin['prefix'] . html::tag('pre', array(), + rcmail_plain_body(rcube::Q($MESSAGE->body, 'strict', false)))); + } + } + + // list images after mail body + if ($RCMAIL->config->get('inline_images', true) && !empty($MESSAGE->attachments)) { + $thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240); + $client_mimetypes = (array)$RCMAIL->config->get('client_mimetypes'); + + foreach ($MESSAGE->attachments as $attach_prop) { + // skip inline images + if ($attach_prop->content_id && $attach_prop->disposition == 'inline') { + continue; + } + + // Content-Type: image/*... + if ($mimetype = rcmail_part_image_type($attach_prop)) { + // display thumbnails + if ($thumbnail_size) { + $show_link = array( + 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), + 'onclick' => sprintf( + 'return %s.command(\'load-attachment\',\'%s\',this)', + rcmail_output::JS_OBJECT_NAME, + $attach_prop->mime_id) + ); + $out .= html::p('image-attachment', + html::a($show_link + array('class' => 'image-link', 'style' => sprintf('width:%dpx', $thumbnail_size)), + html::img(array( + 'class' => 'image-thumbnail', + 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image') . '&_thumb=1', + 'title' => $attach_prop->filename, + 'alt' => $attach_prop->filename, + 'style' => sprintf('max-width:%dpx; max-height:%dpx', $thumbnail_size, $thumbnail_size), + )) + ) . + html::span('image-filename', rcube::Q($attach_prop->filename)) . + html::span('image-filesize', rcube::Q($RCMAIL->message_part_size($attach_prop))) . + html::span('attachment-links', + (in_array($mimetype, $client_mimetypes) ? html::a($show_link, $RCMAIL->gettext('showattachment')) . ' ' : '') . + html::a($show_link['href'] . '&_download=1', $RCMAIL->gettext('download')) + ) . + html::br(array('style' => 'clear:both')) + ); + } + else { + $out .= html::tag('fieldset', 'image-attachment', + html::tag('legend', 'image-filename', rcube::Q($attach_prop->filename)) . + html::p(array('align' => 'center'), + html::img(array( + 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image'), + 'title' => $attach_prop->filename, + 'alt' => $attach_prop->filename, + ))) + ); + } + } } - } } - } - // tell client that there are blocked remote objects - if ($REMOTE_OBJECTS && !$safe_mode) - $OUTPUT->set_env('blockedobjects', true); + // tell client that there are blocked remote objects + if ($REMOTE_OBJECTS && !$safe_mode) { + $OUTPUT->set_env('blockedobjects', true); + } - return html::div($attrib, $out); + return html::div($attrib, $out); } function rcmail_part_image_type($part) { - $rcmail = rcmail::get_instance(); - - // Skip TIFF images if browser doesn't support this format... - $tiff_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps']['tif']); - // until we can convert them to JPEG - $tiff_support = $tiff_support || $rcmail->config->get('im_convert_path'); - - // Content-type regexp - $mime_regex = $tiff_support ? '/^image\//i' : '/^image\/(?!tif)/i'; - - // Content-Type: image/*... - if (preg_match($mime_regex, $part->mimetype)) { - return rcmail_fix_mimetype($part->mimetype); - } - - // Many clients use application/octet-stream, we'll detect mimetype - // by checking filename extension - - // Supported image filename extensions to image type map - $types = array( - 'jpg' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'png' => 'image/png', - 'gif' => 'image/gif', - 'bmp' => 'image/bmp', - ); - if ($tiff_support) { - $types['tif'] = 'image/tiff'; - $types['tiff'] = 'image/tiff'; - } - - if ($part->filename - && preg_match('/^application\/octet-stream$/i', $part->mimetype) - && preg_match('/\.([^.]+)$/i', $part->filename, $m) - && ($extension = strtolower($m[1])) - && isset($types[$extension]) - ) { - return $types[$extension]; - } -} + $rcmail = rcmail::get_instance(); + + // Skip TIFF images if browser doesn't support this format... + $tiff_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps']['tif']); + // until we can convert them to JPEG + $tiff_support = $tiff_support || $rcmail->config->get('im_convert_path'); + // Content-type regexp + $mime_regex = $tiff_support ? '/^image\//i' : '/^image\/(?!tif)/i'; + + // Content-Type: image/*... + if (preg_match($mime_regex, $part->mimetype)) { + return rcmail_fix_mimetype($part->mimetype); + } + + // Many clients use application/octet-stream, we'll detect mimetype + // by checking filename extension + + // Supported image filename extensions to image type map + $types = array( + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'png' => 'image/png', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + ); + if ($tiff_support) { + $types['tif'] = 'image/tiff'; + $types['tiff'] = 'image/tiff'; + } + + if ($part->filename + && preg_match('/^application\/octet-stream$/i', $part->mimetype) + && preg_match('/\.([^.]+)$/i', $part->filename, $m) + && ($extension = strtolower($m[1])) + && isset($types[$extension]) + ) { + return $types[$extension]; + } +} /** * modify a HTML message that it can be displayed inside a HTML page */ function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null, $allow_remote=false) { - $last_style_pos = 0; - $cont_id = $container_id.($body_id ? ' div.'.$body_id : ''); - - // find STYLE tags - while (($pos = stripos($body, '<style', $last_style_pos)) && ($pos2 = stripos($body, '</style>', $pos))) - { - $pos = strpos($body, '>', $pos) + 1; - $len = $pos2 - $pos; - - // replace all css definitions with #container [def] - $styles = substr($body, $pos, $len); - $styles = rcube_utils::mod_css_styles($styles, $cont_id, $allow_remote); - - $body = substr_replace($body, $styles, $pos, $len); - $last_style_pos = $pos2 + strlen($styles) - $len; - } - - // modify HTML links to open a new window if clicked - $GLOBALS['rcmail_html_container_id'] = $container_id; - $body = preg_replace_callback('/<(a|link|area)\s+([^>]+)>/Ui', 'rcmail_alter_html_link', $body); - unset($GLOBALS['rcmail_html_container_id']); - - $body = preg_replace(array( - // add comments arround html and other tags - '/(<!DOCTYPE[^>]*>)/i', - '/(<\?xml[^>]*>)/i', - '/(<\/?html[^>]*>)/i', - '/(<\/?head[^>]*>)/i', - '/(<title[^>]*>.*<\/title>)/Ui', - '/(<\/?meta[^>]*>)/i', - // quote <? of php and xml files that are specified as text/html - '/<\?/', - '/\?>/', - // replace <body> with <div> - '/<body([^>]*)>/i', - '/<\/body>/i', - ), - array( - '<!--\\1-->', - '<!--\\1-->', - '<!--\\1-->', - '<!--\\1-->', - '<!--\\1-->', - '<!--\\1-->', - '<?', - '?>', - '<div class="'.$body_id.'"\\1>', - '</div>', - ), - $body); - - $attributes = array(); - - // Handle body attributes that doesn't play nicely with div elements - $regexp = '/<div class="' . preg_quote($body_id, '/') . '"([^>]*)/'; - if (preg_match($regexp, $body, $m)) { - $attrs = $m[0]; - // Get bgcolor, we'll set it as background-color of the message container - if ($m[1] && preg_match('/bgcolor=["\']*([a-z0-9#]+)["\']*/i', $attrs, $mb)) { - $attributes['background-color'] = $mb[1]; - $attrs = preg_replace('/bgcolor=["\']*[a-z0-9#]+["\']*/i', '', $attrs); - } - // Get background, we'll set it as background-image of the message container - if ($m[1] && preg_match('/background=["\']*([^"\'>\s]+)["\']*/', $attrs, $mb)) { - $attributes['background-image'] = 'url('.$mb[1].')'; - $attrs = preg_replace('/background=["\']*([^"\'>\s]+)["\']*/', '', $attrs); - } - if (!empty($attributes)) { - $body = preg_replace($regexp, rtrim($attrs), $body, 1); - } - - // handle body styles related to background image - if ($attributes['background-image']) { - // get body style - if (preg_match('/#'.preg_quote($cont_id, '/').'\s+\{([^}]+)}/i', $body, $m)) { - // get background related style - if (preg_match_all('/(background-position|background-repeat)\s*:\s*([^;]+);/i', $m[1], $ma, PREG_SET_ORDER)) { - foreach ($ma as $style) - $attributes[$style[1]] = $style[2]; + $last_style_pos = 0; + $cont_id = $container_id.($body_id ? ' div.'.$body_id : ''); + + // find STYLE tags + while (($pos = stripos($body, '<style', $last_style_pos)) && ($pos2 = stripos($body, '</style>', $pos))) { + $pos = strpos($body, '>', $pos) + 1; + $len = $pos2 - $pos; + + // replace all css definitions with #container [def] + $styles = substr($body, $pos, $len); + $styles = rcube_utils::mod_css_styles($styles, $cont_id, $allow_remote); + + $body = substr_replace($body, $styles, $pos, $len); + $last_style_pos = $pos2 + strlen($styles) - $len; + } + + // modify HTML links to open a new window if clicked + $GLOBALS['rcmail_html_container_id'] = $container_id; + $body = preg_replace_callback('/<(a|link|area)\s+([^>]+)>/Ui', 'rcmail_alter_html_link', $body); + unset($GLOBALS['rcmail_html_container_id']); + + $body = preg_replace(array( + // add comments arround html and other tags + '/(<!DOCTYPE[^>]*>)/i', + '/(<\?xml[^>]*>)/i', + '/(<\/?html[^>]*>)/i', + '/(<\/?head[^>]*>)/i', + '/(<title[^>]*>.*<\/title>)/Ui', + '/(<\/?meta[^>]*>)/i', + // quote <? of php and xml files that are specified as text/html + '/<\?/', + '/\?>/', + // replace <body> with <div> + '/<body([^>]*)>/i', + '/<\/body>/i', + ), + array( + '<!--\\1-->', + '<!--\\1-->', + '<!--\\1-->', + '<!--\\1-->', + '<!--\\1-->', + '<!--\\1-->', + '<?', + '?>', + '<div class="'.$body_id.'"\\1>', + '</div>', + ), + $body); + + $attributes = array(); + + // Handle body attributes that doesn't play nicely with div elements + $regexp = '/<div class="' . preg_quote($body_id, '/') . '"([^>]*)/'; + if (preg_match($regexp, $body, $m)) { + $attrs = $m[0]; + + // Get bgcolor, we'll set it as background-color of the message container + if ($m[1] && preg_match('/bgcolor=["\']*([a-z0-9#]+)["\']*/i', $attrs, $mb)) { + $attributes['background-color'] = $mb[1]; + $attrs = preg_replace('/bgcolor=["\']*[a-z0-9#]+["\']*/i', '', $attrs); + } + + // Get background, we'll set it as background-image of the message container + if ($m[1] && preg_match('/background=["\']*([^"\'>\s]+)["\']*/', $attrs, $mb)) { + $attributes['background-image'] = 'url('.$mb[1].')'; + $attrs = preg_replace('/background=["\']*([^"\'>\s]+)["\']*/', '', $attrs); + } + + if (!empty($attributes)) { + $body = preg_replace($regexp, rtrim($attrs), $body, 1); + } + + // handle body styles related to background image + if ($attributes['background-image']) { + // get body style + if (preg_match('/#'.preg_quote($cont_id, '/').'\s+\{([^}]+)}/i', $body, $m)) { + // get background related style + $regexp = '/(background-position|background-repeat)\s*:\s*([^;]+);/i'; + if (preg_match_all($regexp, $m[1], $ma, PREG_SET_ORDER)) { + foreach ($ma as $style) { + $attributes[$style[1]] = $style[2]; + } + } + } } - } } - } - // make sure there's 'rcmBody' div, we need it for proper css modification - // its name is hardcoded in rcmail_message_body() also - else { - $body = '<div class="' . $body_id . '">' . $body . '</div>'; - } + // make sure there's 'rcmBody' div, we need it for proper css modification + // its name is hardcoded in rcmail_message_body() also + else { + $body = '<div class="' . $body_id . '">' . $body . '</div>'; + } - return $body; + return $body; } - /** * parse link (a, link, area) attributes and set correct target */ function rcmail_alter_html_link($matches) { - global $RCMAIL; - - $tag = strtolower($matches[1]); - $attrib = html::parse_attrib_string($matches[2]); - $end = '>'; - - // Remove non-printable characters in URL (#1487805) - if ($attrib['href']) - $attrib['href'] = preg_replace('/[\x00-\x1F]/', '', $attrib['href']); - - if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href'])) { - $tempurl = 'tmp-' . md5($attrib['href']) . '.css'; - $_SESSION['modcssurls'][$tempurl] = $attrib['href']; - $attrib['href'] = $RCMAIL->url(array('task' => 'utils', 'action' => 'modcss', 'u' => $tempurl, 'c' => $GLOBALS['rcmail_html_container_id'])); - $end = ' />'; - } - else if (preg_match('/^mailto:(.+)/i', $attrib['href'], $mailto)) { - list($mailto, $url) = explode('?', html_entity_decode($mailto[1], ENT_QUOTES, 'UTF-8'), 2); - - $url = urldecode($url); - $mailto = urldecode($mailto); - $addresses = rcube_mime::decode_address_list($mailto, null, true); - $mailto = array(); - - // do sanity checks on recipients - foreach ($addresses as $idx => $addr) { - if (rcube_utils::check_email($addr['mailto'], false)) { - $addresses[$idx] = $addr['mailto']; - $mailto[] = $addr['string']; - } - else { - unset($addresses[$idx]); - } - } - - if (!empty($addresses)) { - $attrib['href'] = 'mailto:' . implode(',', $addresses); - $attrib['onclick'] = sprintf( - "return %s.command('compose','%s',this)", - rcmail_output::JS_OBJECT_NAME, - rcube::JQ(implode(',', $mailto) . ($url ? "?$url" : ''))); + global $RCMAIL; + + $tag = strtolower($matches[1]); + $attrib = html::parse_attrib_string($matches[2]); + $end = '>'; + + // Remove non-printable characters in URL (#1487805) + if ($attrib['href']) + $attrib['href'] = preg_replace('/[\x00-\x1F]/', '', $attrib['href']); + + if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href'])) { + $tempurl = 'tmp-' . md5($attrib['href']) . '.css'; + $_SESSION['modcssurls'][$tempurl] = $attrib['href']; + $attrib['href'] = $RCMAIL->url(array('task' => 'utils', 'action' => 'modcss', 'u' => $tempurl, 'c' => $GLOBALS['rcmail_html_container_id'])); + $end = ' />'; } - else { - $attrib['href'] = '#NOP'; - $attrib['onclick'] = ''; - } - } - else if (empty($attrib['href']) && !$attrib['name']) { - $attrib['href'] = './#NOP'; - $attrib['onclick'] = 'return false'; - } - else if (!empty($attrib['href']) && $attrib['href'][0] != '#') { - $attrib['target'] = '_blank'; - } - - // Better security by adding rel="noreferrer" (#1484686) - if (($tag == 'a' || $tag == 'area') && $attrib['href'] && $attrib['href'][0] != '#') { - $attrib['rel'] = 'noreferrer'; - } - - // allowed attributes for a|link|area tags - $allow = array('href','name','target','onclick','id','class','style','title', - 'rel','type','media','alt','coords','nohref','hreflang','shape'); - - return "<$tag" . html::attrib_string($attrib, $allow) . $end; -} + else if (preg_match('/^mailto:(.+)/i', $attrib['href'], $mailto)) { + list($mailto, $url) = explode('?', html_entity_decode($mailto[1], ENT_QUOTES, 'UTF-8'), 2); + + $url = urldecode($url); + $mailto = urldecode($mailto); + $addresses = rcube_mime::decode_address_list($mailto, null, true); + $mailto = array(); + + // do sanity checks on recipients + foreach ($addresses as $idx => $addr) { + if (rcube_utils::check_email($addr['mailto'], false)) { + $addresses[$idx] = $addr['mailto']; + $mailto[] = $addr['string']; + } + else { + unset($addresses[$idx]); + } + } + if (!empty($addresses)) { + $attrib['href'] = 'mailto:' . implode(',', $addresses); + $attrib['onclick'] = sprintf( + "return %s.command('compose','%s',this)", + rcmail_output::JS_OBJECT_NAME, + rcube::JQ(implode(',', $mailto) . ($url ? "?$url" : ''))); + } + else { + $attrib['href'] = '#NOP'; + $attrib['onclick'] = ''; + } + } + else if (empty($attrib['href']) && !$attrib['name']) { + $attrib['href'] = './#NOP'; + $attrib['onclick'] = 'return false'; + } + else if (!empty($attrib['href']) && $attrib['href'][0] != '#') { + $attrib['target'] = '_blank'; + } + + // Better security by adding rel="noreferrer" (#1484686) + if (($tag == 'a' || $tag == 'area') && $attrib['href'] && $attrib['href'][0] != '#') { + $attrib['rel'] = 'noreferrer'; + } + + // allowed attributes for a|link|area tags + $allow = array('href','name','target','onclick','id','class','style','title', + 'rel','type','media','alt','coords','nohref','hreflang','shape'); + + return "<$tag" . html::attrib_string($attrib, $allow) . $end; +} /** * decode address string and re-format it as HTML links */ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $default_charset=null, $title=null) { - global $RCMAIL, $PRINT_MODE, $CONFIG; - - $a_parts = rcube_mime::decode_address_list($input, null, true, $default_charset); - - if (!sizeof($a_parts)) - return $input; - - $c = count($a_parts); - $j = 0; - $out = ''; - $allvalues = array(); - $show_email = $RCMAIL->config->get('message_show_email'); - - if ($addicon && !isset($_SESSION['writeable_abook'])) { - $_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false; - } - - foreach ($a_parts as $part) { - $j++; - $name = $part['name']; - $mailto = $part['mailto']; - $string = $part['string']; - $valid = rcube_utils::check_email($mailto, false); - - // phishing email prevention (#1488981), e.g. "valid@email.addr <phishing@email.addr>" - if (!$show_email && $valid && $name && $name != $mailto && strpos($name, '@')) { - $name = ''; - } - - // IDNA ASCII to Unicode - if ($name == $mailto) - $name = rcube_utils::idn_to_utf8($name); - if ($string == $mailto) - $string = rcube_utils::idn_to_utf8($string); - $mailto = rcube_utils::idn_to_utf8($mailto); - - if ($PRINT_MODE) { - $address = sprintf('%s <%s>', rcube::Q($name), rcube::Q($mailto)); - } - else if ($valid) { - if ($linked) { - $attrs = array( - 'href' => 'mailto:' . $mailto, - 'onclick' => sprintf("return %s.command('compose','%s',this)", rcmail_output::JS_OBJECT_NAME, rcube::JQ(format_email_recipient($mailto, $name))), - 'class' => "rcmContactAddress", - ); + global $RCMAIL, $PRINT_MODE; - if ($show_email && $name && $mailto) { - $content = rcube::Q($name ? sprintf('%s <%s>', $name, $mailto) : $mailto); - } - else { - $content = rcube::Q($name ? $name : $mailto); - $attrs['title'] = $mailto; - } + $a_parts = rcube_mime::decode_address_list($input, null, true, $default_charset); - $address = html::a($attrs, $content); - } - else { - $address = html::span(array('title' => $mailto, 'class' => "rcmContactAddress"), - rcube::Q($name ? $name : $mailto)); - } - - if ($addicon && $_SESSION['writeable_abook']) { - $address .= html::a(array( - 'href' => "#add", - 'onclick' => sprintf("return %s.command('add-contact','%s',this)", rcmail_output::JS_OBJECT_NAME, rcube::JQ($string)), - 'title' => $RCMAIL->gettext('addtoaddressbook'), - 'class' => 'rcmaddcontact', - ), - html::img(array( - 'src' => $CONFIG['skin_path'] . $addicon, - 'alt' => "Add contact", - ))); - } + if (!sizeof($a_parts)) { + return $input; } - else { - $address = ''; - if ($name) - $address .= rcube::Q($name); - if ($mailto) - $address = trim($address . ' ' . rcube::Q($name ? sprintf('<%s>', $mailto) : $mailto)); + + $c = count($a_parts); + $j = 0; + $out = ''; + $allvalues = array(); + $show_email = $RCMAIL->config->get('message_show_email'); + + if ($addicon && !isset($_SESSION['writeable_abook'])) { + $_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false; } - $address = html::span('adr', $address); - $allvalues[] = $address; + foreach ($a_parts as $part) { + $j++; - if (!$moreadrs) - $out .= ($out ? ', ' : '') . $address; + $name = $part['name']; + $mailto = $part['mailto']; + $string = $part['string']; + $valid = rcube_utils::check_email($mailto, false); - if ($max && $j == $max && $c > $j) { - if ($linked) { - $moreadrs = $c - $j; - } - else { - $out .= '...'; - break; - } - } - } + // phishing email prevention (#1488981), e.g. "valid@email.addr <phishing@email.addr>" + if (!$show_email && $valid && $name && $name != $mailto && strpos($name, '@')) { + $name = ''; + } - if ($moreadrs) { - if ($PRINT_MODE) { - $out .= ' ' . html::a(array( - 'href' => '#more', - 'class' => 'morelink', - 'onclick' => '$(this).hide().next().show()', - ), rcube::Q($RCMAIL->gettext(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs))))) . - html::span(array('style' => 'display:none'), join(', ', $allvalues)); + // IDNA ASCII to Unicode + if ($name == $mailto) + $name = rcube_utils::idn_to_utf8($name); + if ($string == $mailto) + $string = rcube_utils::idn_to_utf8($string); + $mailto = rcube_utils::idn_to_utf8($mailto); + + if ($PRINT_MODE) { + $address = sprintf('%s <%s>', rcube::Q($name), rcube::Q($mailto)); + } + else if ($valid) { + if ($linked) { + $attrs = array( + 'href' => 'mailto:' . $mailto, + 'class' => 'rcmContactAddress', + 'onclick' => sprintf("return %s.command('compose','%s',this)", + rcmail_output::JS_OBJECT_NAME, rcube::JQ(format_email_recipient($mailto, $name))), + ); + + if ($show_email && $name && $mailto) { + $content = rcube::Q($name ? sprintf('%s <%s>', $name, $mailto) : $mailto); + } + else { + $content = rcube::Q($name ? $name : $mailto); + $attrs['title'] = $mailto; + } + + $address = html::a($attrs, $content); + } + else { + $address = html::span(array('title' => $mailto, 'class' => "rcmContactAddress"), + rcube::Q($name ? $name : $mailto)); + } + + if ($addicon && $_SESSION['writeable_abook']) { + $address .= html::a(array( + 'href' => "#add", + 'title' => $RCMAIL->gettext('addtoaddressbook'), + 'class' => 'rcmaddcontact', + 'onclick' => sprintf("return %s.command('add-contact','%s',this)", + rcmail_output::JS_OBJECT_NAME, rcube::JQ($string)), + ), + html::img(array( + 'src' => $RCMAIL->config->get('skin_path') . $addicon, + 'alt' => "Add contact", + ))); + } + } + else { + $address = ''; + if ($name) + $address .= rcube::Q($name); + if ($mailto) + $address = trim($address . ' ' . rcube::Q($name ? sprintf('<%s>', $mailto) : $mailto)); + } + + $address = html::span('adr', $address); + $allvalues[] = $address; + + if (!$moreadrs) + $out .= ($out ? ', ' : '') . $address; + + if ($max && $j == $max && $c > $j) { + if ($linked) { + $moreadrs = $c - $j; + } + else { + $out .= '...'; + break; + } + } } - else { - $out .= ' ' . html::a(array( - 'href' => '#more', - 'class' => 'morelink', - 'onclick' => sprintf("return %s.show_popup_dialog('%s','%s')", - rcmail_output::JS_OBJECT_NAME, - rcube::JQ(join(', ', $allvalues)), - rcube::JQ($title)) - ), - rcube::Q($RCMAIL->gettext(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs))))); + + if ($moreadrs) { + if ($PRINT_MODE) { + $out .= ' ' . html::a(array( + 'href' => '#more', + 'class' => 'morelink', + 'onclick' => '$(this).hide().next().show()', + ), + rcube::Q($RCMAIL->gettext(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs))))) + . html::span(array('style' => 'display:none'), join(', ', $allvalues)); + } + else { + $out .= ' ' . html::a(array( + 'href' => '#more', + 'class' => 'morelink', + 'onclick' => sprintf("return %s.show_popup_dialog('%s','%s')", + rcmail_output::JS_OBJECT_NAME, + rcube::JQ(join(', ', $allvalues)), + rcube::JQ($title)) + ), + rcube::Q($RCMAIL->gettext(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs))))); + } } - } - return $out; + return $out; } - /** * Wrap text to a given number of characters per line * but respect the mail quotation of replies messages (>). @@ -1595,74 +1656,79 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, */ function rcmail_wrap_and_quote($text, $length = 72) { - // Rebuild the message body with a maximum of $max chars, while keeping quoted message. - $max = max(75, $length + 8); - $lines = preg_split('/\r?\n/', trim($text)); - $out = ''; - - foreach ($lines as $line) { - // don't wrap already quoted lines - if ($line[0] == '>') - $line = '>' . rtrim($line); - else if (mb_strlen($line) > $max) { - $newline = ''; - foreach (explode("\n", rcube_mime::wordwrap($line, $length - 2)) as $l) { - if (strlen($l)) - $newline .= '> ' . $l . "\n"; - else - $newline .= ">\n"; - } - $line = rtrim($newline); - } - else - $line = '> ' . $line; + // Rebuild the message body with a maximum of $max chars, while keeping quoted message. + $max = max(75, $length + 8); + $lines = preg_split('/\r?\n/', trim($text)); + $out = ''; + + foreach ($lines as $line) { + // don't wrap already quoted lines + if ($line[0] == '>') { + $line = '>' . rtrim($line); + } + else if (mb_strlen($line) > $max) { + $newline = ''; + + foreach (explode("\n", rcube_mime::wordwrap($line, $length - 2)) as $l) { + if (strlen($l)) + $newline .= '> ' . $l . "\n"; + else + $newline .= ">\n"; + } + + $line = rtrim($newline); + } + else { + $line = '> ' . $line; + } - // Append the line - $out .= $line . "\n"; - } + // Append the line + $out .= $line . "\n"; + } - return rtrim($out, "\n"); + return rtrim($out, "\n"); } - function rcmail_draftinfo_encode($p) { - $parts = array(); - foreach ($p as $key => $val) - $parts[] = $key . '=' . ($key == 'folder' ? base64_encode($val) : $val); + $parts = array(); + foreach ($p as $key => $val) { + $parts[] = $key . '=' . ($key == 'folder' ? base64_encode($val) : $val); + } - return join('; ', $parts); + return join('; ', $parts); } - function rcmail_draftinfo_decode($str) { - $info = array(); - foreach (preg_split('/;\s+/', $str) as $part) { - list($key, $val) = explode('=', $part, 2); - if ($key == 'folder') - $val = base64_decode($val); - $info[$key] = $val; - } - - return $info; -} + $info = array(); + + foreach (preg_split('/;\s+/', $str) as $part) { + list($key, $val) = explode('=', $part, 2); + if ($key == 'folder') { + $val = base64_decode($val); + } + $info[$key] = $val; + } + + return $info; +} /** * clear message composing settings */ function rcmail_compose_cleanup($id) { - if (!isset($_SESSION['compose_data_'.$id])) - return; + if (!isset($_SESSION['compose_data_'.$id])) { + return; + } - $rcmail = rcmail::get_instance(); - $rcmail->plugins->exec_hook('attachments_cleanup', array('group' => $id)); - $rcmail->session->remove('compose_data_'.$id); + $rcmail = rcmail::get_instance(); + $rcmail->plugins->exec_hook('attachments_cleanup', array('group' => $id)); + $rcmail->session->remove('compose_data_'.$id); } - /** * Send the MDN response * @@ -1673,76 +1739,78 @@ function rcmail_compose_cleanup($id) */ function rcmail_send_mdn($message, &$smtp_error) { - global $RCMAIL; - - if (!is_object($message) || !is_a($message, 'rcube_message')) - $message = new rcube_message($message); - - if ($message->headers->mdn_to && empty($message->headers->flags['MDNSENT']) && - ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*'))) - { - $identity = rcmail_identity_select($message); - $sender = format_email_recipient($identity['email'], $identity['name']); - $recipient = array_shift(rcube_mime::decode_address_list( - $message->headers->mdn_to, 1, true, $message->headers->charset)); - $mailto = $recipient['mailto']; - - $compose = new Mail_mime("\r\n"); - - $compose->setParam('text_encoding', 'quoted-printable'); - $compose->setParam('html_encoding', 'quoted-printable'); - $compose->setParam('head_encoding', 'quoted-printable'); - $compose->setParam('head_charset', RCUBE_CHARSET); - $compose->setParam('html_charset', RCUBE_CHARSET); - $compose->setParam('text_charset', RCUBE_CHARSET); - - // compose headers array - $headers = array( - 'Date' => $RCMAIL->user_date(), - 'From' => $sender, - 'To' => $message->headers->mdn_to, - 'Subject' => $RCMAIL->gettext('receiptread') . ': ' . $message->subject, - 'Message-ID' => $RCMAIL->gen_message_id(), - 'X-Sender' => $identity['email'], - 'References' => trim($message->headers->references . ' ' . $message->headers->messageID), - ); - - $report = "Final-Recipient: rfc822; {$identity['email']}\r\n" . - "Original-Message-ID: {$message->headers->messageID}\r\n" . - "Disposition: manual-action/MDN-sent-manually; displayed\r\n"; + global $RCMAIL; - if ($message->headers->to) { - $report .= "Original-Recipient: {$message->headers->to}\r\n"; + if (!is_object($message) || !is_a($message, 'rcube_message')) { + $message = new rcube_message($message); } - if ($agent = $RCMAIL->config->get('useragent')) { - $headers['User-Agent'] = $agent; - $report .= "Reporting-UA: $agent\r\n"; - } + if ($message->headers->mdn_to && empty($message->headers->flags['MDNSENT']) && + ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*')) + ) { + $identity = rcmail_identity_select($message); + $sender = format_email_recipient($identity['email'], $identity['name']); + $recipient = array_shift(rcube_mime::decode_address_list( + $message->headers->mdn_to, 1, true, $message->headers->charset)); + $mailto = $recipient['mailto']; + + $compose = new Mail_mime("\r\n"); + + $compose->setParam('text_encoding', 'quoted-printable'); + $compose->setParam('html_encoding', 'quoted-printable'); + $compose->setParam('head_encoding', 'quoted-printable'); + $compose->setParam('head_charset', RCUBE_CHARSET); + $compose->setParam('html_charset', RCUBE_CHARSET); + $compose->setParam('text_charset', RCUBE_CHARSET); + + // compose headers array + $headers = array( + 'Date' => $RCMAIL->user_date(), + 'From' => $sender, + 'To' => $message->headers->mdn_to, + 'Subject' => $RCMAIL->gettext('receiptread') . ': ' . $message->subject, + 'Message-ID' => $RCMAIL->gen_message_id(), + 'X-Sender' => $identity['email'], + 'References' => trim($message->headers->references . ' ' . $message->headers->messageID), + ); - $body = $RCMAIL->gettext("yourmessage") . "\r\n\r\n" . - "\t" . $RCMAIL->gettext("to") . ': ' . rcube_mime::decode_mime_string($message->headers->to, $message->headers->charset) . "\r\n" . - "\t" . $RCMAIL->gettext("subject") . ': ' . $message->subject . "\r\n" . - "\t" . $RCMAIL->gettext("sent") . ': ' . $RCMAIL->format_date($message->headers->date, $RCMAIL->config->get('date_long')) . "\r\n" . - "\r\n" . $RCMAIL->gettext("receiptnote"); + $report = "Final-Recipient: rfc822; {$identity['email']}\r\n" + . "Original-Message-ID: {$message->headers->messageID}\r\n" + . "Disposition: manual-action/MDN-sent-manually; displayed\r\n"; - $compose->headers($headers); - $compose->setContentType('multipart/report', array('report-type'=> 'disposition-notification')); - $compose->setTXTBody(rcube_mime::wordwrap($body, 75, "\r\n")); - $compose->addAttachment($report, 'message/disposition-notification', 'MDNPart2.txt', false, '7bit', 'inline'); + if ($message->headers->to) { + $report .= "Original-Recipient: {$message->headers->to}\r\n"; + } - if ($RCMAIL->config->get('mdn_use_from')) - $options['mdn_use_from'] = true; + if ($agent = $RCMAIL->config->get('useragent')) { + $headers['User-Agent'] = $agent; + $report .= "Reporting-UA: $agent\r\n"; + } + + $body = $RCMAIL->gettext("yourmessage") . "\r\n\r\n" . + "\t" . $RCMAIL->gettext("to") . ': ' . rcube_mime::decode_mime_string($message->headers->to, $message->headers->charset) . "\r\n" . + "\t" . $RCMAIL->gettext("subject") . ': ' . $message->subject . "\r\n" . + "\t" . $RCMAIL->gettext("sent") . ': ' . $RCMAIL->format_date($message->headers->date, $RCMAIL->config->get('date_long')) . "\r\n" . + "\r\n" . $RCMAIL->gettext("receiptnote"); + + $compose->headers($headers); + $compose->setContentType('multipart/report', array('report-type'=> 'disposition-notification')); + $compose->setTXTBody(rcube_mime::wordwrap($body, 75, "\r\n")); + $compose->addAttachment($report, 'message/disposition-notification', 'MDNPart2.txt', false, '7bit', 'inline'); - $sent = $RCMAIL->deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file, $options); + if ($RCMAIL->config->get('mdn_use_from')) { + $options['mdn_use_from'] = true; + } + + $sent = $RCMAIL->deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file, $options); - if ($sent) { - $RCMAIL->storage->set_flag($message->uid, 'MDNSENT'); - return true; + if ($sent) { + $RCMAIL->storage->set_flag($message->uid, 'MDNSENT'); + return true; + } } - } - return false; + return false; } /** @@ -1856,15 +1924,17 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r // Fixes some content-type names function rcmail_fix_mimetype($name) { - // Some versions of Outlook create garbage Content-Type: - // application/pdf.A520491B_3BF7_494D_8855_7FAC2C6C0608 - if (preg_match('/^application\/pdf.+/', $name)) - $name = 'application/pdf'; - // treat image/pjpeg (image/pjpg, image/jpg) as image/jpeg (#1489097) - else if (preg_match('/^image\/p?jpe?g$/', $name)) - $name = 'image/jpeg'; - - return $name; + // Some versions of Outlook create garbage Content-Type: + // application/pdf.A520491B_3BF7_494D_8855_7FAC2C6C0608 + if (preg_match('/^application\/pdf.+/', $name)) { + $name = 'application/pdf'; + } + // treat image/pjpeg (image/pjpg, image/jpg) as image/jpeg (#1489097) + else if (preg_match('/^image\/p?jpe?g$/', $name)) { + $name = 'image/jpeg'; + } + + return $name; } // return attachment filename, handle empty filename case @@ -1902,92 +1972,104 @@ function rcmail_attachment_name($attachment, $display = false) function rcmail_search_filter($attrib) { - global $RCMAIL, $OUTPUT, $CONFIG; - - if (!strlen($attrib['id'])) - $attrib['id'] = 'rcmlistfilter'; - - $attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.'.filter_mailbox(this.value)'; - - // Content-Type values of messages with attachments - // the same as in app.js:add_message_row() - $ctypes = array('application/', 'multipart/m', 'multipart/signed', 'multipart/report'); - - // Build search string of "with attachment" filter - $attachment = str_repeat(' OR', count($ctypes)-1); - foreach ($ctypes as $type) { - $attachment .= ' HEADER Content-Type ' . rcube_imap_generic::escape($type); - } - - $select_filter = new html_select($attrib); - $select_filter->add($RCMAIL->gettext('all'), 'ALL'); - $select_filter->add($RCMAIL->gettext('unread'), 'UNSEEN'); - $select_filter->add($RCMAIL->gettext('flagged'), 'FLAGGED'); - $select_filter->add($RCMAIL->gettext('unanswered'), 'UNANSWERED'); - if (!$CONFIG['skip_deleted']) { - $select_filter->add($RCMAIL->gettext('deleted'), 'DELETED'); - $select_filter->add($RCMAIL->gettext('undeleted'), 'UNDELETED'); - } - $select_filter->add($RCMAIL->gettext('withattachment'), $attachment); - $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('highest'), 'HEADER X-PRIORITY 1'); - $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('high'), 'HEADER X-PRIORITY 2'); - $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('normal'), 'NOT HEADER X-PRIORITY 1 NOT HEADER X-PRIORITY 2 NOT HEADER X-PRIORITY 4 NOT HEADER X-PRIORITY 5'); - $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('low'), 'HEADER X-PRIORITY 4'); - $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('lowest'), 'HEADER X-PRIORITY 5'); - - $out = $select_filter->show($_SESSION['search_filter']); - - $OUTPUT->add_gui_object('search_filter', $attrib['id']); - - return $out; + global $RCMAIL; + + if (!strlen($attrib['id'])) + $attrib['id'] = 'rcmlistfilter'; + + $attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.'.filter_mailbox(this.value)'; + + // Content-Type values of messages with attachments + // the same as in app.js:add_message_row() + $ctypes = array('application/', 'multipart/m', 'multipart/signed', 'multipart/report'); + + // Build search string of "with attachment" filter + $attachment = str_repeat(' OR', count($ctypes)-1); + foreach ($ctypes as $type) { + $attachment .= ' HEADER Content-Type ' . rcube_imap_generic::escape($type); + } + + $select_filter = new html_select($attrib); + $select_filter->add($RCMAIL->gettext('all'), 'ALL'); + $select_filter->add($RCMAIL->gettext('unread'), 'UNSEEN'); + $select_filter->add($RCMAIL->gettext('flagged'), 'FLAGGED'); + $select_filter->add($RCMAIL->gettext('unanswered'), 'UNANSWERED'); + if (!$RCMAIL->config->get('skip_deleted')) { + $select_filter->add($RCMAIL->gettext('deleted'), 'DELETED'); + $select_filter->add($RCMAIL->gettext('undeleted'), 'UNDELETED'); + } + $select_filter->add($RCMAIL->gettext('withattachment'), $attachment); + $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('highest'), 'HEADER X-PRIORITY 1'); + $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('high'), 'HEADER X-PRIORITY 2'); + $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('normal'), 'NOT HEADER X-PRIORITY 1 NOT HEADER X-PRIORITY 2 NOT HEADER X-PRIORITY 4 NOT HEADER X-PRIORITY 5'); + $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('low'), 'HEADER X-PRIORITY 4'); + $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('lowest'), 'HEADER X-PRIORITY 5'); + + $out = $select_filter->show($_SESSION['search_filter']); + + $RCMAIL->output->add_gui_object('search_filter', $attrib['id']); + + return $out; } function rcmail_message_error($uid=null) { - global $RCMAIL; + global $RCMAIL; - // Set env variables for messageerror.html template - if ($RCMAIL->action == 'show') { - $mbox_name = $RCMAIL->storage->get_folder(); - $RCMAIL->output->set_env('mailbox', $mbox_name); - $RCMAIL->output->set_env('uid', null); - } - // display error message - $RCMAIL->output->show_message('messageopenerror', 'error'); - // ... display message error page - $RCMAIL->output->send('messageerror'); + // Set env variables for messageerror.html template + if ($RCMAIL->action == 'show') { + $mbox_name = $RCMAIL->storage->get_folder(); + + $RCMAIL->output->set_env('mailbox', $mbox_name); + $RCMAIL->output->set_env('uid', null); + } + + // display error message + $RCMAIL->output->show_message('messageopenerror', 'error'); + // ... display message error page + $RCMAIL->output->send('messageerror'); } function rcmail_message_import_form($attrib = array()) { - global $OUTPUT, $RCMAIL; - - // set defaults - $attrib += array('id' => 'rcmImportform', 'buttons' => 'yes'); - - // Get filesize, enable upload progress bar - $max_filesize = $RCMAIL->upload_init(); - - $button = new html_inputfield(array('type' => 'button')); - $fileinput = new html_inputfield(array( - 'type' => 'file', - 'name' => '_file[]', - 'multiple' => 'multiple', - 'accept' => ".eml, .mbox, message/rfc822, text/*", - )); - - $out = html::div($attrib, - $OUTPUT->form_tag(array('id' => $attrib['id'].'Frm', 'method' => 'post', 'enctype' => 'multipart/form-data'), - html::tag('input', array('type' => 'hidden', 'name' => '_unlock', 'value' => '')) . - html::div(null, $fileinput->show()) . - html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) . - (rcube_utils::get_boolean($attrib['buttons']) ? html::div('buttons', - $button->show($RCMAIL->gettext('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' . - $button->show($RCMAIL->gettext('upload'), array('class' => 'button mainaction', 'onclick' => rcmail_output::JS_OBJECT_NAME . ".command('import-messages', this.form)")) - ) : '') - ) - ); - - $OUTPUT->add_gui_object('importform', $attrib['id'].'Frm'); - return $out; + global $RCMAIL; + + // set defaults + $attrib += array('id' => 'rcmImportform', 'buttons' => 'yes'); + + // Get filesize, enable upload progress bar + $max_filesize = $RCMAIL->upload_init(); + + $button = new html_inputfield(array('type' => 'button')); + $fileinput = new html_inputfield(array( + 'type' => 'file', + 'name' => '_file[]', + 'multiple' => 'multiple', + 'accept' => ".eml, .mbox, message/rfc822, text/*", + )); + + $content = html::tag('input', array('type' => 'hidden', 'name' => '_unlock', 'value' => '')) + . html::div(null, $fileinput->show()) + . html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))); + + if (rcube_utils::get_boolean($attrib['buttons'])) { + $content .= html::div('buttons', + $button->show($RCMAIL->gettext('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) + . ' ' . + $button->show($RCMAIL->gettext('upload'), array( + 'class' => 'button mainaction', + 'onclick' => rcmail_output::JS_OBJECT_NAME . ".command('import-messages', this.form)" + ))); + } + + $out = $RCMAIL->output->form_tag(array( + 'id' => $attrib['id'].'Frm', + 'method' => 'post', + 'enctype' => 'multipart/form-data' + ), + $content); + + $RCMAIL->output->add_gui_object('importform', $attrib['id'].'Frm'); + + return html::div($attrib, $out); } diff --git a/program/steps/mail/mark.inc b/program/steps/mail/mark.inc index b081bc9b0..daa8c7e54 100644 --- a/program/steps/mail/mark.inc +++ b/program/steps/mail/mark.inc @@ -4,7 +4,7 @@ | program/steps/mail/mark.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -19,112 +19,123 @@ */ // only process ajax requests -if (!$OUTPUT->ajax_call) - return; - -$a_flags_map = array( - 'undelete' => 'UNDELETED', - 'delete' => 'DELETED', - 'read' => 'SEEN', - 'unread' => 'UNSEEN', - 'flagged' => 'FLAGGED', - 'unflagged' => 'UNFLAGGED'); - -$threading = (bool) $RCMAIL->storage->get_threading(); - -if (($uids = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST)) && ($flag = rcube_utils::get_input_value('_flag', rcube_utils::INPUT_POST))) -{ - $flag = $a_flags_map[$flag] ? $a_flags_map[$flag] : strtoupper($flag); - - if ($flag == 'DELETED' && $CONFIG['skip_deleted'] && $_POST['_from'] != 'show') { - // count messages before changing anything - $old_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL'); - $old_pages = ceil($old_count / $RCMAIL->storage->get_pagesize()); - $count = sizeof(explode(',', $uids)); - } - - $marked = $RCMAIL->storage->set_flag($uids, $flag); - - if (!$marked) { - // send error message - if ($_POST['_from'] != 'show') - $OUTPUT->command('list_mailbox'); - $RCMAIL->display_server_error('errormarking'); - $OUTPUT->send(); - exit; - } - else if (empty($_POST['_quiet'])) { - $OUTPUT->show_message('messagemarked', 'confirmation'); - } - - if ($flag == 'DELETED' && $CONFIG['read_when_deleted'] && !empty($_POST['_ruid'])) { - $ruids = rcube_utils::get_input_value('_ruid', rcube_utils::INPUT_POST); - $read = $RCMAIL->storage->set_flag($ruids, 'SEEN'); - - if ($read && !$CONFIG['skip_deleted']) - $OUTPUT->command('flag_deleted_as_read', $ruids); - } - - if ($flag == 'SEEN' || $flag == 'UNSEEN' || ($flag == 'DELETED' && !$CONFIG['skip_deleted'])) { - rcmail_send_unread_count($RCMAIL->storage->get_folder()); - } - else if ($flag == 'DELETED' && $CONFIG['skip_deleted']) { - if ($_POST['_from'] == 'show') { - if ($next = rcube_utils::get_input_value('_next_uid', rcube_utils::INPUT_GPC)) - $OUTPUT->command('show_message', $next); - else - $OUTPUT->command('command', 'list'); - } else { - $search_request = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC); - // refresh saved search set after moving some messages - if ($search_request && $RCMAIL->storage->get_search_set()) { - $_SESSION['search'] = $RCMAIL->storage->refresh_search(); - } - - $msg_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL'); - $page_size = $RCMAIL->storage->get_pagesize(); - $page = $RCMAIL->storage->get_page(); - $pages = ceil($msg_count / $page_size); - $nextpage_count = $old_count - $page_size * $page; - $remaining = $msg_count - $page_size * ($page - 1); - - // jump back one page (user removed the whole last page) - if ($page > 1 && $remaining == 0) { - $page -= 1; - $RCMAIL->storage->set_page($page); - $_SESSION['page'] = $page; - $jump_back = true; - } - - // update message count display - $OUTPUT->set_env('messagecount', $msg_count); - $OUTPUT->set_env('current_page', $page); - $OUTPUT->set_env('pagecount', $pages); - - // update mailboxlist - $mbox = $RCMAIL->storage->get_folder(); - $unseen_count = $msg_count ? $RCMAIL->storage->count($mbox, 'UNSEEN') : 0; - $old_unseen = rcmail_get_unseen_count($mbox); - - if ($old_unseen != $unseen_count) { - $OUTPUT->command('set_unread_count', $mbox, $unseen_count, ($mbox == 'INBOX')); - rcmail_set_unseen_count($mbox, $unseen_count); - } - $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count), $mbox); - - if ($threading) { - $count = rcube_utils::get_input_value('_count', rcube_utils::INPUT_POST); - } - - // add new rows from next page (if any) - if ($count && $uids != '*' && ($jump_back || $nextpage_count > 0)) { - $a_headers = $RCMAIL->storage->list_messages($mbox, NULL, - rcmail_sort_column(), rcmail_sort_order(), $jump_back ? NULL : $count); - - rcmail_js_message_list($a_headers, false); - } +if (!$OUTPUT->ajax_call) { + return; +} + +$threading = (bool) $RCMAIL->storage->get_threading(); +$skip_deleted = (bool) $RCMAIL->config->get('skip_deleted'); +$read_deleted = (bool) $RCMAIL->config->get('read_when_deleted'); + +$a_flags_map = array( + 'undelete' => 'UNDELETED', + 'delete' => 'DELETED', + 'read' => 'SEEN', + 'unread' => 'UNSEEN', + 'flagged' => 'FLAGGED', + 'unflagged' => 'UNFLAGGED', +); + +if (($uids = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST)) + && ($flag = rcube_utils::get_input_value('_flag', rcube_utils::INPUT_POST)) +) { + $flag = $a_flags_map[$flag] ? $a_flags_map[$flag] : strtoupper($flag); + + if ($flag == 'DELETED' && $skip_deleted && $_POST['_from'] != 'show') { + // count messages before changing anything + $old_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL'); + $old_pages = ceil($old_count / $RCMAIL->storage->get_pagesize()); + $count = sizeof(explode(',', $uids)); + } + + $marked = $RCMAIL->storage->set_flag($uids, $flag); + + if (!$marked) { + // send error message + if ($_POST['_from'] != 'show') { + $OUTPUT->command('list_mailbox'); + } + + $RCMAIL->display_server_error('errormarking'); + $OUTPUT->send(); + exit; + } + else if (empty($_POST['_quiet'])) { + $OUTPUT->show_message('messagemarked', 'confirmation'); + } + + if ($flag == 'DELETED' && $read_deleted && !empty($_POST['_ruid'])) { + $ruids = rcube_utils::get_input_value('_ruid', rcube_utils::INPUT_POST); + $read = $RCMAIL->storage->set_flag($ruids, 'SEEN'); + + if ($read && !$skip_deleted) { + $OUTPUT->command('flag_deleted_as_read', $ruids); + } + } + + if ($flag == 'SEEN' || $flag == 'UNSEEN' || ($flag == 'DELETED' && !$skip_deleted)) { + rcmail_send_unread_count($RCMAIL->storage->get_folder()); + } + else if ($flag == 'DELETED' && $skip_deleted) { + if ($_POST['_from'] == 'show') { + if ($next = rcube_utils::get_input_value('_next_uid', rcube_utils::INPUT_GPC)) + $OUTPUT->command('show_message', $next); + else + $OUTPUT->command('command', 'list'); + } + else { + $search_request = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC); + + // refresh saved search set after moving some messages + if ($search_request && $RCMAIL->storage->get_search_set()) { + $_SESSION['search'] = $RCMAIL->storage->refresh_search(); + } + + $msg_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL'); + $page_size = $RCMAIL->storage->get_pagesize(); + $page = $RCMAIL->storage->get_page(); + $pages = ceil($msg_count / $page_size); + $nextpage_count = $old_count - $page_size * $page; + $remaining = $msg_count - $page_size * ($page - 1); + + // jump back one page (user removed the whole last page) + if ($page > 1 && $remaining == 0) { + $page -= 1; + $RCMAIL->storage->set_page($page); + $_SESSION['page'] = $page; + $jump_back = true; + } + + // update message count display + $OUTPUT->set_env('messagecount', $msg_count); + $OUTPUT->set_env('current_page', $page); + $OUTPUT->set_env('pagecount', $pages); + + // update mailboxlist + $mbox = $RCMAIL->storage->get_folder(); + $unseen_count = $msg_count ? $RCMAIL->storage->count($mbox, 'UNSEEN') : 0; + $old_unseen = rcmail_get_unseen_count($mbox); + + if ($old_unseen != $unseen_count) { + $OUTPUT->command('set_unread_count', $mbox, $unseen_count, ($mbox == 'INBOX')); + rcmail_set_unseen_count($mbox, $unseen_count); + } + + $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count), $mbox); + + if ($threading) { + $count = rcube_utils::get_input_value('_count', rcube_utils::INPUT_POST); + } + + // add new rows from next page (if any) + if ($count && $uids != '*' && ($jump_back || $nextpage_count > 0)) { + $a_headers = $RCMAIL->storage->list_messages($mbox, NULL, + rcmail_sort_column(), rcmail_sort_order(), $jump_back ? NULL : $count); + + rcmail_js_message_list($a_headers, false); + } + } } - } } else { $OUTPUT->show_message('internalerror', 'error'); diff --git a/program/steps/mail/pagenav.inc b/program/steps/mail/pagenav.inc index 59c131f69..74cca88f2 100644 --- a/program/steps/mail/pagenav.inc +++ b/program/steps/mail/pagenav.inc @@ -35,14 +35,19 @@ if ($prev) { $OUTPUT->set_env('prev_uid', $prev); $OUTPUT->command('enable_command', 'previousmessage', 'firstmessage', true); } + if ($next) { $OUTPUT->set_env('next_uid', $next); $OUTPUT->command('enable_command', 'nextmessage', 'lastmessage', true); } -if ($first) + +if ($first) { $OUTPUT->set_env('first_uid', $first); -if ($last) +} + +if ($last) { $OUTPUT->set_env('last_uid', $last); +} // Don't need a real messages count value $OUTPUT->set_env('messagecount', 1); @@ -54,4 +59,3 @@ $OUTPUT->command('set_rowcount', $RCMAIL->gettext(array( ))); $OUTPUT->send(); - diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc index 210bedbb8..a80887254 100644 --- a/program/steps/mail/search.inc +++ b/program/steps/mail/search.inc @@ -1,14 +1,18 @@ <?php + /* +-----------------------------------------------------------------------+ | steps/mail/search.inc | | | - | Search functions for rc webmail | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | | See the README file for a full license statement. | | | + | PURPOSE: | + | Mail messages search action | +-----------------------------------------------------------------------+ | Author: Benjamin Smith <defitro@gmail.com> | | Thomas Bruederli <roundcube@gmail.com> | @@ -41,110 +45,108 @@ $search_str = $filter && $filter != 'ALL' ? $filter : ''; $_SESSION['search_filter'] = $filter; // Check the search string for type of search -if (preg_match("/^from:.*/i", $str)) -{ - list(,$srch) = explode(":", $str); - $subject['from'] = "HEADER FROM"; +if (preg_match("/^from:.*/i", $str)) { + list(,$srch) = explode(":", $str); + $subject['from'] = "HEADER FROM"; } -else if (preg_match("/^to:.*/i", $str)) -{ - list(,$srch) = explode(":", $str); - $subject['to'] = "HEADER TO"; +else if (preg_match("/^to:.*/i", $str)) { + list(,$srch) = explode(":", $str); + $subject['to'] = "HEADER TO"; } -else if (preg_match("/^cc:.*/i", $str)) -{ - list(,$srch) = explode(":", $str); - $subject['cc'] = "HEADER CC"; +else if (preg_match("/^cc:.*/i", $str)) { + list(,$srch) = explode(":", $str); + $subject['cc'] = "HEADER CC"; } -else if (preg_match("/^bcc:.*/i", $str)) -{ - list(,$srch) = explode(":", $str); - $subject['bcc'] = "HEADER BCC"; +else if (preg_match("/^bcc:.*/i", $str)) { + list(,$srch) = explode(":", $str); + $subject['bcc'] = "HEADER BCC"; } -else if (preg_match("/^subject:.*/i", $str)) -{ - list(,$srch) = explode(":", $str); - $subject['subject'] = "HEADER SUBJECT"; +else if (preg_match("/^subject:.*/i", $str)) { + list(,$srch) = explode(":", $str); + $subject['subject'] = "HEADER SUBJECT"; } -else if (preg_match("/^body:.*/i", $str)) -{ - list(,$srch) = explode(":", $str); - $subject['body'] = "BODY"; +else if (preg_match("/^body:.*/i", $str)) { + list(,$srch) = explode(":", $str); + $subject['body'] = "BODY"; } -else if (strlen(trim($str))) -{ - if ($headers) { - foreach (explode(',', $headers) as $header) { - if ($header == 'text') { - // #1488208: get rid of other headers when searching by "TEXT" - $subject = array('text' => 'TEXT'); - break; - } - else { - $subject[$header] = ($header != 'body' ? 'HEADER ' : '') . strtoupper($header); - } +else if (strlen(trim($str))) { + if ($headers) { + foreach (explode(',', $headers) as $header) { + if ($header == 'text') { + // #1488208: get rid of other headers when searching by "TEXT" + $subject = array('text' => 'TEXT'); + break; + } + else { + $subject[$header] = ($header != 'body' ? 'HEADER ' : '') . strtoupper($header); + } + } + + // save search modifiers for the current folder to user prefs + $search_mods = rcmail_search_mods(); + $search_mods[$mbox] = array_fill_keys(array_keys($subject), 1); + + $RCMAIL->user->save_prefs(array('search_mods' => $search_mods)); + } + else { + // search in subject by default + $subject['subject'] = 'HEADER SUBJECT'; } - - // save search modifiers for the current folder to user prefs - $search_mods = $RCMAIL->config->get('search_mods', $SEARCH_MODS_DEFAULT); - $search_mods[$mbox] = array_fill_keys(array_keys($subject), 1); - $RCMAIL->user->save_prefs(array('search_mods' => $search_mods)); - } - else { - // search in subject by default - $subject['subject'] = 'HEADER SUBJECT'; - } } $search = isset($srch) ? trim($srch) : trim($str); if (!empty($subject)) { - $search_str .= str_repeat(' OR', count($subject)-1); - foreach ($subject as $sub) - $search_str .= ' ' . $sub . ' ' . rcube_imap_generic::escape($search); + $search_str .= str_repeat(' OR', count($subject)-1); + foreach ($subject as $sub) { + $search_str .= ' ' . $sub . ' ' . rcube_imap_generic::escape($search); + } } $search_str = trim($search_str); $sort_column = rcmail_sort_column(); // execute IMAP search -if ($search_str) - $RCMAIL->storage->search($mbox, $search_str, $imap_charset, $sort_column); +if ($search_str) { + $RCMAIL->storage->search($mbox, $search_str, $imap_charset, $sort_column); +} // save search results in session -if (!is_array($_SESSION['search'])) - $_SESSION['search'] = array(); +if (!is_array($_SESSION['search'])) { + $_SESSION['search'] = array(); +} if ($search_str) { - $_SESSION['search'] = $RCMAIL->storage->get_search_set(); - $_SESSION['last_text_search'] = $str; + $_SESSION['search'] = $RCMAIL->storage->get_search_set(); + $_SESSION['last_text_search'] = $str; } $_SESSION['search_request'] = $search_request; // Get the headers $result_h = $RCMAIL->storage->list_messages($mbox, 1, $sort_column, rcmail_sort_order()); -$count = $RCMAIL->storage->count($mbox, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'); +$count = $RCMAIL->storage->count($mbox, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'); // Make sure we got the headers if (!empty($result_h)) { - rcmail_js_message_list($result_h); - if ($search_str) - $OUTPUT->show_message('searchsuccessful', 'confirmation', array('nr' => $RCMAIL->storage->count(NULL, 'ALL'))); - - // remember last HIGHESTMODSEQ value (if supported) - // we need it for flag updates in check-recent - $data = $RCMAIL->storage->folder_data($mbox_name); - if (!empty($data['HIGHESTMODSEQ'])) { - $_SESSION['list_mod_seq'] = $data['HIGHESTMODSEQ']; - } + rcmail_js_message_list($result_h); + if ($search_str) { + $OUTPUT->show_message('searchsuccessful', 'confirmation', array('nr' => $RCMAIL->storage->count(NULL, 'ALL'))); + } + + // remember last HIGHESTMODSEQ value (if supported) + // we need it for flag updates in check-recent + $data = $RCMAIL->storage->folder_data($mbox_name); + if (!empty($data['HIGHESTMODSEQ'])) { + $_SESSION['list_mod_seq'] = $data['HIGHESTMODSEQ']; + } } // handle IMAP errors (e.g. #1486905) else if ($err_code = $RCMAIL->storage->get_error_code()) { - $RCMAIL->display_server_error(); + $RCMAIL->display_server_error(); } else { - $OUTPUT->show_message('searchnomatch', 'notice'); + $OUTPUT->show_message('searchnomatch', 'notice'); } // update message count display diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc index a9e3d3f91..b187d5c5c 100644 --- a/program/steps/mail/sendmail.inc +++ b/program/steps/mail/sendmail.inc @@ -5,7 +5,7 @@ | program/steps/mail/sendmail.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2011, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -24,7 +24,9 @@ $OUTPUT->reset(); $OUTPUT->framed = TRUE; -$savedraft = !empty($_POST['_draft']) ? true : false; +$savedraft = !empty($_POST['_draft']) ? true : false; +$sendmail_delay = (int) $RCMAIL->config->get('sendmail_delay'); +$drafts_mbox = $RCMAIL->config->get('drafts_mbox'); $COMPOSE_ID = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC); $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; @@ -32,260 +34,36 @@ $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; /****** checks ********/ if (!isset($COMPOSE['id'])) { - rcube::raise_error(array('code' => 500, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Invalid compose ID"), true, false); - - $OUTPUT->show_message('internalerror', 'error'); - $OUTPUT->send('iframe'); -} + rcube::raise_error(array('code' => 500, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Invalid compose ID"), true, false); -if (!$savedraft) { - if (empty($_POST['_to']) && empty($_POST['_cc']) && empty($_POST['_bcc']) - && empty($_POST['_subject']) && $_POST['_message']) { - $OUTPUT->show_message('sendingfailed', 'error'); + $OUTPUT->show_message('internalerror', 'error'); $OUTPUT->send('iframe'); - } - - if(!empty($CONFIG['sendmail_delay'])) { - $wait_sec = time() - intval($CONFIG['sendmail_delay']) - intval($CONFIG['last_message_time']); - if ($wait_sec < 0) { - $OUTPUT->show_message('senttooquickly', 'error', array('sec' => $wait_sec * -1)); - $OUTPUT->send('iframe'); - } - } -} - - -/****** message sending functions ********/ - -// encrypt parts of the header -function rcmail_encrypt_header($what) -{ - global $CONFIG, $RCMAIL; - if (!$CONFIG['http_received_header_encrypt']) { - return $what; - } - return $RCMAIL->encrypt($what); -} - -// get identity record -function rcmail_get_identity($id) -{ - global $RCMAIL, $message_charset; - global $RCMAIL; - - if ($sql_arr = $RCMAIL->user->get_identity($id)) { - $out = $sql_arr; - - if ($message_charset != RCUBE_CHARSET) { - foreach ($out as $k => $v) - $out[$k] = rcube_charset::convert($v, RCUBE_CHARSET, $message_charset); - } - - $out['mailto'] = $sql_arr['email']; - $out['string'] = format_email_recipient($sql_arr['email'], $sql_arr['name']); - - return $out; - } - - return FALSE; } -/** - * go from this: - * <img src="http[s]://.../tiny_mce/plugins/emotions/images/smiley-cool.gif" border="0" alt="Cool" title="Cool" /> - * - * to this: - * - * <img src="/path/on/server/.../tiny_mce/plugins/emotions/images/smiley-cool.gif" border="0" alt="Cool" title="Cool" /> - */ -function rcmail_fix_emoticon_paths($mime_message) -{ - global $RCMAIL; - - $body = $mime_message->getHTMLBody(); - - // remove any null-byte characters before parsing - $body = preg_replace('/\x00/', '', $body); - - $searchstr = 'program/js/tiny_mce/plugins/emotions/img/'; - $offset = 0; - - // keep track of added images, so they're only added once - $included_images = array(); - - if (preg_match_all('# src=[\'"]([^\'"]+)#', $body, $matches, PREG_OFFSET_CAPTURE)) { - foreach ($matches[1] as $m) { - // find emoticon image tags - if (preg_match('#'.$searchstr.'(.*)$#', $m[0], $imatches)) { - $image_name = $imatches[1]; - - // sanitize image name so resulting attachment doesn't leave images dir - $image_name = preg_replace('/[^a-zA-Z0-9_\.\-]/i', '', $image_name); - $img_file = INSTALL_PATH . '/' . $searchstr . $image_name; - - if (! in_array($image_name, $included_images)) { - // add the image to the MIME message - if (!$mime_message->addHTMLImage($img_file, 'image/gif', '', true, $image_name)) { - $RCMAIL->output->show_message("emoticonerror", 'error'); - } - array_push($included_images, $image_name); - } - - $body = substr_replace($body, $img_file, $m[1] + $offset, strlen($m[0])); - $offset += strlen($img_file) - strlen($m[0]); - } - } - } - - $mime_message->setHTMLBody($body); -} - -/** - * Extract image attachments from HTML content (data URIs) - */ -function rcmail_extract_inline_images($mime_message, $from) -{ - $body = $mime_message->getHTMLBody(); - $offset = 0; - $list = array(); - $regexp = '# src=[\'"](data:(image/[a-z]+);base64,([a-z0-9+/=\r\n]+))([\'"])#i'; - - // get domain for the Content-ID, must be the same as in Mail_Mime::get() - if (preg_match('#@([0-9a-zA-Z\-\.]+)#', $from, $matches)) { - $domain = $matches[1]; - } else { - $domain = 'localhost'; +if (!$savedraft) { + if (empty($_POST['_to']) && empty($_POST['_cc']) && empty($_POST['_bcc']) + && empty($_POST['_subject']) && $_POST['_message'] + ) { + $OUTPUT->show_message('sendingfailed', 'error'); + $OUTPUT->send('iframe'); } - if (preg_match_all($regexp, $body, $matches, PREG_OFFSET_CAPTURE)) { - foreach ($matches[1] as $idx => $m) { - $data = preg_replace('/\r\n/', '', $matches[3][$idx][0]); - $data = base64_decode($data); - - if (empty($data)) { - continue; - } - - $hash = md5($data) . '@' . $domain; - $mime_type = $matches[2][$idx][0]; - $name = $list[$hash]; - - // add the image to the MIME message - if (!$name) { - $ext = preg_replace('#^[^/]+/#', '', $mime_type); - $name = substr($hash, 0, 8) . '.' . $ext; - $list[$hash] = $name; - - $mime_message->addHTMLImage($data, $mime_type, $name, false, $hash); - } - - $body = substr_replace($body, $name, $m[1] + $offset, strlen($m[0])); - $offset += strlen($name) - strlen($m[0]); + if ($sendmail_delay) { + $wait_sec = time() - $sendmail_delay - intval($RCMAIL->config->get('last_message_time')); + if ($wait_sec < 0) { + $OUTPUT->show_message('senttooquickly', 'error', array('sec' => $wait_sec * -1)); + $OUTPUT->send('iframe'); } } - - $mime_message->setHTMLBody($body); -} - -/** - * Parse and cleanup email address input (and count addresses) - * - * @param string Address input - * @param boolean Do count recipients (saved in global $RECIPIENT_COUNT) - * @param boolean Validate addresses (errors saved in global $EMAIL_FORMAT_ERROR) - * @return string Canonical recipients string separated by comma - */ -function rcmail_email_input_format($mailto, $count=false, $check=true) -{ - global $RCMAIL, $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT; - - // simplified email regexp, supporting quoted local part - $email_regexp = '(\S+|("[^"]+"))@\S+'; - - $delim = trim($RCMAIL->config->get('recipients_separator', ',')); - $regexp = array("/[,;$delim]\s*[\r\n]+/", '/[\r\n]+/', "/[,;$delim]\s*\$/m", '/;/', '/(\S{1})(<'.$email_regexp.'>)/U'); - $replace = array($delim.' ', ', ', '', $delim, '\\1 \\2'); - - // replace new lines and strip ending ', ', make address input more valid - $mailto = trim(preg_replace($regexp, $replace, $mailto)); - - $result = array(); - $items = rcube_utils::explode_quoted_string($delim, $mailto); - - foreach($items as $item) { - $item = trim($item); - // address in brackets without name (do nothing) - if (preg_match('/^<'.$email_regexp.'>$/', $item)) { - $item = rcube_utils::idn_to_ascii(trim($item, '<>')); - $result[] = $item; - // address without brackets and without name (add brackets) - } else if (preg_match('/^'.$email_regexp.'$/', $item)) { - $item = rcube_utils::idn_to_ascii($item); - $result[] = $item; - // address with name (handle name) - } else if (preg_match('/<*'.$email_regexp.'>*$/', $item, $matches)) { - $address = $matches[0]; - $name = trim(str_replace($address, '', $item)); - if ($name[0] == '"' && $name[count($name)-1] == '"') { - $name = substr($name, 1, -1); - } - $name = stripcslashes($name); - $address = rcube_utils::idn_to_ascii(trim($address, '<>')); - $result[] = format_email_recipient($address, $name); - $item = $address; - } else if (trim($item)) { - continue; - } - - // check address format - $item = trim($item, '<>'); - if ($item && $check && !rcube_utils::check_email($item)) { - $EMAIL_FORMAT_ERROR = $item; - return; - } - } - - if ($count) { - $RECIPIENT_COUNT += count($result); - } - - return implode(', ', $result); -} - - -function rcmail_generic_message_footer($isHtml) -{ - global $CONFIG; - - if ($isHtml && !empty($CONFIG['generic_message_footer_html'])) { - $file = $CONFIG['generic_message_footer_html']; - $html_footer = true; - } - else { - $file = $CONFIG['generic_message_footer']; - $html_footer = false; - } - - if ($file && realpath($file)) { - // sanity check - if (!preg_match('/\.(php|ini|conf)$/', $file) && strpos($file, '/etc/') === false) { - $footer = file_get_contents($file); - if ($isHtml && !$html_footer) - $footer = '<pre>' . $footer . '</pre>'; - return $footer; - } - } - - return false; } /****** compose message ********/ if (empty($COMPOSE['param']['message-id'])) { - $COMPOSE['param']['message-id'] = $RCMAIL->gen_message_id(); + $COMPOSE['param']['message-id'] = $RCMAIL->gen_message_id(); } $message_id = $COMPOSE['param']['message-id']; @@ -293,92 +71,102 @@ $message_id = $COMPOSE['param']['message-id']; $message_charset = isset($_POST['_charset']) ? $_POST['_charset'] : $OUTPUT->get_charset(); $EMAIL_FORMAT_ERROR = NULL; -$RECIPIENT_COUNT = 0; +$RECIPIENT_COUNT = 0; -$mailto = rcmail_email_input_format(rcube_utils::get_input_value('_to', rcube_utils::INPUT_POST, TRUE, $message_charset), true); -$mailcc = rcmail_email_input_format(rcube_utils::get_input_value('_cc', rcube_utils::INPUT_POST, TRUE, $message_charset), true); +$mailto = rcmail_email_input_format(rcube_utils::get_input_value('_to', rcube_utils::INPUT_POST, TRUE, $message_charset), true); +$mailcc = rcmail_email_input_format(rcube_utils::get_input_value('_cc', rcube_utils::INPUT_POST, TRUE, $message_charset), true); $mailbcc = rcmail_email_input_format(rcube_utils::get_input_value('_bcc', rcube_utils::INPUT_POST, TRUE, $message_charset), true); if ($EMAIL_FORMAT_ERROR) { - $OUTPUT->show_message('emailformaterror', 'error', array('email' => $EMAIL_FORMAT_ERROR)); - $OUTPUT->send('iframe'); + $OUTPUT->show_message('emailformaterror', 'error', array('email' => $EMAIL_FORMAT_ERROR)); + $OUTPUT->send('iframe'); } if (empty($mailto) && !empty($mailcc)) { - $mailto = $mailcc; - $mailcc = null; + $mailto = $mailcc; + $mailcc = null; +} +else if (empty($mailto)) { + $mailto = 'undisclosed-recipients:;'; } -else if (empty($mailto)) - $mailto = 'undisclosed-recipients:;'; // Get sender name and address... $from = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST, true, $message_charset); // ... from identity... if (is_numeric($from)) { - if (is_array($identity_arr = rcmail_get_identity($from))) { - if ($identity_arr['mailto']) - $from = $identity_arr['mailto']; - if ($identity_arr['string']) - $from_string = $identity_arr['string']; - } - else { - $from = null; - } + if (is_array($identity_arr = rcmail_get_identity($from))) { + if ($identity_arr['mailto']) + $from = $identity_arr['mailto']; + if ($identity_arr['string']) + $from_string = $identity_arr['string']; + } + else { + $from = null; + } } // ... if there is no identity record, this might be a custom from else if ($from_string = rcmail_email_input_format($from)) { - if (preg_match('/(\S+@\S+)/', $from_string, $m)) - $from = trim($m[1], '<>'); - else - $from = null; + if (preg_match('/(\S+@\S+)/', $from_string, $m)) + $from = trim($m[1], '<>'); + else + $from = null; } -if (!$from_string && $from) - $from_string = $from; +if (!$from_string && $from) { + $from_string = $from; +} // compose headers array $headers = array(); // if configured, the Received headers goes to top, for good measure -if ($CONFIG['http_received_header']) -{ - $nldlm = "\r\n\t"; - // FROM/VIA - $http_header = 'from '; - if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { - $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2); - $hostname = gethostbyaddr($hosts[0]); - - if ($CONFIG['http_received_header_encrypt']) { - $http_header .= rcmail_encrypt_header($hostname); - if ($host != $hostname) - $http_header .= ' ('. rcmail_encrypt_header($host) . ')'; - } else { - $http_header .= (($host != $hostname) ? $hostname : '[' . $host . ']'); - if ($host != $hostname) - $http_header .= ' (['. $host .'])'; - } - $http_header .= $nldlm . ' via '; - } - $host = $_SERVER['REMOTE_ADDR']; - $hostname = gethostbyaddr($host); - if ($CONFIG['http_received_header_encrypt']) { - $http_header .= rcmail_encrypt_header($hostname); - if ($host != $hostname) - $http_header .= ' ('. rcmail_encrypt_header($host) . ')'; - } else { - $http_header .= (($host != $hostname) ? $hostname : '[' . $host . ']'); - if ($host != $hostname) - $http_header .= ' (['. $host .'])'; - } - // BY - $http_header .= $nldlm . 'by ' . $_SERVER['HTTP_HOST']; - // WITH - $http_header .= $nldlm . 'with HTTP (' . $_SERVER['SERVER_PROTOCOL'] . +if ($RCMAIL->config->get('http_received_header')) { + $nldlm = "\r\n\t"; + $encrypt = $RCMAIL->config->get('http_received_header_encrypt'); + + // FROM/VIA + $http_header = 'from '; + + if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2); + $hostname = gethostbyaddr($hosts[0]); + + if ($encrypt) { + $http_header .= rcmail_encrypt_header($hostname); + if ($host != $hostname) + $http_header .= ' ('. rcmail_encrypt_header($host) . ')'; + } + else { + $http_header .= (($host != $hostname) ? $hostname : '[' . $host . ']'); + if ($host != $hostname) + $http_header .= ' (['. $host .'])'; + } + $http_header .= $nldlm . ' via '; + } + + $host = $_SERVER['REMOTE_ADDR']; + $hostname = gethostbyaddr($host); + + if ($encrypt) { + $http_header .= rcmail_encrypt_header($hostname); + if ($host != $hostname) + $http_header .= ' ('. rcmail_encrypt_header($host) . ')'; + } + else { + $http_header .= (($host != $hostname) ? $hostname : '[' . $host . ']'); + if ($host != $hostname) + $http_header .= ' (['. $host .'])'; + } + + // BY + $http_header .= $nldlm . 'by ' . $_SERVER['HTTP_HOST']; + + // WITH + $http_header .= $nldlm . 'with HTTP (' . $_SERVER['SERVER_PROTOCOL'] . ' '.$_SERVER['REQUEST_METHOD'] . '); ' . date('r'); - $http_header = wordwrap($http_header, 69, $nldlm); + $http_header = wordwrap($http_header, 69, $nldlm); - $headers['Received'] = $http_header; + $headers['Received'] = $http_header; } $headers['Date'] = $RCMAIL->user_date(); @@ -387,72 +175,73 @@ $headers['To'] = $mailto; // additional recipients if (!empty($mailcc)) { - $headers['Cc'] = $mailcc; + $headers['Cc'] = $mailcc; } if (!empty($mailbcc)) { - $headers['Bcc'] = $mailbcc; + $headers['Bcc'] = $mailbcc; } if (($max_recipients = (int) $RCMAIL->config->get('max_recipients')) > 0) { - if ($RECIPIENT_COUNT > $max_recipients) { - $OUTPUT->show_message('toomanyrecipients', 'error', array('max' => $max_recipients)); - $OUTPUT->send('iframe'); - } + if ($RECIPIENT_COUNT > $max_recipients) { + $OUTPUT->show_message('toomanyrecipients', 'error', array('max' => $max_recipients)); + $OUTPUT->send('iframe'); + } } // add subject $headers['Subject'] = trim(rcube_utils::get_input_value('_subject', rcube_utils::INPUT_POST, TRUE, $message_charset)); if (!empty($identity_arr['organization'])) { - $headers['Organization'] = $identity_arr['organization']; + $headers['Organization'] = $identity_arr['organization']; } -if (!empty($_POST['_replyto'])) { - $headers['Reply-To'] = rcmail_email_input_format(rcube_utils::get_input_value('_replyto', rcube_utils::INPUT_POST, TRUE, $message_charset)); +if ($hdr = rcube_utils::get_input_value('_replyto', rcube_utils::INPUT_POST, TRUE, $message_charset)) { + $headers['Reply-To'] = rcmail_email_input_format($hdr); } if (!empty($headers['Reply-To'])) { - $headers['Mail-Reply-To'] = $headers['Reply-To']; + $headers['Mail-Reply-To'] = $headers['Reply-To']; } -if (!empty($_POST['_followupto'])) { - $headers['Mail-Followup-To'] = rcmail_email_input_format(rcube_utils::get_input_value('_followupto', rcube_utils::INPUT_POST, TRUE, $message_charset)); +if ($hdr = rcube_utils::get_input_value('_followupto', rcube_utils::INPUT_POST, TRUE, $message_charset)) { + $headers['Mail-Followup-To'] = rcmail_email_input_format(); } // remember reply/forward UIDs in special headers if (!empty($COMPOSE['reply_uid']) && $savedraft) { - $headers['X-Draft-Info'] = array('type' => 'reply', 'uid' => $COMPOSE['reply_uid']); + $headers['X-Draft-Info'] = array('type' => 'reply', 'uid' => $COMPOSE['reply_uid']); } else if (!empty($COMPOSE['forward_uid']) && $savedraft) { - $headers['X-Draft-Info'] = array('type' => 'forward', 'uid' => $COMPOSE['forward_uid']); + $headers['X-Draft-Info'] = array('type' => 'forward', 'uid' => $COMPOSE['forward_uid']); } if (!empty($COMPOSE['reply_msgid'])) { - $headers['In-Reply-To'] = $COMPOSE['reply_msgid']; + $headers['In-Reply-To'] = $COMPOSE['reply_msgid']; } if (!empty($COMPOSE['references'])) { - $headers['References'] = $COMPOSE['references']; + $headers['References'] = $COMPOSE['references']; } if (!empty($_POST['_priority'])) { - $priority = intval($_POST['_priority']); - $a_priorities = array(1=>'highest', 2=>'high', 4=>'low', 5=>'lowest'); - if ($str_priority = $a_priorities[$priority]) { - $headers['X-Priority'] = sprintf("%d (%s)", $priority, ucfirst($str_priority)); - } + $priority = intval($_POST['_priority']); + $a_priorities = array(1 => 'highest', 2 => 'high', 4 => 'low', 5 => 'lowest'); + + if ($str_priority = $a_priorities[$priority]) { + $headers['X-Priority'] = sprintf("%d (%s)", $priority, ucfirst($str_priority)); + } } if (!empty($_POST['_receipt'])) { - $headers['Return-Receipt-To'] = $from_string; - $headers['Disposition-Notification-To'] = $from_string; + $headers['Return-Receipt-To'] = $from_string; + $headers['Disposition-Notification-To'] = $from_string; } // additional headers $headers['Message-ID'] = $message_id; -$headers['X-Sender'] = $from; +$headers['X-Sender'] = $from; if (is_array($headers['X-Draft-Info'])) { - $headers['X-Draft-Info'] = rcmail_draftinfo_encode($headers['X-Draft-Info'] + array('folder' => $COMPOSE['mailbox'])); + $headers['X-Draft-Info'] = rcmail_draftinfo_encode($headers['X-Draft-Info'] + array('folder' => $COMPOSE['mailbox'])); } -if (!empty($CONFIG['useragent'])) { - $headers['User-Agent'] = $CONFIG['useragent']; +if ($hdr = $RCMAIL->config->get('useragent')) { + $headers['User-Agent'] = $hdr; } // exec hook for header checking and manipulation @@ -461,12 +250,12 @@ $data = $RCMAIL->plugins->exec_hook('message_outgoing_headers', array('headers' // sending aborted by plugin if ($data['abort'] && !$savedraft) { - $OUTPUT->show_message($data['message'] ? $data['message'] : 'sendingfailed'); - $OUTPUT->send('iframe'); + $OUTPUT->show_message($data['message'] ? $data['message'] : 'sendingfailed'); + $OUTPUT->send('iframe'); +} +else { + $headers = $data['headers']; } -else - $headers = $data['headers']; - $isHtml = (bool) rcube_utils::get_input_value('_is_html', rcube_utils::INPUT_POST); @@ -474,72 +263,72 @@ $isHtml = (bool) rcube_utils::get_input_value('_is_html', rcube_utils::INPUT_POS $message_body = rcube_utils::get_input_value('_message', rcube_utils::INPUT_POST, TRUE, $message_charset); if ($isHtml) { - $bstyle = array(); + $bstyle = array(); - if ($font_size = $RCMAIL->config->get('default_font_size')) { - $bstyle[] = 'font-size: ' . $font_size; - } - if ($font_family = $RCMAIL->config->get('default_font')) { - $bstyle[] = 'font-family: ' . rcmail::font_defs($font_family); - } + if ($font_size = $RCMAIL->config->get('default_font_size')) { + $bstyle[] = 'font-size: ' . $font_size; + } + if ($font_family = $RCMAIL->config->get('default_font')) { + $bstyle[] = 'font-family: ' . rcmail::font_defs($font_family); + } - // append doctype and html/body wrappers - $message_body = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">' - . "\r\n<html><body" . (!empty($bstyle) ? " style='" . implode($bstyle, '; ') . "'" : '') . ">\r\n" - . $message_body; + // append doctype and html/body wrappers + $message_body = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">' + . "\r\n<html><body" . (!empty($bstyle) ? " style='" . implode($bstyle, '; ') . "'" : '') . ">\r\n" + . $message_body; } if (!$savedraft) { - if ($isHtml) { - // remove signature's div ID - $message_body = preg_replace('/\s*id="_rc_sig"/', '', $message_body); + if ($isHtml) { + // remove signature's div ID + $message_body = preg_replace('/\s*id="_rc_sig"/', '', $message_body); + + // add inline css for blockquotes + $bstyle = 'padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px'; + $message_body = preg_replace('/<blockquote>/', + '<blockquote type="cite" style="'.$bstyle.'">', $message_body); + } - // add inline css for blockquotes - $bstyle = 'padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px'; - $message_body = preg_replace('/<blockquote>/', - '<blockquote type="cite" style="'.$bstyle.'">', $message_body); - } + // Check spelling before send + if ($RCMAIL->config->get('spellcheck_before_send') && $RCMAIL->config->get('enable_spellcheck') + && empty($COMPOSE['spell_checked']) && !empty($message_body) + ) { + $message_body = str_replace("\r\n", "\n", $message_body); + $spellchecker = new rcube_spellchecker(rcube_utils::get_input_value('_lang', rcube_utils::INPUT_GPC)); + $spell_result = $spellchecker->check($message_body, $isHtml); - // Check spelling before send - if ($CONFIG['spellcheck_before_send'] && $CONFIG['enable_spellcheck'] - && empty($COMPOSE['spell_checked']) && !empty($message_body) - ) { - $message_body = str_replace("\r\n", "\n", $message_body); - $spellchecker = new rcube_spellchecker(rcube_utils::get_input_value('_lang', rcube_utils::INPUT_GPC)); - $spell_result = $spellchecker->check($message_body, $isHtml); + $COMPOSE['spell_checked'] = true; - $COMPOSE['spell_checked'] = true; + if (!$spell_result) { + $result = $isHtml ? $spellchecker->get_words() : $spellchecker->get_xml(); - if (!$spell_result) { - $result = $isHtml ? $spellchecker->get_words() : $spellchecker->get_xml(); - $OUTPUT->show_message('mispellingsfound', 'error'); - $OUTPUT->command('spellcheck_resume', $isHtml, $result); - $OUTPUT->send('iframe'); + $OUTPUT->show_message('mispellingsfound', 'error'); + $OUTPUT->command('spellcheck_resume', $isHtml, $result); + $OUTPUT->send('iframe'); + } } - } - // generic footer for all messages - if ($footer = rcmail_generic_message_footer($isHtml)) { - $footer = rcube_charset::convert($footer, RCUBE_CHARSET, $message_charset); - $message_body .= "\r\n" . $footer; - } + // generic footer for all messages + if ($footer = rcmail_generic_message_footer($isHtml)) { + $footer = rcube_charset::convert($footer, RCUBE_CHARSET, $message_charset); + $message_body .= "\r\n" . $footer; + } } if ($isHtml) { - $message_body .= "\r\n</body></html>\r\n"; + $message_body .= "\r\n</body></html>\r\n"; } // sort attachments to make sure the order is the same as in the UI (#1488423) -$files = rcube_utils::get_input_value('_attachments', rcube_utils::INPUT_POST); -if ($files) { - $files = explode(',', $files); - $files = array_flip($files); - foreach ($files as $idx => $val) { - $files[$idx] = $COMPOSE['attachments'][$idx]; - unset($COMPOSE['attachments'][$idx]); - } +if ($files = rcube_utils::get_input_value('_attachments', rcube_utils::INPUT_POST)) { + $files = explode(',', $files); + $files = array_flip($files); + foreach ($files as $idx => $val) { + $files[$idx] = $COMPOSE['attachments'][$idx]; + unset($COMPOSE['attachments'][$idx]); + } - $COMPOSE['attachments'] = array_merge(array_filter($files), $COMPOSE['attachments']); + $COMPOSE['attachments'] = array_merge(array_filter($files), $COMPOSE['attachments']); } // set line length for body wrapping @@ -553,138 +342,141 @@ $MAIL_MIME = new Mail_mime("\r\n"); // Check if we have enough memory to handle the message in it // It's faster than using files, so we'll do this if we only can -if (is_array($COMPOSE['attachments']) && $CONFIG['smtp_server'] - && ($mem_limit = parse_bytes(ini_get('memory_limit')))) -{ - $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB - - foreach ($COMPOSE['attachments'] as $id => $attachment) - $memory += $attachment['size']; +if (is_array($COMPOSE['attachments']) && $RCMAIL->config->get('smtp_server') + && ($mem_limit = parse_bytes(ini_get('memory_limit'))) +) { + $memory = 0; + foreach ($COMPOSE['attachments'] as $id => $attachment) { + $memory += $attachment['size']; + } - // Yeah, Net_SMTP needs up to 12x more memory, 1.33 is for base64 - if ($memory * 1.33 * 12 > $mem_limit) - $MAIL_MIME->setParam('delay_file_io', true); + // Yeah, Net_SMTP needs up to 12x more memory, 1.33 is for base64 + if (!rcube_utils::mem_check($memory * 1.33 * 12)) { + $MAIL_MIME->setParam('delay_file_io', true); + } } // For HTML-formatted messages, construct the MIME message with both // the HTML part and the plain-text part - if ($isHtml) { - $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body', - array('body' => $message_body, 'type' => 'html', 'message' => $MAIL_MIME)); + $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body', + array('body' => $message_body, 'type' => 'html', 'message' => $MAIL_MIME)); - $MAIL_MIME->setHTMLBody($plugin['body']); + $MAIL_MIME->setHTMLBody($plugin['body']); - // replace emoticons - $plugin['body'] = $RCMAIL->replace_emoticons($plugin['body']); + // replace emoticons + $plugin['body'] = $RCMAIL->replace_emoticons($plugin['body']); - // add a plain text version of the e-mail as an alternative part. - $h2t = new rcube_html2text($plugin['body'], false, true, 0, $message_charset); - $plainTextPart = rcube_mime::wordwrap($h2t->get_text(), $LINE_LENGTH, "\r\n", false, $message_charset); - $plainTextPart = wordwrap($plainTextPart, 998, "\r\n", true); + // add a plain text version of the e-mail as an alternative part. + $h2t = new rcube_html2text($plugin['body'], false, true, 0, $message_charset); + $plainTextPart = rcube_mime::wordwrap($h2t->get_text(), $LINE_LENGTH, "\r\n", false, $message_charset); + $plainTextPart = wordwrap($plainTextPart, 998, "\r\n", true); - // make sure all line endings are CRLF (#1486712) - $plainTextPart = preg_replace('/\r?\n/', "\r\n", $plainTextPart); + // make sure all line endings are CRLF (#1486712) + $plainTextPart = preg_replace('/\r?\n/', "\r\n", $plainTextPart); - $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body', - array('body' => $plainTextPart, 'type' => 'alternative', 'message' => $MAIL_MIME)); + $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body', + array('body' => $plainTextPart, 'type' => 'alternative', 'message' => $MAIL_MIME)); - $MAIL_MIME->setTXTBody($plugin['body']); + $MAIL_MIME->setTXTBody($plugin['body']); - // look for "emoticon" images from TinyMCE and change their src paths to - // be file paths on the server instead of URL paths. - rcmail_fix_emoticon_paths($MAIL_MIME); + // look for "emoticon" images from TinyMCE and change their src paths to + // be file paths on the server instead of URL paths. + rcmail_fix_emoticon_paths($MAIL_MIME); - // Extract image Data URIs into message attachments (#1488502) - rcmail_extract_inline_images($MAIL_MIME, $from); + // Extract image Data URIs into message attachments (#1488502) + rcmail_extract_inline_images($MAIL_MIME, $from); } else { - $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body', - array('body' => $message_body, 'type' => 'plain', 'message' => $MAIL_MIME)); + $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body', + array('body' => $message_body, 'type' => 'plain', 'message' => $MAIL_MIME)); - $message_body = $plugin['body']; + $message_body = $plugin['body']; - // compose format=flowed content if enabled - if ($flowed = ($savedraft || $RCMAIL->config->get('send_format_flowed', true))) - $message_body = rcube_mime::format_flowed($message_body, min($LINE_LENGTH+2, 79), $message_charset); - else - $message_body = rcube_mime::wordwrap($message_body, $LINE_LENGTH, "\r\n", false, $message_charset); + // compose format=flowed content if enabled + if ($flowed = ($savedraft || $RCMAIL->config->get('send_format_flowed', true))) + $message_body = rcube_mime::format_flowed($message_body, min($LINE_LENGTH+2, 79), $message_charset); + else + $message_body = rcube_mime::wordwrap($message_body, $LINE_LENGTH, "\r\n", false, $message_charset); - $message_body = wordwrap($message_body, 998, "\r\n", true); + $message_body = wordwrap($message_body, 998, "\r\n", true); - $MAIL_MIME->setTXTBody($message_body, false, true); + $MAIL_MIME->setTXTBody($message_body, false, true); } // add stored attachments, if any if (is_array($COMPOSE['attachments'])) { - foreach ($COMPOSE['attachments'] as $id => $attachment) { - // This hook retrieves the attachment contents from the file storage backend - $attachment = $RCMAIL->plugins->exec_hook('attachment_get', $attachment); - - if ($isHtml) { - $dispurl = '/\ssrc\s*=\s*[\'"]*\S+display-attachment\S+file=rcmfile' . preg_quote($attachment['id']) . '[\s\'"]*/'; - $message_body = $MAIL_MIME->getHTMLBody(); - $is_inline = preg_match($dispurl, $message_body); - } - else { - $is_inline = false; - } - - // inline image - if ($is_inline) { - // Mail_Mime does not support many inline attachments with the same name (#1489406) - // we'll generate cid: urls here to workaround this - $cid = preg_replace('/[^0-9a-zA-Z]/', '', uniqid(time(), true)); - if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $from, $matches)) { - $cid .= $matches[1]; - } else { - $cid .= '@localhost'; - } + foreach ($COMPOSE['attachments'] as $id => $attachment) { + // This hook retrieves the attachment contents from the file storage backend + $attachment = $RCMAIL->plugins->exec_hook('attachment_get', $attachment); + + if ($isHtml) { + $dispurl = '/\ssrc\s*=\s*[\'"]*\S+display-attachment\S+file=rcmfile' + . preg_quote($attachment['id']) . '[\s\'"]*/'; + $message_body = $MAIL_MIME->getHTMLBody(); + $is_inline = preg_match($dispurl, $message_body); + } + else { + $is_inline = false; + } - $message_body = preg_replace($dispurl, ' src="cid:' . $cid . '" ', $message_body); + // inline image + if ($is_inline) { + // Mail_Mime does not support many inline attachments with the same name (#1489406) + // we'll generate cid: urls here to workaround this + $cid = preg_replace('/[^0-9a-zA-Z]/', '', uniqid(time(), true)); + if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $from, $matches)) { + $cid .= $matches[1]; + } + else { + $cid .= '@localhost'; + } - $MAIL_MIME->setHTMLBody($message_body); + $message_body = preg_replace($dispurl, ' src="cid:' . $cid . '" ', $message_body); - if ($attachment['data']) - $MAIL_MIME->addHTMLImage($attachment['data'], $attachment['mimetype'], $attachment['name'], false, $cid); - else - $MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name'], true, $cid); - } - else { - $ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914 - $file = $attachment['data'] ? $attachment['data'] : $attachment['path']; + $MAIL_MIME->setHTMLBody($message_body); - $MAIL_MIME->addAttachment($file, - $ctype, - $attachment['name'], - ($attachment['data'] ? false : true), - ($ctype == 'message/rfc822' ? '8bit' : 'base64'), - 'attachment', - '', '', '', - $CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL, - $CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL, - '', RCUBE_CHARSET - ); + if ($attachment['data']) + $MAIL_MIME->addHTMLImage($attachment['data'], $attachment['mimetype'], $attachment['name'], false, $cid); + else + $MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name'], true, $cid); + } + else { + $ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914 + $file = $attachment['data'] ? $attachment['data'] : $attachment['path']; + $folding = (int) $RCMAIL->config->get('mime_param_folding'); + + $MAIL_MIME->addAttachment($file, + $ctype, + $attachment['name'], + $attachment['data'] ? false : true, + $ctype == 'message/rfc822' ? '8bit' : 'base64', + 'attachment', + '', '', '', + $folding ? 'quoted-printable' : NULL, + $folding == 2 ? 'quoted-printable' : NULL, + '', RCUBE_CHARSET + ); + } } - } } // choose transfer encoding for plain/text body if (preg_match('/[^\x00-\x7F]/', $MAIL_MIME->getTXTBody())) { - $text_charset = $message_charset; - $transfer_encoding = $RCMAIL->config->get('force_7bit') ? 'quoted-printable' : '8bit'; + $text_charset = $message_charset; + $transfer_encoding = $RCMAIL->config->get('force_7bit') ? 'quoted-printable' : '8bit'; } else { - $text_charset = ''; - $transfer_encoding = '7bit'; + $text_charset = ''; + $transfer_encoding = '7bit'; } if ($flowed) { - if (!$text_charset) { - $text_charset = 'US-ASCII'; - } + if (!$text_charset) { + $text_charset = 'US-ASCII'; + } - $text_charset .= ";\r\n format=flowed"; + $text_charset .= ";\r\n format=flowed"; } // encoding settings for mail composing @@ -697,184 +489,425 @@ $MAIL_MIME->setParam('text_charset', $text_charset); // encoding subject header with mb_encode provides better results with asian characters if (function_exists('mb_encode_mimeheader')) { - mb_internal_encoding($message_charset); - $headers['Subject'] = mb_encode_mimeheader($headers['Subject'], - $message_charset, 'Q', "\r\n", 8); - mb_internal_encoding(RCUBE_CHARSET); + mb_internal_encoding($message_charset); + $headers['Subject'] = mb_encode_mimeheader($headers['Subject'], + $message_charset, 'Q', "\r\n", 8); + mb_internal_encoding(RCUBE_CHARSET); } // pass headers to message object $MAIL_MIME->headers($headers); // Begin SMTP Delivery Block -if (!$savedraft) -{ - // check 'From' address (identity may be incomplete) - if (empty($from)) { - $OUTPUT->show_message('nofromaddress', 'error'); - $OUTPUT->send('iframe'); - } - - // Handle Delivery Status Notification request - if (!empty($_POST['_dsn'])) { - $smtp_opts['dsn'] = true; - } - - $sent = $RCMAIL->deliver_message($MAIL_MIME, $from, $mailto, - $smtp_error, $mailbody_file, $smtp_opts); +if (!$savedraft) { + // check 'From' address (identity may be incomplete) + if (empty($from)) { + $OUTPUT->show_message('nofromaddress', 'error'); + $OUTPUT->send('iframe'); + } - // return to compose page if sending failed - if (!$sent) { - // remove temp file - if ($mailbody_file) { - unlink($mailbody_file); + // Handle Delivery Status Notification request + if (!empty($_POST['_dsn'])) { + $smtp_opts['dsn'] = true; } - if ($smtp_error) - $OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']); - else - $OUTPUT->show_message('sendingfailed', 'error'); - $OUTPUT->send('iframe'); - } + $sent = $RCMAIL->deliver_message($MAIL_MIME, $from, $mailto, + $smtp_error, $mailbody_file, $smtp_opts); - // save message sent time - if (!empty($CONFIG['sendmail_delay'])) - $RCMAIL->user->save_prefs(array('last_message_time' => time())); + // return to compose page if sending failed + if (!$sent) { + // remove temp file + if ($mailbody_file) { + unlink($mailbody_file); + } - // set replied/forwarded flag - if ($COMPOSE['reply_uid']) - $RCMAIL->storage->set_flag($COMPOSE['reply_uid'], 'ANSWERED', $COMPOSE['mailbox']); - else if ($COMPOSE['forward_uid']) - $RCMAIL->storage->set_flag($COMPOSE['forward_uid'], 'FORWARDED', $COMPOSE['mailbox']); + if ($smtp_error) + $OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']); + else + $OUTPUT->show_message('sendingfailed', 'error'); + $OUTPUT->send('iframe'); + } -} // End of SMTP Delivery Block + // save message sent time + if ($sendmail_delay) { + $RCMAIL->user->save_prefs(array('last_message_time' => time())); + } + // set replied/forwarded flag + if ($COMPOSE['reply_uid']) + $RCMAIL->storage->set_flag($COMPOSE['reply_uid'], 'ANSWERED', $COMPOSE['mailbox']); + else if ($COMPOSE['forward_uid']) + $RCMAIL->storage->set_flag($COMPOSE['forward_uid'], 'FORWARDED', $COMPOSE['mailbox']); +} // Determine which folder to save message -if ($savedraft) - $store_target = $CONFIG['drafts_mbox']; -else if (!$RCMAIL->config->get('no_save_sent_messages')) - $store_target = isset($_POST['_store_target']) ? rcube_utils::get_input_value('_store_target', rcube_utils::INPUT_POST) : $CONFIG['sent_mbox']; +if ($savedraft) { + $store_target = $drafts_mbox; +} +else if (!$RCMAIL->config->get('no_save_sent_messages')) { + $store_target = rcube_utils::get_input_value('_store_target', rcube_utils::INPUT_POST); + if (!strlen($store_target)) { + $sore_target = $RCMAIL->config->get('sent_mbox'); + } +} if ($store_target) { - // check if folder is subscribed - if ($RCMAIL->storage->folder_exists($store_target, true)) - $store_folder = true; - // folder may be existing but not subscribed (#1485241) - else if (!$RCMAIL->storage->folder_exists($store_target)) - $store_folder = $RCMAIL->storage->create_folder($store_target, true); - else if ($RCMAIL->storage->subscribe($store_target)) - $store_folder = true; - - // append message to sent box - if ($store_folder) { - // message body in file - if ($mailbody_file || $MAIL_MIME->getParam('delay_file_io')) { - $headers = $MAIL_MIME->txtHeaders(); - - // file already created - if ($mailbody_file) - $msg = $mailbody_file; - else { - $temp_dir = $RCMAIL->config->get('temp_dir'); - $mailbody_file = tempnam($temp_dir, 'rcmMsg'); - if (!PEAR::isError($msg = $MAIL_MIME->saveMessageBody($mailbody_file))) - $msg = $mailbody_file; - } + // check if folder is subscribed + if ($RCMAIL->storage->folder_exists($store_target, true)) { + $store_folder = true; } - else { - $msg = $MAIL_MIME->getMessage(); - $headers = ''; + // folder may be existing but not subscribed (#1485241) + else if (!$RCMAIL->storage->folder_exists($store_target)) { + $store_folder = $RCMAIL->storage->create_folder($store_target, true); } - - if (PEAR::isError($msg)) - rcube::raise_error(array('code' => 650, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not create message: ".$msg->getMessage()), - TRUE, FALSE); - else { - $saved = $RCMAIL->storage->save_message($store_target, $msg, $headers, - $mailbody_file ? true : false, array('SEEN')); + else if ($RCMAIL->storage->subscribe($store_target)) { + $store_folder = true; } - if ($mailbody_file) { - unlink($mailbody_file); - $mailbody_file = null; - } - } + // append message to sent box + if ($store_folder) { + // message body in file + if ($mailbody_file || $MAIL_MIME->getParam('delay_file_io')) { + $headers = $MAIL_MIME->txtHeaders(); + + // file already created + if ($mailbody_file) { + $msg = $mailbody_file; + } + else { + $temp_dir = $RCMAIL->config->get('temp_dir'); + $mailbody_file = tempnam($temp_dir, 'rcmMsg'); + + if (!PEAR::isError($msg = $MAIL_MIME->saveMessageBody($mailbody_file))) { + $msg = $mailbody_file; + } + } + } + else { + $msg = $MAIL_MIME->getMessage(); + $headers = ''; + } - // raise error if saving failed - if (!$saved) { - rcube::raise_error(array('code' => 800, 'type' => 'imap', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not save message in $store_target"), TRUE, FALSE); + if (PEAR::isError($msg)) { + rcube::raise_error(array('code' => 650, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not create message: ".$msg->getMessage()), + true, false); + } + else { + $saved = $RCMAIL->storage->save_message($store_target, $msg, $headers, + $mailbody_file ? true : false, array('SEEN')); + } - if ($savedraft) { - $OUTPUT->show_message('errorsaving', 'error'); - // start the auto-save timer again - $OUTPUT->command('auto_save_start'); - $OUTPUT->send('iframe'); + if ($mailbody_file) { + unlink($mailbody_file); + $mailbody_file = null; + } } - } - if ($saved && ($old_id = rcube_utils::get_input_value('_draft_saveid', rcube_utils::INPUT_POST))) { - // delete previous saved draft - $deleted = $RCMAIL->storage->delete_message($old_id, $CONFIG['drafts_mbox']); + // raise error if saving failed + if (!$saved) { + rcube::raise_error(array('code' => 800, 'type' => 'imap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not save message in $store_target"), true, false); + + if ($savedraft) { + $OUTPUT->show_message('errorsaving', 'error'); + // start the auto-save timer again + $OUTPUT->command('auto_save_start'); + $OUTPUT->send('iframe'); + } + } - // raise error if deletion of old draft failed - if (!$deleted) - rcube::raise_error(array('code' => 800, 'type' => 'imap', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not delete message from ".$CONFIG['drafts_mbox']), TRUE, FALSE); - } + // delete previous saved draft + if ($saved && ($old_id = rcube_utils::get_input_value('_draft_saveid', rcube_utils::INPUT_POST))) { + $deleted = $RCMAIL->storage->delete_message($old_id, $drafts_mbox); + + // raise error if deletion of old draft failed + if (!$deleted) { + rcube::raise_error(array('code' => 800, 'type' => 'imap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not delete message from $drafts_mbox"), true, false); + } + } } // remove temp file else if ($mailbody_file) { - unlink($mailbody_file); + unlink($mailbody_file); } if ($savedraft) { - // remember new draft-uid ($saved could be an UID or true/false here) - if ($saved && is_bool($saved)) { - $index = $RCMAIL->storage->search_once($CONFIG['drafts_mbox'], 'HEADER Message-ID ' . $message_id); - $saved = @max($index->get()); - } + // remember new draft-uid ($saved could be an UID or true/false here) + if ($saved && is_bool($saved)) { + $index = $RCMAIL->storage->search_once($drafts_mbox, 'HEADER Message-ID ' . $message_id); + $saved = @max($index->get()); + } - if ($saved) { - $plugin = $RCMAIL->plugins->exec_hook('message_draftsaved', - array('msgid' => $message_id, 'uid' => $saved, 'folder' => $store_target)); + if ($saved) { + $plugin = $RCMAIL->plugins->exec_hook('message_draftsaved', + array('msgid' => $message_id, 'uid' => $saved, 'folder' => $store_target)); - // display success - $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'messagesaved', 'confirmation'); + // display success + $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'messagesaved', 'confirmation'); - // update "_draft_saveid" and the "cmp_hash" to prevent "Unsaved changes" warning - $COMPOSE['param']['draft_uid'] = $plugin['uid']; - $OUTPUT->command('set_draft_id', $plugin['uid']); - $OUTPUT->command('compose_field_hash', true); - } + // update "_draft_saveid" and the "cmp_hash" to prevent "Unsaved changes" warning + $COMPOSE['param']['draft_uid'] = $plugin['uid']; + $OUTPUT->command('set_draft_id', $plugin['uid']); + $OUTPUT->command('compose_field_hash', true); + } - // start the auto-save timer again - $OUTPUT->command('auto_save_start'); + // start the auto-save timer again + $OUTPUT->command('auto_save_start'); } else { - $folders = array(); + $folders = array(); - if ($COMPOSE['mode'] == 'reply' || $COMPOSE['mode'] == 'forward') - $folders[] = $COMPOSE['mailbox']; + if ($COMPOSE['mode'] == 'reply' || $COMPOSE['mode'] == 'forward') { + $folders[] = $COMPOSE['mailbox']; + } - rcmail_compose_cleanup($COMPOSE_ID); - $OUTPUT->command('remove_compose_data', $COMPOSE_ID); + rcmail_compose_cleanup($COMPOSE_ID); + $OUTPUT->command('remove_compose_data', $COMPOSE_ID); - if ($store_folder && !$saved) - $OUTPUT->command('sent_successfully', 'error', $RCMAIL->gettext('errorsavingsent'), $folders); - else { - if ($store_folder) { - $folders[] = $store_target; + if ($store_folder && !$saved) { + $OUTPUT->command('sent_successfully', 'error', $RCMAIL->gettext('errorsavingsent'), $folders); + } + else if ($store_folder) { + $folders[] = $store_target; } $OUTPUT->command('sent_successfully', 'confirmation', $RCMAIL->gettext('messagesent'), $folders); - } } $OUTPUT->send('iframe'); + + +/****** message sending functions ********/ + +// encrypt parts of the header +function rcmail_encrypt_header($what) +{ + global $RCMAIL; + + if (!$RCMAIL->config->get('http_received_header_encrypt')) { + return $what; + } + + return $RCMAIL->encrypt($what); +} + +// get identity record +function rcmail_get_identity($id) +{ + global $RCMAIL, $message_charset; + + if ($sql_arr = $RCMAIL->user->get_identity($id)) { + $out = $sql_arr; + + if ($message_charset != RCUBE_CHARSET) { + foreach ($out as $k => $v) { + $out[$k] = rcube_charset::convert($v, RCUBE_CHARSET, $message_charset); + } + } + + $out['mailto'] = $sql_arr['email']; + $out['string'] = format_email_recipient($sql_arr['email'], $sql_arr['name']); + + return $out; + } + + return false; +} + +/** + * go from this: + * <img src="http[s]://.../tiny_mce/plugins/emotions/images/smiley-cool.gif" border="0" alt="Cool" title="Cool" /> + * + * to this: + * + * <img src="/path/on/server/.../tiny_mce/plugins/emotions/images/smiley-cool.gif" border="0" alt="Cool" title="Cool" /> + */ +function rcmail_fix_emoticon_paths($mime_message) +{ + global $RCMAIL; + + $body = $mime_message->getHTMLBody(); + + // remove any null-byte characters before parsing + $body = preg_replace('/\x00/', '', $body); + + $searchstr = 'program/js/tiny_mce/plugins/emotions/img/'; + $offset = 0; + + // keep track of added images, so they're only added once + $included_images = array(); + + if (preg_match_all('# src=[\'"]([^\'"]+)#', $body, $matches, PREG_OFFSET_CAPTURE)) { + foreach ($matches[1] as $m) { + // find emoticon image tags + if (preg_match('#'.$searchstr.'(.*)$#', $m[0], $imatches)) { + $image_name = $imatches[1]; + + // sanitize image name so resulting attachment doesn't leave images dir + $image_name = preg_replace('/[^a-zA-Z0-9_\.\-]/i', '', $image_name); + $img_file = INSTALL_PATH . '/' . $searchstr . $image_name; + + if (! in_array($image_name, $included_images)) { + // add the image to the MIME message + if (!$mime_message->addHTMLImage($img_file, 'image/gif', '', true, $image_name)) { + $RCMAIL->output->show_message("emoticonerror", 'error'); + } + + array_push($included_images, $image_name); + } + + $body = substr_replace($body, $img_file, $m[1] + $offset, strlen($m[0])); + $offset += strlen($img_file) - strlen($m[0]); + } + } + } + + $mime_message->setHTMLBody($body); +} + +/** + * Extract image attachments from HTML content (data URIs) + */ +function rcmail_extract_inline_images($mime_message, $from) +{ + $body = $mime_message->getHTMLBody(); + $offset = 0; + $list = array(); + $regexp = '# src=[\'"](data:(image/[a-z]+);base64,([a-z0-9+/=\r\n]+))([\'"])#i'; + + // get domain for the Content-ID, must be the same as in Mail_Mime::get() + if (preg_match('#@([0-9a-zA-Z\-\.]+)#', $from, $matches)) { + $domain = $matches[1]; + } else { + $domain = 'localhost'; + } + + if (preg_match_all($regexp, $body, $matches, PREG_OFFSET_CAPTURE)) { + foreach ($matches[1] as $idx => $m) { + $data = preg_replace('/\r\n/', '', $matches[3][$idx][0]); + $data = base64_decode($data); + + if (empty($data)) { + continue; + } + + $hash = md5($data) . '@' . $domain; + $mime_type = $matches[2][$idx][0]; + $name = $list[$hash]; + + // add the image to the MIME message + if (!$name) { + $ext = preg_replace('#^[^/]+/#', '', $mime_type); + $name = substr($hash, 0, 8) . '.' . $ext; + $list[$hash] = $name; + + $mime_message->addHTMLImage($data, $mime_type, $name, false, $hash); + } + + $body = substr_replace($body, $name, $m[1] + $offset, strlen($m[0])); + $offset += strlen($name) - strlen($m[0]); + } + } + + $mime_message->setHTMLBody($body); +} + +/** + * Parse and cleanup email address input (and count addresses) + * + * @param string Address input + * @param boolean Do count recipients (saved in global $RECIPIENT_COUNT) + * @param boolean Validate addresses (errors saved in global $EMAIL_FORMAT_ERROR) + * @return string Canonical recipients string separated by comma + */ +function rcmail_email_input_format($mailto, $count=false, $check=true) +{ + global $RCMAIL, $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT; + + // simplified email regexp, supporting quoted local part + $email_regexp = '(\S+|("[^"]+"))@\S+'; + + $delim = trim($RCMAIL->config->get('recipients_separator', ',')); + $regexp = array("/[,;$delim]\s*[\r\n]+/", '/[\r\n]+/', "/[,;$delim]\s*\$/m", '/;/', '/(\S{1})(<'.$email_regexp.'>)/U'); + $replace = array($delim.' ', ', ', '', $delim, '\\1 \\2'); + + // replace new lines and strip ending ', ', make address input more valid + $mailto = trim(preg_replace($regexp, $replace, $mailto)); + $items = rcube_utils::explode_quoted_string($delim, $mailto); + $result = array(); + + foreach ($items as $item) { + $item = trim($item); + // address in brackets without name (do nothing) + if (preg_match('/^<'.$email_regexp.'>$/', $item)) { + $item = rcube_utils::idn_to_ascii(trim($item, '<>')); + $result[] = $item; + } + // address without brackets and without name (add brackets) + else if (preg_match('/^'.$email_regexp.'$/', $item)) { + $item = rcube_utils::idn_to_ascii($item); + $result[] = $item; + } + // address with name (handle name) + else if (preg_match('/<*'.$email_regexp.'>*$/', $item, $matches)) { + $address = $matches[0]; + $name = trim(str_replace($address, '', $item)); + if ($name[0] == '"' && $name[count($name)-1] == '"') { + $name = substr($name, 1, -1); + } + $name = stripcslashes($name); + $address = rcube_utils::idn_to_ascii(trim($address, '<>')); + $result[] = format_email_recipient($address, $name); + $item = $address; + } + else if (trim($item)) { + continue; + } + + // check address format + $item = trim($item, '<>'); + if ($item && $check && !rcube_utils::check_email($item)) { + $EMAIL_FORMAT_ERROR = $item; + return; + } + } + + if ($count) { + $RECIPIENT_COUNT += count($result); + } + + return implode(', ', $result); +} + + +function rcmail_generic_message_footer($isHtml) +{ + global $RCMAIL; + + if ($isHtml && ($file = $RCMAIL->config->get('generic_message_footer_html'))) { + $html_footer = true; + } + else { + $file = $RCMAIL->config->get('generic_message_footer'); + $html_footer = false; + } + + if ($file && realpath($file)) { + // sanity check + if (!preg_match('/\.(php|ini|conf)$/', $file) && strpos($file, '/etc/') === false) { + $footer = file_get_contents($file); + if ($isHtml && !$html_footer) { + $footer = '<pre>' . $footer . '</pre>'; + } + return $footer; + } + } + + return false; +} diff --git a/program/steps/mail/sendmdn.inc b/program/steps/mail/sendmdn.inc index 7cc152a2b..727e75bb9 100644 --- a/program/steps/mail/sendmdn.inc +++ b/program/steps/mail/sendmdn.inc @@ -5,7 +5,7 @@ | program/steps/mail/sendmdn.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2008-2009, The Roundcube Dev Team | + | Copyright (C) 2008-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -20,23 +20,24 @@ */ // only process ajax requests -if (!$OUTPUT->ajax_call) - return; +if (!$OUTPUT->ajax_call) { + return; +} if (!empty($_POST['_uid'])) { - $sent = rcmail_send_mdn(rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST), $smtp_error); + $sent = rcmail_send_mdn(rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST), $smtp_error); } // show either confirm or error message if ($sent) { - $OUTPUT->set_env('mdn_request', false); - $OUTPUT->show_message('receiptsent', 'confirmation'); + $OUTPUT->set_env('mdn_request', false); + $OUTPUT->show_message('receiptsent', 'confirmation'); } else if ($smtp_error) { - $OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']); + $OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']); } else { - $OUTPUT->show_message('errorsendingreceipt', 'error'); + $OUTPUT->show_message('errorsendingreceipt', 'error'); } $OUTPUT->send(); diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc index 6382e49fe..9498d1dc5 100644 --- a/program/steps/mail/show.inc +++ b/program/steps/mail/show.inc @@ -5,7 +5,7 @@ | program/steps/mail/show.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -23,12 +23,12 @@ $PRINT_MODE = $RCMAIL->action == 'print' ? TRUE : FALSE; // Read browser capabilities and store them in session if ($caps = rcube_utils::get_input_value('_caps', rcube_utils::INPUT_GET)) { - $browser_caps = array(); - foreach (explode(',', $caps) as $cap) { - $cap = explode('=', $cap); - $browser_caps[$cap[0]] = $cap[1]; - } - $_SESSION['browser_caps'] = $browser_caps; + $browser_caps = array(); + foreach (explode(',', $caps) as $cap) { + $cap = explode('=', $cap); + $browser_caps[$cap[0]] = $cap[1]; + } + $_SESSION['browser_caps'] = $browser_caps; } $uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET); @@ -36,298 +36,319 @@ $mbox_name = $RCMAIL->storage->get_folder(); // similar code as in program/steps/mail/get.inc if ($uid) { - // set message format (need to be done before rcube_message construction) - if (!empty($_GET['_format'])) { - $prefer_html = $_GET['_format'] == 'html'; - $RCMAIL->config->set('prefer_html', $prefer_html); - $_SESSION['msg_formats'][$mbox_name.':'.$uid] = $prefer_html; - } - else if (isset($_SESSION['msg_formats'][$mbox_name.':'.$uid])) { - $RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$uid]); - } - - $MESSAGE = new rcube_message($uid); - - // if message not found (wrong UID)... - if (empty($MESSAGE->headers)) { - rcmail_message_error($uid); - } - - - // show images? - rcmail_check_safe($MESSAGE); - - // set message charset as default - if (!empty($MESSAGE->headers->charset)) - $RCMAIL->storage->set_charset($MESSAGE->headers->charset); - - $OUTPUT->set_pagetitle(abbreviate_string($MESSAGE->subject, 128, '...', true)); - - // give message uid to the client - $OUTPUT->set_env('uid', $MESSAGE->uid); - // set environement - $OUTPUT->set_env('safemode', $MESSAGE->is_safe); - $OUTPUT->set_env('sender', $MESSAGE->sender['string']); - $OUTPUT->set_env('permaurl', $RCMAIL->url(array('_action' => 'show', '_uid' => $MESSAGE->uid, '_mbox' => $mbox_name))); - $OUTPUT->set_env('delimiter', $RCMAIL->storage->get_hierarchy_delimiter()); - $OUTPUT->set_env('mailbox', $mbox_name); - $OUTPUT->set_env('compose_extwin', $RCMAIL->config->get('compose_extwin',false)); - - // mimetypes supported by the browser (default settings) - $mimetypes = (array)$RCMAIL->config->get('client_mimetypes'); - - // Remove unsupported types, which makes that attachment which cannot be - // displayed in a browser will be downloaded directly without displaying an overlay page - if (empty($_SESSION['browser_caps']['pdf']) && ($key = array_search('application/pdf', $mimetypes)) !== false) { - unset($mimetypes[$key]); - } - if (empty($_SESSION['browser_caps']['flash']) && ($key = array_search('application/x-shockwave-flash', $mimetypes)) !== false) { - unset($mimetypes[$key]); - } - if (empty($_SESSION['browser_caps']['tif']) && ($key = array_search('image/tiff', $mimetypes)) !== false) { - // we can convert tiff to jpeg - if (!$RCMAIL->config->get('im_convert_path')) { - unset($mimetypes[$key]); + // set message format (need to be done before rcube_message construction) + if (!empty($_GET['_format'])) { + $prefer_html = $_GET['_format'] == 'html'; + $RCMAIL->config->set('prefer_html', $prefer_html); + $_SESSION['msg_formats'][$mbox_name.':'.$uid] = $prefer_html; } - } - - $OUTPUT->set_env('mimetypes', array_values($mimetypes)); - - if ($CONFIG['drafts_mbox']) - $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']); - if ($CONFIG['trash_mbox']) - $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']); - if ($CONFIG['junk_mbox']) - $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']); - if ($CONFIG['delete_junk']) - $OUTPUT->set_env('delete_junk', true); - if ($CONFIG['flag_for_deletion']) - $OUTPUT->set_env('flag_for_deletion', true); - if ($CONFIG['read_when_deleted']) - $OUTPUT->set_env('read_when_deleted', true); - if ($CONFIG['skip_deleted']) - $OUTPUT->set_env('skip_deleted', true); - if ($CONFIG['display_next']) - $OUTPUT->set_env('display_next', true); - if ($MESSAGE->headers->get('list-post', false)) - $OUTPUT->set_env('list_post', true); - if ($CONFIG['forward_attachment']) - $OUTPUT->set_env('forward_attachment', true); - - if (!$OUTPUT->ajax_call) - $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', - 'movingmessage', 'deletingmessage', 'markingmessage', 'replyall', 'replylist'); - - $prefer_html = $RCMAIL->config->get('prefer_html'); - if ($MESSAGE->has_html_part()) { - $OUTPUT->set_env('optional_format', $prefer_html ? 'text' : 'html'); - } - - // check for unset disposition notification - if ($MESSAGE->headers->mdn_to - && empty($MESSAGE->headers->flags['MDNSENT']) - && empty($MESSAGE->headers->flags['SEEN']) - && ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*')) - && $mbox_name != $CONFIG['drafts_mbox'] - && $mbox_name != $CONFIG['sent_mbox'] - ) { - $mdn_cfg = intval($CONFIG['mdn_requests']); - - if ($mdn_cfg == 1 || (($mdn_cfg == 3 || $mdn_cfg == 4) && rcmail_contact_exists($MESSAGE->sender['mailto']))) { - // Send MDN - if (rcmail_send_mdn($MESSAGE, $smtp_error)) - $OUTPUT->show_message('receiptsent', 'confirmation'); - else if ($smtp_error) - $OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']); - else - $OUTPUT->show_message('errorsendingreceipt', 'error'); + else if (isset($_SESSION['msg_formats'][$mbox_name.':'.$uid])) { + $RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$uid]); } - else if ($mdn_cfg != 2 && $mdn_cfg != 4) { - // Ask user - $OUTPUT->add_label('mdnrequest'); - $OUTPUT->set_env('mdn_request', true); + + $MESSAGE = new rcube_message($uid); + + // if message not found (wrong UID)... + if (empty($MESSAGE->headers)) { + rcmail_message_error($uid); } - } - - if (empty($MESSAGE->headers->flags['SEEN']) - && ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($CONFIG['preview_pane_mark_read']) == 0)) - ) { - $RCMAIL->plugins->exec_hook('message_read', array('uid' => $MESSAGE->uid, - 'mailbox' => $mbox_name, 'message' => $MESSAGE)); - } -} + // show images? + rcmail_check_safe($MESSAGE); -function rcmail_message_attachments($attrib) -{ - global $PRINT_MODE, $MESSAGE, $RCMAIL; - - $out = $ol = ''; - $attachments = array(); - - if (sizeof($MESSAGE->attachments)) { - foreach ($MESSAGE->attachments as $attach_prop) { - $filename = rcmail_attachment_name($attach_prop, true); - - if ($PRINT_MODE) { - $size = $RCMAIL->message_part_size($attach_prop); - $ol .= html::tag('li', null, rcube::Q(sprintf("%s (%s)", $filename, $size))); - } - else { - if ($attrib['maxlength'] && mb_strlen($filename) > $attrib['maxlength']) { - $title = $filename; - $filename = abbreviate_string($filename, $attrib['maxlength']); + // set message charset as default + if (!empty($MESSAGE->headers->charset)) { + $RCMAIL->storage->set_charset($MESSAGE->headers->charset); + } + + $OUTPUT->set_pagetitle(abbreviate_string($MESSAGE->subject, 128, '...', true)); + + // set message environment + $OUTPUT->set_env('uid', $MESSAGE->uid); + $OUTPUT->set_env('safemode', $MESSAGE->is_safe); + $OUTPUT->set_env('sender', $MESSAGE->sender['string']); + $OUTPUT->set_env('mailbox', $mbox_name); + $OUTPUT->set_env('permaurl', $RCMAIL->url(array('_action' => 'show', '_uid' => $MESSAGE->uid, '_mbox' => $mbox_name))); + + if ($MESSAGE->headers->get('list-post', false)) { + $OUTPUT->set_env('list_post', true); + } + + // set environment + $OUTPUT->set_env('delimiter', $RCMAIL->storage->get_hierarchy_delimiter()); + + // set configuration + $RCMAIL->set_env_config(array('delete_junk', 'flag_for_deletion', 'read_when_deleted', + 'skip_deleted', 'display_next', 'compose_extwin', 'forward_attachment')); + + // set special folders + foreach (array('drafts', 'trash', 'junk') as $mbox) { + if ($folder = $RCMAIL->config->get($mbox . '_mbox')) { + $OUTPUT->set_env($mbox . '_mailbox', $folder); } - else { - $title = ''; + } + + // mimetypes supported by the browser (default settings) + $mimetypes = (array)$RCMAIL->config->get('client_mimetypes'); + + // Remove unsupported types, which makes that attachment which cannot be + // displayed in a browser will be downloaded directly without displaying an overlay page + if (empty($_SESSION['browser_caps']['pdf']) && ($key = array_search('application/pdf', $mimetypes)) !== false) { + unset($mimetypes[$key]); + } + if (empty($_SESSION['browser_caps']['flash']) && ($key = array_search('application/x-shockwave-flash', $mimetypes)) !== false) { + unset($mimetypes[$key]); + } + if (empty($_SESSION['browser_caps']['tif']) && ($key = array_search('image/tiff', $mimetypes)) !== false) { + // we can convert tiff to jpeg + if (!$RCMAIL->config->get('im_convert_path')) { + unset($mimetypes[$key]); } + } - $mimetype = rcmail_fix_mimetype($attach_prop->mimetype); - $class = rcube_utils::file2class($mimetype, $filename); - $id = 'attach' . $attach_prop->mime_id; - $link = html::a(array( - 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), - 'onclick' => sprintf('return %s.command(\'load-attachment\',\'%s\',this)', - rcmail_output::JS_OBJECT_NAME, $attach_prop->mime_id), - 'onmouseover' => $title ? '' : 'rcube_webmail.long_subject_title_ex(this, 0)', - 'title' => rcube::Q($title), - ), rcube::Q($filename)); - $ol .= html::tag('li', array('class' => $class, 'id' => $id), $link); - - $attachments[$attach_prop->mime_id] = $mimetype; - } + $OUTPUT->set_env('mimetypes', array_values($mimetypes)); + + if ($MESSAGE->has_html_part()) { + $prefer_html = $RCMAIL->config->get('prefer_html'); + $OUTPUT->set_env('optional_format', $prefer_html ? 'text' : 'html'); + } + + if (!$OUTPUT->ajax_call) { + $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', + 'movingmessage', 'deletingmessage', 'markingmessage', 'replyall', 'replylist'); } - $out = html::tag('ul', $attrib, $ol, html::$common_attrib); - $RCMAIL->output->set_env('attachments', $attachments); - } + // check for unset disposition notification + if ($MESSAGE->headers->mdn_to + && empty($MESSAGE->headers->flags['MDNSENT']) + && empty($MESSAGE->headers->flags['SEEN']) + && ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*')) + && $mbox_name != $RCMAIL->config->get('drafts_mbox') + && $mbox_name != $RCMAIL->config->get('sent_mbox') + ) { + $mdn_cfg = intval($RCMAIL->config->get('mdn_requests')); + + if ($mdn_cfg == 1 || (($mdn_cfg == 3 || $mdn_cfg == 4) && rcmail_contact_exists($MESSAGE->sender['mailto']))) { + // Send MDN + if (rcmail_send_mdn($MESSAGE, $smtp_error)) + $OUTPUT->show_message('receiptsent', 'confirmation'); + else if ($smtp_error) + $OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']); + else + $OUTPUT->show_message('errorsendingreceipt', 'error'); + } + else if ($mdn_cfg != 2 && $mdn_cfg != 4) { + // Ask user + $OUTPUT->add_label('mdnrequest'); + $OUTPUT->set_env('mdn_request', true); + } + } - return $out; + if (empty($MESSAGE->headers->flags['SEEN']) + && ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($RCMAIL->config->get('preview_pane_mark_read')) == 0)) + ) { + $RCMAIL->plugins->exec_hook('message_read', array( + 'uid' => $MESSAGE->uid, + 'mailbox' => $mbox_name, + 'message' => $MESSAGE, + )); + } } -function rcmail_remote_objects_msg() + +$OUTPUT->add_handlers(array( + 'messageattachments' => 'rcmail_message_attachments', + 'mailboxname' => 'rcmail_mailbox_name_display', + 'messageobjects' => 'rcmail_message_objects', + 'contactphoto' => 'rcmail_message_contactphoto', +)); + + +if ($RCMAIL->action == 'print' && $OUTPUT->template_exists('messageprint')) + $OUTPUT->send('messageprint', false); +else if ($RCMAIL->action == 'preview' && $OUTPUT->template_exists('messagepreview')) + $OUTPUT->send('messagepreview', false); +else + $OUTPUT->send('message', false); + + +// mark message as read +if ($MESSAGE && $MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN']) && + ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($RCMAIL->config->get('preview_pane_mark_read')) == 0)) +) { + if ($RCMAIL->storage->set_flag($MESSAGE->uid, 'SEEN')) { + if ($count = rcmail_get_unseen_count($mbox_name)) { + rcmail_set_unseen_count($mbox_name, $count - 1); + } + } +} + +exit; + + + +function rcmail_message_attachments($attrib) { - global $MESSAGE, $RCMAIL; + global $PRINT_MODE, $MESSAGE, $RCMAIL; + + $out = $ol = ''; + $attachments = array(); + + if (sizeof($MESSAGE->attachments)) { + foreach ($MESSAGE->attachments as $attach_prop) { + $filename = rcmail_attachment_name($attach_prop, true); + + if ($PRINT_MODE) { + $size = $RCMAIL->message_part_size($attach_prop); + $ol .= html::tag('li', null, rcube::Q(sprintf("%s (%s)", $filename, $size))); + } + else { + if ($attrib['maxlength'] && mb_strlen($filename) > $attrib['maxlength']) { + $title = $filename; + $filename = abbreviate_string($filename, $attrib['maxlength']); + } + else { + $title = ''; + } + + $mimetype = rcmail_fix_mimetype($attach_prop->mimetype); + $class = rcube_utils::file2class($mimetype, $filename); + $id = 'attach' . $attach_prop->mime_id; + $link = html::a(array( + 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), + 'onclick' => sprintf('return %s.command(\'load-attachment\',\'%s\',this)', + rcmail_output::JS_OBJECT_NAME, $attach_prop->mime_id), + 'onmouseover' => $title ? '' : 'rcube_webmail.long_subject_title_ex(this, 0)', + 'title' => rcube::Q($title), + ), rcube::Q($filename)); + + $ol .= html::tag('li', array('class' => $class, 'id' => $id), $link); + + $attachments[$attach_prop->mime_id] = $mimetype; + } + } - $attrib['id'] = 'remote-objects-message'; - $attrib['class'] = 'notice'; - $attrib['style'] = 'display: none'; + $out = html::tag('ul', $attrib, $ol, html::$common_attrib); - $msg = rcube::Q($RCMAIL->gettext('blockedimages')) . ' '; - $msg .= html::a(array('href' => "#loadimages", 'onclick' => rcmail_output::JS_OBJECT_NAME.".command('load-images')"), rcube::Q($RCMAIL->gettext('showimages'))); + $RCMAIL->output->set_env('attachments', $attachments); + } + + return $out; +} + +function rcmail_remote_objects_msg() +{ + global $MESSAGE, $RCMAIL; + + $attrib['id'] = 'remote-objects-message'; + $attrib['class'] = 'notice'; + $attrib['style'] = 'display: none'; + + $msg = rcube::Q($RCMAIL->gettext('blockedimages')) . ' '; + $msg .= html::a(array( + 'href' => "#loadimages", + 'onclick' => rcmail_output::JS_OBJECT_NAME.".command('load-images')" + ), + rcube::Q($RCMAIL->gettext('showimages'))); + + // add link to save sender in addressbook and reload message + if ($MESSAGE->sender['mailto'] && $RCMAIL->config->get('show_images') == 1) { + $msg .= ' ' . html::a(array( + 'href' => "#alwaysload", + 'onclick' => rcmail_output::JS_OBJECT_NAME.".command('always-load')", + 'style' => "white-space:nowrap" + ), + rcube::Q($RCMAIL->gettext(array('name' => 'alwaysshow', 'vars' => array('sender' => $MESSAGE->sender['mailto']))))); + } - // add link to save sender in addressbook and reload message - if ($MESSAGE->sender['mailto'] && $RCMAIL->config->get('show_images') == 1) { - $msg .= ' ' . html::a(array('href' => "#alwaysload", 'onclick' => rcmail_output::JS_OBJECT_NAME.".command('always-load')", 'style' => "white-space:nowrap"), - rcube::Q($RCMAIL->gettext(array('name' => 'alwaysshow', 'vars' => array('sender' => $MESSAGE->sender['mailto']))))); - } + $RCMAIL->output->add_gui_object('remoteobjectsmsg', $attrib['id']); - $RCMAIL->output->add_gui_object('remoteobjectsmsg', $attrib['id']); - return html::div($attrib, $msg); + return html::div($attrib, $msg); } function rcmail_message_buttons() { - global $RCMAIL; + global $RCMAIL; - $mbox = $RCMAIL->storage->get_folder(); - $delim = $RCMAIL->storage->get_hierarchy_delimiter(); - $dbox = $RCMAIL->config->get('drafts_mbox'); + $mbox = $RCMAIL->storage->get_folder(); + $delim = $RCMAIL->storage->get_hierarchy_delimiter(); + $dbox = $RCMAIL->config->get('drafts_mbox'); - // the message is not a draft - if ($mbox != $dbox && strpos($mbox, $dbox.$delim) !== 0) { - return ''; - } + // the message is not a draft + if ($mbox != $dbox && strpos($mbox, $dbox.$delim) !== 0) { + return ''; + } - $attrib['id'] = 'message-buttons'; - $attrib['class'] = 'notice'; + $attrib['id'] = 'message-buttons'; + $attrib['class'] = 'notice'; - $msg = rcube::Q($RCMAIL->gettext('isdraft')) . ' '; - $msg .= html::a(array('href' => "#edit", 'onclick' => rcmail_output::JS_OBJECT_NAME.".command('edit')"), rcube::Q($RCMAIL->gettext('edit'))); + $msg = rcube::Q($RCMAIL->gettext('isdraft')) . ' '; + $msg .= html::a(array( + 'href' => "#edit", + 'onclick' => rcmail_output::JS_OBJECT_NAME.".command('edit')" + ), + rcube::Q($RCMAIL->gettext('edit'))); - return html::div($attrib, $msg); + return html::div($attrib, $msg); } function rcmail_message_objects($attrib) { - global $RCMAIL, $MESSAGE; + global $RCMAIL, $MESSAGE; - if (!$attrib['id']) - $attrib['id'] = 'message-objects'; + if (!$attrib['id']) + $attrib['id'] = 'message-objects'; - $content = array( - rcmail_message_buttons(), - rcmail_remote_objects_msg(), - ); + $content = array( + rcmail_message_buttons(), + rcmail_remote_objects_msg(), + ); - $plugin = $RCMAIL->plugins->exec_hook('message_objects', - array('content' => $content, 'message' => $MESSAGE)); + $plugin = $RCMAIL->plugins->exec_hook('message_objects', + array('content' => $content, 'message' => $MESSAGE)); - $content = implode("\n", $plugin['content']); + $content = implode("\n", $plugin['content']); - return html::div($attrib, $content); + return html::div($attrib, $content); } function rcmail_contact_exists($email) { - global $RCMAIL; + global $RCMAIL; - if ($email) { - // @TODO: search in all address books? - $CONTACTS = $RCMAIL->get_address_book(-1, true); + if ($email) { + // @TODO: search in all address books? + $CONTACTS = $RCMAIL->get_address_book(-1, true); - if (is_object($CONTACTS)) { - $existing = $CONTACTS->search('email', $email, true, false); - if ($existing->count) { - return true; - } + if (is_object($CONTACTS)) { + $existing = $CONTACTS->search('email', $email, true, false); + if ($existing->count) { + return true; + } + } } - } - return false; + return false; } function rcmail_message_contactphoto($attrib) { - global $RCMAIL, $MESSAGE; + global $RCMAIL, $MESSAGE; - $placeholder = $attrib['placeholder'] ? $RCMAIL->config->get('skin_path') . $attrib['placeholder'] : null; - if ($MESSAGE->sender) - $photo_img = $RCMAIL->url(array('_task' => 'addressbook', '_action' => 'photo', '_email' => $MESSAGE->sender['mailto'], '_alt' => $placeholder)); - else - $photo_img = $placeholder ? $placeholder : 'program/resources/blank.gif'; + $placeholder = $attrib['placeholder'] ? $RCMAIL->config->get('skin_path') . $attrib['placeholder'] : null; - return html::img(array('src' => $photo_img) + $attrib); -} - - -$OUTPUT->add_handlers(array( - 'messageattachments' => 'rcmail_message_attachments', - 'mailboxname' => 'rcmail_mailbox_name_display', - 'messageobjects' => 'rcmail_message_objects', - 'contactphoto' => 'rcmail_message_contactphoto', -)); - - -if ($RCMAIL->action == 'print' && $OUTPUT->template_exists('messageprint')) - $OUTPUT->send('messageprint', false); -else if ($RCMAIL->action == 'preview' && $OUTPUT->template_exists('messagepreview')) - $OUTPUT->send('messagepreview', false); -else - $OUTPUT->send('message', false); - - -// mark message as read -if ($MESSAGE && $MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN']) && - ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($CONFIG['preview_pane_mark_read']) == 0))) -{ - if ($RCMAIL->storage->set_flag($MESSAGE->uid, 'SEEN')) { - if ($count = rcmail_get_unseen_count($mbox_name)) { - rcmail_set_unseen_count($mbox_name, $count - 1); + if ($MESSAGE->sender) { + $photo_img = $RCMAIL->url(array( + '_task' => 'addressbook', + '_action' => 'photo', + '_email' => $MESSAGE->sender['mailto'], + '_alt' => $placeholder + )); + } + else { + $photo_img = $placeholder ? $placeholder : 'program/resources/blank.gif'; } - } -} - -exit; + return html::img(array('src' => $photo_img) + $attrib); +} diff --git a/program/steps/mail/viewsource.inc b/program/steps/mail/viewsource.inc index 719239344..0328d9600 100644 --- a/program/steps/mail/viewsource.inc +++ b/program/steps/mail/viewsource.inc @@ -5,7 +5,7 @@ | program/steps/mail/viewsource.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -22,39 +22,39 @@ ob_end_clean(); // similar code as in program/steps/mail/get.inc -if ($uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET)) -{ - $headers = $RCMAIL->storage->get_message_headers($uid); - $charset = $headers->charset ? $headers->charset : $CONFIG['default_charset']; - header("Content-Type: text/plain; charset={$charset}"); - - if (!empty($_GET['_save'])) { - $subject = rcube_mime::decode_header($headers->subject, $headers->charset); - $filename = ($subject ? $subject : $RCMAIL->config->get('product_name', 'email')) . '.eml'; - $browser = $RCMAIL->output->browser; - - if ($browser->ie && $browser->ver < 7) - $filename = rawurlencode(abbreviate_string($filename, 55)); - else if ($browser->ie) - $filename = rawurlencode($filename); - else - $filename = addcslashes($filename, '"'); - - header("Content-Length: {$headers->size}"); - header("Content-Disposition: attachment; filename=\"$filename\""); - } - - $RCMAIL->storage->print_raw_body($uid, empty($_GET['_save'])); +if ($uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET)) { + $headers = $RCMAIL->storage->get_message_headers($uid); + $charset = $headers->charset ? $headers->charset : $RCMAIL->config->get('default_charset'); + + header("Content-Type: text/plain; charset={$charset}"); + + if (!empty($_GET['_save'])) { + $subject = rcube_mime::decode_header($headers->subject, $headers->charset); + $filename = ($subject ? $subject : $RCMAIL->config->get('product_name', 'email')) . '.eml'; + $browser = $RCMAIL->output->browser; + + if ($browser->ie && $browser->ver < 7) + $filename = rawurlencode(abbreviate_string($filename, 55)); + else if ($browser->ie) + $filename = rawurlencode($filename); + else + $filename = addcslashes($filename, '"'); + + header("Content-Length: {$headers->size}"); + header("Content-Disposition: attachment; filename=\"$filename\""); + } + + $RCMAIL->storage->print_raw_body($uid, empty($_GET['_save'])); } -else -{ - rcube::raise_error(array( - 'code' => 500, - 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => 'Message UID '.$uid.' not found'), - true, true); +else { + rcube::raise_error(array( + 'code' => 500, + 'type' => 'php', + 'file' => __FILE__, + 'line' => __LINE__, + 'message' => "Message UID $uid not found" + ), + true, true); } exit; - diff --git a/program/steps/settings/about.inc b/program/steps/settings/about.inc index eae4da842..026bfc1a2 100644 --- a/program/steps/settings/about.inc +++ b/program/steps/settings/about.inc @@ -5,8 +5,8 @@ | program/steps/settings/about.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2011, The Roundcube Dev Team | - | Copyright (C) 2011, Kolab Systems AG | + | Copyright (C) 2005-2013, The Roundcube Dev Team | + | Copyright (C) 2011-2013, Kolab Systems AG | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -21,78 +21,83 @@ */ +$OUTPUT->set_pagetitle($RCMAIL->gettext('about')); + +$OUTPUT->add_handler('supportlink', 'rcmail_supportlink'); +$OUTPUT->add_handler('pluginlist', 'rcmail_plugins_list'); + +$OUTPUT->send('about'); + + + function rcmail_supportlink($attrib) { - global $RCMAIL; + global $RCMAIL; - if ($url = $RCMAIL->config->get('support_url')) { - $label = $attrib['label'] ? $attrib['label'] : 'support'; - $attrib['href'] = $url; - return html::a($attrib, $RCMAIL->gettext($label)); - } + if ($url = $RCMAIL->config->get('support_url')) { + $label = $attrib['label'] ? $attrib['label'] : 'support'; + $attrib['href'] = $url; + + return html::a($attrib, $RCMAIL->gettext($label)); + } } function rcmail_plugins_list($attrib) { - global $RCMAIL; - - if (!$attrib['id']) - $attrib['id'] = 'rcmpluginlist'; - - $plugins = array_filter((array) $RCMAIL->config->get('plugins')); - $plugin_info = array(); - - foreach ($plugins as $name) { - if ($info = $RCMAIL->plugins->get_info($name)) - $plugin_info[$name] = $info; - } - - // load info from required plugins, too - foreach ($plugin_info as $name => $info) { - if (is_array($info['required']) && !empty($info['required'])) { - foreach ($info['required'] as $req_name) { - if (!isset($plugin_info[$req_name]) && ($req_info = $RCMAIL->plugins->get_info($req_name))) - $plugin_info[$req_name] = $req_info; - } - } - } + global $RCMAIL; - if (empty($plugin_info)) { - return ''; - } + if (!$attrib['id']) { + $attrib['id'] = 'rcmpluginlist'; + } - ksort($plugin_info, SORT_LOCALE_STRING); + $plugins = array_filter((array) $RCMAIL->config->get('plugins')); + $plugin_info = array(); - $table = new html_table($attrib); + foreach ($plugins as $name) { + if ($info = $RCMAIL->plugins->get_info($name)) { + $plugin_info[$name] = $info; + } + } - // add table header - $table->add_header('name', $RCMAIL->gettext('plugin')); - $table->add_header('version', $RCMAIL->gettext('version')); - $table->add_header('license', $RCMAIL->gettext('license')); - $table->add_header('source', $RCMAIL->gettext('source')); + // load info from required plugins, too + foreach ($plugin_info as $name => $info) { + if (is_array($info['required']) && !empty($info['required'])) { + foreach ($info['required'] as $req_name) { + if (!isset($plugin_info[$req_name]) && ($req_info = $RCMAIL->plugins->get_info($req_name))) { + $plugin_info[$req_name] = $req_info; + } + } + } + } - foreach ($plugin_info as $name => $data) { - $uri = $data['src_uri'] ? $data['src_uri'] : $data['uri']; - if ($uri && stripos($uri, 'http') !== 0) { - $uri = 'http://' . $uri; + if (empty($plugin_info)) { + return ''; } - $table->add_row(); - $table->add('name', rcube::Q($data['name'] ? $data['name'] : $name)); - $table->add('version', rcube::Q($data['version'])); - $table->add('license', $data['license_uri'] ? html::a(array('target' => '_blank', href=> rcube::Q($data['license_uri'])), - rcube::Q($data['license'])) : $data['license']); - $table->add('source', $uri ? html::a(array('target' => '_blank', href=> rcube::Q($uri)), - rcube::Q($RCMAIL->gettext('download'))) : ''); - } + ksort($plugin_info, SORT_LOCALE_STRING); + + $table = new html_table($attrib); + + // add table header + $table->add_header('name', $RCMAIL->gettext('plugin')); + $table->add_header('version', $RCMAIL->gettext('version')); + $table->add_header('license', $RCMAIL->gettext('license')); + $table->add_header('source', $RCMAIL->gettext('source')); + + foreach ($plugin_info as $name => $data) { + $uri = $data['src_uri'] ? $data['src_uri'] : $data['uri']; + if ($uri && stripos($uri, 'http') !== 0) { + $uri = 'http://' . $uri; + } + + $table->add_row(); + $table->add('name', rcube::Q($data['name'] ? $data['name'] : $name)); + $table->add('version', rcube::Q($data['version'])); + $table->add('license', $data['license_uri'] ? html::a(array('target' => '_blank', href=> rcube::Q($data['license_uri'])), + rcube::Q($data['license'])) : $data['license']); + $table->add('source', $uri ? html::a(array('target' => '_blank', href=> rcube::Q($uri)), + rcube::Q($RCMAIL->gettext('download'))) : ''); + } - return $table->show(); + return $table->show(); } - - -$OUTPUT->set_pagetitle($RCMAIL->gettext('about')); - -$OUTPUT->add_handler('supportlink', 'rcmail_supportlink'); -$OUTPUT->add_handler('pluginlist', 'rcmail_plugins_list'); - -$OUTPUT->send('about'); diff --git a/program/steps/settings/delete_identity.inc b/program/steps/settings/delete_identity.inc index 85d128c8f..f77620438 100644 --- a/program/steps/settings/delete_identity.inc +++ b/program/steps/settings/delete_identity.inc @@ -5,7 +5,7 @@ | program/steps/settings/delete_identity.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -23,29 +23,33 @@ $iid = rcube_utils::get_input_value('_iid', rcube_utils::INPUT_GPC); // check request token if (!$OUTPUT->ajax_call && !$RCMAIL->check_request(rcube_utils::INPUT_GPC)) { - $OUTPUT->show_message('invalidrequest', 'error'); - $RCMAIL->overwrite_action('identities'); - return; + $OUTPUT->show_message('invalidrequest', 'error'); + $RCMAIL->overwrite_action('identities'); + return; } -if ($iid && preg_match('/^[0-9]+(,[0-9]+)*$/', $iid)) -{ - $plugin = $RCMAIL->plugins->exec_hook('identity_delete', array('id' => $iid)); +if ($iid && preg_match('/^[0-9]+(,[0-9]+)*$/', $iid)) { + $plugin = $RCMAIL->plugins->exec_hook('identity_delete', array('id' => $iid)); - $deleted = !$plugin['abort'] ? $RCMAIL->user->delete_identity($iid) : $plugin['result']; + $deleted = !$plugin['abort'] ? $RCMAIL->user->delete_identity($iid) : $plugin['result']; - if ($deleted > 0 && $deleted !== false) - $OUTPUT->show_message('deletedsuccessfully', 'confirmation', null, false); - else - $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : ($deleted < 0 ? 'nodeletelastidentity' : 'errorsaving'), 'error', null, false); + if ($deleted > 0 && $deleted !== false) { + $OUTPUT->show_message('deletedsuccessfully', 'confirmation', null, false); + } + else { + $msg = $plugin['message'] ? $plugin['message'] : ($deleted < 0 ? 'nodeletelastidentity' : 'errorsaving'); + $OUTPUT->show_message($msg, 'error', null, false); + } - // send response - if ($OUTPUT->ajax_call) - $OUTPUT->send(); + // send response + if ($OUTPUT->ajax_call) { + $OUTPUT->send(); + } } -if ($OUTPUT->ajax_call) - exit; +if ($OUTPUT->ajax_call) { + exit; +} // go to identities page $RCMAIL->overwrite_action('identities'); diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index ff28d04c8..fc6b2cd16 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -5,7 +5,7 @@ | program/steps/settings/edit_folder.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -19,6 +19,16 @@ +-----------------------------------------------------------------------+ */ +// register UI objects +$OUTPUT->add_handlers(array( + 'folderdetails' => 'rcmail_folder_form', +)); + +$OUTPUT->add_label('nonamewarning'); + +$OUTPUT->send('folderedit'); + + // WARNING: folder names in UI are encoded with RCUBE_CHARSET function rcmail_folder_form($attrib) @@ -256,7 +266,8 @@ function rcmail_folder_form($attrib) foreach ($tab['fieldsets'] as $fieldset) { $subcontent = rcmail_get_form_part($fieldset, $attrib); if ($subcontent) { - $content .= html::tag('fieldset', null, html::tag('legend', null, rcube::Q($fieldset['name'])) . $subcontent) ."\n"; + $subcontent = html::tag('legend', null, rcube::Q($fieldset['name'])) . $subcontent; + $content .= html::tag('fieldset', null, $subcontent) ."\n"; } } } @@ -300,15 +311,3 @@ function rcmail_get_form_part($form, $attrib = array()) return $content; } - - -//$OUTPUT->set_pagetitle($RCMAIL->gettext('folders')); - -// register UI objects -$OUTPUT->add_handlers(array( - 'folderdetails' => 'rcmail_folder_form', -)); - -$OUTPUT->add_label('nonamewarning'); - -$OUTPUT->send('folderedit'); diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc index 974acb42a..f208c8a05 100644 --- a/program/steps/settings/edit_identity.inc +++ b/program/steps/settings/edit_identity.inc @@ -5,7 +5,7 @@ | program/steps/settings/edit_identity.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2011, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -23,152 +23,158 @@ define('IDENTITIES_LEVEL', intval($RCMAIL->config->get('identities_level', 0))); // edit-identity if (($_GET['_iid'] || $_POST['_iid']) && $RCMAIL->action=='edit-identity') { - $IDENTITY_RECORD = $RCMAIL->user->get_identity(rcube_utils::get_input_value('_iid', rcube_utils::INPUT_GPC)); - - if (is_array($IDENTITY_RECORD)) - $OUTPUT->set_env('iid', $IDENTITY_RECORD['identity_id']); - else { - $OUTPUT->show_message('dberror', 'error'); - // go to identities page - $RCMAIL->overwrite_action('identities'); - return; - } + $id = rcube_utils::get_input_value('_iid', rcube_utils::INPUT_GPC); + $IDENTITY_RECORD = $RCMAIL->user->get_identity($id); + + if (is_array($IDENTITY_RECORD)) { + $OUTPUT->set_env('iid', $IDENTITY_RECORD['identity_id']); + } + else { + $OUTPUT->show_message('dberror', 'error'); + // go to identities page + $RCMAIL->overwrite_action('identities'); + return; + } } // add-identity else { - if (IDENTITIES_LEVEL > 1) { - $OUTPUT->show_message('opnotpermitted', 'error'); - // go to identities page - $RCMAIL->overwrite_action('identities'); - return; - } - else if (IDENTITIES_LEVEL == 1) { - $IDENTITY_RECORD['email'] = $RCMAIL->get_user_email(); - } + if (IDENTITIES_LEVEL > 1) { + $OUTPUT->show_message('opnotpermitted', 'error'); + // go to identities page + $RCMAIL->overwrite_action('identities'); + return; + } + else if (IDENTITIES_LEVEL == 1) { + $IDENTITY_RECORD['email'] = $RCMAIL->get_user_email(); + } +} + +$OUTPUT->include_script('list.js'); +$OUTPUT->add_handler('identityform', 'rcube_identity_form'); +$OUTPUT->set_env('identities_level', IDENTITIES_LEVEL); +$OUTPUT->add_label('deleteidentityconfirm'); + +$OUTPUT->set_pagetitle($RCMAIL->gettext(($RCMAIL->action == 'add-identity' ? 'newidentity' : 'edititem'))); + +if ($RCMAIL->action == 'add-identity' && $OUTPUT->template_exists('identityadd')) { + $OUTPUT->send('identityadd'); } +$OUTPUT->send('identityedit'); + function rcube_identity_form($attrib) { - global $IDENTITY_RECORD, $RCMAIL, $OUTPUT; - - // Add HTML editor script(s) - $RCMAIL->html_editor('identity'); - - // add some labels to client - $OUTPUT->add_label('noemailwarning', 'nonamewarning', 'converting', 'editorwarning'); - - $i_size = !empty($attrib['size']) ? $attrib['size'] : 40; - $t_rows = !empty($attrib['textarearows']) ? $attrib['textarearows'] : 6; - $t_cols = !empty($attrib['textareacols']) ? $attrib['textareacols'] : 40; - - // list of available cols - $form = array( - 'addressing' => array( - 'name' => $RCMAIL->gettext('settings'), - 'content' => array( - 'name' => array('type' => 'text', 'size' => $i_size), - 'email' => array('type' => 'text', 'size' => $i_size), - 'organization' => array('type' => 'text', 'size' => $i_size), - 'reply-to' => array('type' => 'text', 'size' => $i_size), - 'bcc' => array('type' => 'text', 'size' => $i_size), - 'standard' => array('type' => 'checkbox', 'label' => $RCMAIL->gettext('setdefault')), - )), - 'signature' => array( - 'name' => $RCMAIL->gettext('signature'), - 'content' => array( - 'signature' => array('type' => 'textarea', 'size' => $t_cols, 'rows' => $t_rows, - 'spellcheck' => true), - 'html_signature' => array('type' => 'checkbox', 'label' => $RCMAIL->gettext('htmlsignature'), - 'onclick' => 'return rcmail_toggle_editor(this, \'rcmfd_signature\');'), - )) - ); - - // Enable TinyMCE editor - if ($IDENTITY_RECORD['html_signature']) { - $form['signature']['content']['signature']['class'] = 'mce_editor'; - $form['signature']['content']['signature']['is_escaped'] = true; - - // Correctly handle HTML entities in HTML editor (#1488483) - $IDENTITY_RECORD['signature'] = htmlspecialchars($IDENTITY_RECORD['signature'], ENT_NOQUOTES, RCUBE_CHARSET); - } - - // disable some field according to access level - if (IDENTITIES_LEVEL == 1 || IDENTITIES_LEVEL == 3) { - $form['addressing']['content']['email']['disabled'] = true; - $form['addressing']['content']['email']['class'] = 'disabled'; - } - - if (IDENTITIES_LEVEL == 4) { - foreach($form['addressing']['content'] as $formfield => $value){ - $form['addressing']['content'][$formfield]['disabled'] = true; - $form['addressing']['content'][$formfield]['class'] = 'disabled'; + global $IDENTITY_RECORD, $RCMAIL, $OUTPUT; + + // Add HTML editor script(s) + $RCMAIL->html_editor('identity'); + + // add some labels to client + $OUTPUT->add_label('noemailwarning', 'nonamewarning', 'converting', 'editorwarning'); + + $i_size = !empty($attrib['size']) ? $attrib['size'] : 40; + $t_rows = !empty($attrib['textarearows']) ? $attrib['textarearows'] : 6; + $t_cols = !empty($attrib['textareacols']) ? $attrib['textareacols'] : 40; + + // list of available cols + $form = array( + 'addressing' => array( + 'name' => $RCMAIL->gettext('settings'), + 'content' => array( + 'name' => array('type' => 'text', 'size' => $i_size), + 'email' => array('type' => 'text', 'size' => $i_size), + 'organization' => array('type' => 'text', 'size' => $i_size), + 'reply-to' => array('type' => 'text', 'size' => $i_size), + 'bcc' => array('type' => 'text', 'size' => $i_size), + 'standard' => array('type' => 'checkbox', 'label' => $RCMAIL->gettext('setdefault')), + )), + 'signature' => array( + 'name' => $RCMAIL->gettext('signature'), + 'content' => array( + 'signature' => array('type' => 'textarea', 'size' => $t_cols, 'rows' => $t_rows, + 'spellcheck' => true), + 'html_signature' => array('type' => 'checkbox', + 'label' => $RCMAIL->gettext('htmlsignature'), + 'onclick' => 'return rcmail_toggle_editor(this, \'rcmfd_signature\');'), + )) + ); + + // Enable TinyMCE editor + if ($IDENTITY_RECORD['html_signature']) { + $form['signature']['content']['signature']['class'] = 'mce_editor'; + $form['signature']['content']['signature']['is_escaped'] = true; + + // Correctly handle HTML entities in HTML editor (#1488483) + $IDENTITY_RECORD['signature'] = htmlspecialchars($IDENTITY_RECORD['signature'], ENT_NOQUOTES, RCUBE_CHARSET); } - } - $IDENTITY_RECORD['email'] = rcube_utils::idn_to_utf8($IDENTITY_RECORD['email']); + // disable some field according to access level + if (IDENTITIES_LEVEL == 1 || IDENTITIES_LEVEL == 3) { + $form['addressing']['content']['email']['disabled'] = true; + $form['addressing']['content']['email']['class'] = 'disabled'; + } - // Allow plugins to modify identity form content - $plugin = $RCMAIL->plugins->exec_hook('identity_form', array( - 'form' => $form, 'record' => $IDENTITY_RECORD)); + if (IDENTITIES_LEVEL == 4) { + foreach($form['addressing']['content'] as $formfield => $value){ + $form['addressing']['content'][$formfield]['disabled'] = true; + $form['addressing']['content'][$formfield]['class'] = 'disabled'; + } + } - $form = $plugin['form']; - $IDENTITY_RECORD = $plugin['record']; + $IDENTITY_RECORD['email'] = rcube_utils::idn_to_utf8($IDENTITY_RECORD['email']); - // Set form tags and hidden fields - list($form_start, $form_end) = get_form_tags($attrib, 'save-identity', - intval($IDENTITY_RECORD['identity_id']), - array('name' => '_iid', 'value' => $IDENTITY_RECORD['identity_id'])); + // Allow plugins to modify identity form content + $plugin = $RCMAIL->plugins->exec_hook('identity_form', array( + 'form' => $form, 'record' => $IDENTITY_RECORD)); - unset($plugin); - unset($attrib['form'], $attrib['id']); + $form = $plugin['form']; + $IDENTITY_RECORD = $plugin['record']; - // return the complete edit form as table - $out = "$form_start\n"; + // Set form tags and hidden fields + list($form_start, $form_end) = get_form_tags($attrib, 'save-identity', + intval($IDENTITY_RECORD['identity_id']), + array('name' => '_iid', 'value' => $IDENTITY_RECORD['identity_id'])); - foreach ($form as $fieldset) { - if (empty($fieldset['content'])) - continue; + unset($plugin); + unset($attrib['form'], $attrib['id']); - $content = ''; - if (is_array($fieldset['content'])) { - $table = new html_table(array('cols' => 2)); - foreach ($fieldset['content'] as $col => $colprop) { - $colprop['id'] = 'rcmfd_'.$col; + // return the complete edit form as table + $out = "$form_start\n"; - $label = !empty($colprop['label']) ? $colprop['label'] : - $RCMAIL->gettext(str_replace('-', '', $col)); + foreach ($form as $fieldset) { + if (empty($fieldset['content'])) { + continue; + } - $value = !empty($colprop['value']) ? $colprop['value'] : - rcube_output::get_edit_field($col, $IDENTITY_RECORD[$col], $colprop, $colprop['type']); + $content = ''; + if (is_array($fieldset['content'])) { + $table = new html_table(array('cols' => 2)); - $table->add('title', html::label($colprop['id'], rcube::Q($label))); - $table->add(null, $value); - } - $content = $table->show($attrib); - } - else { - $content = $fieldset['content']; - } + foreach ($fieldset['content'] as $col => $colprop) { + $colprop['id'] = 'rcmfd_'.$col; - $out .= html::tag('fieldset', null, html::tag('legend', null, rcube::Q($fieldset['name'])) . $content) ."\n"; - } + $label = !empty($colprop['label']) ? $colprop['label'] : + $RCMAIL->gettext(str_replace('-', '', $col)); - $out .= $form_end; + $value = !empty($colprop['value']) ? $colprop['value'] : + rcube_output::get_edit_field($col, $IDENTITY_RECORD[$col], $colprop, $colprop['type']); - return $out; -} + $table->add('title', html::label($colprop['id'], rcube::Q($label))); + $table->add(null, $value); + } -$OUTPUT->include_script('list.js'); -$OUTPUT->add_handler('identityform', 'rcube_identity_form'); -$OUTPUT->set_env('identities_level', IDENTITIES_LEVEL); -$OUTPUT->add_label('deleteidentityconfirm'); - -$OUTPUT->set_pagetitle($RCMAIL->gettext(($RCMAIL->action=='add-identity' ? 'newidentity' : 'edititem'))); - -if ($RCMAIL->action=='add-identity' && $OUTPUT->template_exists('identityadd')) - $OUTPUT->send('identityadd'); + $content = $table->show($attrib); + } + else { + $content = $fieldset['content']; + } -$OUTPUT->send('identityedit'); + $content = html::tag('legend', null, rcube::Q($fieldset['name'])) . $content; + $out .= html::tag('fieldset', null, $content) . "\n"; + } + $out .= $form_end; + return $out; +} diff --git a/program/steps/settings/edit_prefs.inc b/program/steps/settings/edit_prefs.inc index 93e27aedc..05f4db6a6 100644 --- a/program/steps/settings/edit_prefs.inc +++ b/program/steps/settings/edit_prefs.inc @@ -5,7 +5,7 @@ | program/steps/settings/edit_prefs.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2007, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -19,65 +19,65 @@ +-----------------------------------------------------------------------+ */ -if (!$OUTPUT->ajax_call) - $OUTPUT->set_pagetitle($RCMAIL->gettext('preferences')); +if (!$OUTPUT->ajax_call) { + $OUTPUT->set_pagetitle($RCMAIL->gettext('preferences')); +} -$CURR_SECTION = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GPC); +$CURR_SECTION = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GPC); list($SECTIONS,) = rcmail_user_prefs($CURR_SECTION); +// register UI objects +$OUTPUT->add_handlers(array( + 'userprefs' => 'rcmail_user_prefs_form', + 'sectionname' => 'rcmail_prefs_section_name', +)); + +$OUTPUT->send('settingsedit'); + + + function rcmail_user_prefs_form($attrib) { - global $RCMAIL, $CURR_SECTION, $SECTIONS; + global $RCMAIL, $CURR_SECTION, $SECTIONS; - // add some labels to client - $RCMAIL->output->add_label('nopagesizewarning'); + // add some labels to client + $RCMAIL->output->add_label('nopagesizewarning'); - unset($attrib['form']); + unset($attrib['form']); - list($form_start, $form_end) = get_form_tags($attrib, 'save-prefs', null, - array('name' => '_section', 'value' => $CURR_SECTION)); + list($form_start, $form_end) = get_form_tags($attrib, 'save-prefs', null, + array('name' => '_section', 'value' => $CURR_SECTION)); - $out = $form_start; + $out = $form_start; - foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $class => $block) { - if (!empty($block['options'])) { - $table = new html_table(array('cols' => 2)); + foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $class => $block) { + if (!empty($block['options'])) { + $table = new html_table(array('cols' => 2)); - foreach ($block['options'] as $option) { - if (isset($option['title'])) { - $table->add('title', $option['title']); - $table->add(null, $option['content']); + foreach ($block['options'] as $option) { + if (isset($option['title'])) { + $table->add('title', $option['title']); + $table->add(null, $option['content']); + } + else { + $table->add(array('colspan' => 2), $option['content']); + } + } + + $out .= html::tag('fieldset', $class, html::tag('legend', null, $block['name']) . $table->show($attrib)); } - else { - $table->add(array('colspan' => 2), $option['content']); + else if (!empty($block['content'])) { + $out .= html::tag('fieldset', null, html::tag('legend', null, $block['name']) . $block['content']); } - } - - $out .= html::tag('fieldset', $class, html::tag('legend', null, $block['name']) . $table->show($attrib)); } - else if (!empty($block['content'])) { - $out .= html::tag('fieldset', null, html::tag('legend', null, $block['name']) . $block['content']); - } - } - return $out . $form_end; + return $out . $form_end; } function rcmail_prefs_section_name() { - global $SECTIONS, $CURR_SECTION; - - return $SECTIONS[$CURR_SECTION]['section']; -} - - -// register UI objects -$OUTPUT->add_handlers(array( - 'userprefs' => 'rcmail_user_prefs_form', - 'sectionname' => 'rcmail_prefs_section_name', -)); - -$OUTPUT->send('settingsedit'); - + global $SECTIONS, $CURR_SECTION; + return $SECTIONS[$CURR_SECTION]['section']; +} diff --git a/program/steps/settings/edit_response.inc b/program/steps/settings/edit_response.inc index 371d7ecc4..760f28290 100644 --- a/program/steps/settings/edit_response.inc +++ b/program/steps/settings/edit_response.inc @@ -70,6 +70,12 @@ if ($RCMAIL->action == 'save-response' && isset($_POST['_name']) && !$RESPONSE_R } } +$OUTPUT->set_env('readonly', !empty($RESPONSE_RECORD['static'])); +$OUTPUT->add_handler('responseform', 'rcube_response_form'); +$OUTPUT->set_pagetitle($RCMAIL->gettext($RCMAIL->action == 'add-response' ? 'savenewresponse' : 'editresponse')); + +$OUTPUT->send('responseedit'); + function rcube_response_form($attrib) { @@ -88,20 +94,15 @@ function rcube_response_form($attrib) $label = $RCMAIL->gettext('responsename'); $table->add('title', html::label('ffname', rcube::Q($RCMAIL->gettext('responsename')))); - $table->add(null, rcube_output::get_edit_field('name', $RESPONSE_RECORD['name'], array('id' => 'ffname', 'size' => $attrib['size'], 'disabled' => $disabled), 'text')); + $table->add(null, rcube_output::get_edit_field('name', $RESPONSE_RECORD['name'], + array('id' => 'ffname', 'size' => $attrib['size'], 'disabled' => $disabled), 'text')); $table->add('title', html::label('fftext', rcube::Q($RCMAIL->gettext('responsetext')))); - $table->add(null, rcube_output::get_edit_field('text', $RESPONSE_RECORD['text'], array('id' => 'fftext', 'size' => $attrib['textareacols'], 'rows' => $attrib['textarearows'], 'disabled' => $disabled), 'textarea')); + $table->add(null, rcube_output::get_edit_field('text', $RESPONSE_RECORD['text'], + array('id' => 'fftext', 'size' => $attrib['textareacols'], 'rows' => $attrib['textarearows'], 'disabled' => $disabled), 'textarea')); $out .= $table->show($attrib); $out .= $form_end; return $out; } - -$OUTPUT->set_env('readonly', !empty($RESPONSE_RECORD['static'])); -$OUTPUT->add_handler('responseform', 'rcube_response_form'); -$OUTPUT->set_pagetitle($RCMAIL->gettext($RCMAIL->action == 'add-response' ? 'savenewresponse' : 'editresponse')); - -$OUTPUT->send('responseedit'); - diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 118590318..b09ea03ce 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -5,7 +5,7 @@ | program/steps/settings/folders.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -26,9 +26,9 @@ $STORAGE = $RCMAIL->get_storage(); // subscribe mailbox -if ($RCMAIL->action == 'subscribe') -{ +if ($RCMAIL->action == 'subscribe') { $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true, 'UTF7-IMAP'); + if (strlen($mbox)) { $result = $STORAGE->subscribe(array($mbox)); @@ -56,10 +56,8 @@ if ($RCMAIL->action == 'subscribe') $RCMAIL->display_server_error('errorsaving'); } } - // unsubscribe mailbox -else if ($RCMAIL->action == 'unsubscribe') -{ +else if ($RCMAIL->action == 'unsubscribe') { $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true, 'UTF7-IMAP'); if (strlen($mbox)) { $result = $STORAGE->unsubscribe(array($mbox)); @@ -69,10 +67,8 @@ else if ($RCMAIL->action == 'unsubscribe') $RCMAIL->display_server_error('errorsaving'); } } - // delete an existing mailbox -else if ($RCMAIL->action == 'delete-folder') -{ +else if ($RCMAIL->action == 'delete-folder') { $mbox_utf8 = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true); $mbox = rcube_charset::convert($mbox_utf8, RCUBE_CHARSET, 'UTF7-IMAP'); @@ -104,10 +100,8 @@ else if ($RCMAIL->action == 'delete-folder') $RCMAIL->display_server_error('errorsaving'); } } - // rename an existing mailbox -else if ($RCMAIL->action == 'rename-folder') -{ +else if ($RCMAIL->action == 'rename-folder') { $name_utf8 = trim(rcube_utils::get_input_value('_folder_newname', rcube_utils::INPUT_POST, true)); $oldname_utf8 = rcube_utils::get_input_value('_folder_oldname', rcube_utils::INPUT_POST, true); @@ -125,17 +119,16 @@ else if ($RCMAIL->action == 'rename-folder') $RCMAIL->display_server_error('errorsaving'); } } - // clear mailbox -else if ($RCMAIL->action == 'purge') -{ - $mbox_utf8 = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true); - $mbox = rcube_charset::convert($mbox_utf8, RCUBE_CHARSET, 'UTF7-IMAP'); - $delimiter = $STORAGE->get_hierarchy_delimiter(); - $trash_regexp = '/^' . preg_quote($CONFIG['trash_mbox'] . $delimiter, '/') . '/'; +else if ($RCMAIL->action == 'purge') { + $mbox_utf8 = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true); + $mbox = rcube_charset::convert($mbox_utf8, RCUBE_CHARSET, 'UTF7-IMAP'); + $delimiter = $STORAGE->get_hierarchy_delimiter(); + $trash_mbox = $RCMAIL->config->get('trash_mbox'); + $trash_regexp = '/^' . preg_quote($trash . $delimiter, '/') . '/'; // we should only be purging trash (or their subfolders) - if (!strlen($CONFIG['trash_mbox']) || $mbox == $CONFIG['trash_mbox'] + if (!strlen($trash_mbox) || $mbox === $trash_mbox || preg_match($trash_regexp, $mbox) ) { $success = $STORAGE->delete_message('*', $mbox); @@ -143,7 +136,7 @@ else if ($RCMAIL->action == 'purge') } // copy to Trash else { - $success = $STORAGE->move_message('1:*', $CONFIG['trash_mbox'], $mbox); + $success = $STORAGE->move_message('1:*', $trash_mbox, $mbox); $delete = false; } @@ -163,10 +156,8 @@ else if ($RCMAIL->action == 'purge') $RCMAIL->display_server_error('errorsaving'); } } - // get mailbox size -else if ($RCMAIL->action == 'folder-size') -{ +else if ($RCMAIL->action == 'folder-size') { $name = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true); $size = $STORAGE->folder_size($name); @@ -181,8 +172,29 @@ else if ($RCMAIL->action == 'folder-size') } } -if ($OUTPUT->ajax_call) +if ($OUTPUT->ajax_call) { $OUTPUT->send(); +} + +$OUTPUT->set_pagetitle($RCMAIL->gettext('folders')); +$OUTPUT->include_script('list.js'); +$OUTPUT->set_env('prefix_ns', $STORAGE->get_namespace('prefix')); +if ($STORAGE->get_capability('QUOTA')) { + $OUTPUT->set_env('quota', true); +} + +// add some labels to client +$OUTPUT->add_label('deletefolderconfirm', 'purgefolderconfirm', 'folderdeleting', + 'foldermoving', 'foldersubscribing', 'folderunsubscribing', 'quota'); + +// register UI objects +$OUTPUT->add_handlers(array( + 'foldersubscription' => 'rcube_subscription_form', + 'folderframe' => 'rcmail_folder_frame', + 'quotadisplay' => array($RCMAIL, 'quota_display'), +)); + +$OUTPUT->send('folders'); // build table with all folders listed by server @@ -366,8 +378,9 @@ function rcmail_folder_frame($attrib) { global $OUTPUT; - if (!$attrib['id']) + if (!$attrib['id']) { $attrib['id'] = 'rcmfolderframe'; + } return $OUTPUT->frame($attrib, true); } @@ -416,24 +429,3 @@ function rcmail_rename_folder($oldname, $newname) return false; } - - -$OUTPUT->set_pagetitle($RCMAIL->gettext('folders')); -$OUTPUT->include_script('list.js'); -$OUTPUT->set_env('prefix_ns', $STORAGE->get_namespace('prefix')); -if ($STORAGE->get_capability('QUOTA')) { - $OUTPUT->set_env('quota', true); -} - -// add some labels to client -$OUTPUT->add_label('deletefolderconfirm', 'purgefolderconfirm', 'folderdeleting', - 'foldermoving', 'foldersubscribing', 'folderunsubscribing', 'quota'); - -// register UI objects -$OUTPUT->add_handlers(array( - 'foldersubscription' => 'rcube_subscription_form', - 'folderframe' => 'rcmail_folder_frame', - 'quotadisplay' => array($RCMAIL, 'quota_display'), -)); - -$OUTPUT->send('folders'); diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index c504e6c40..7c36df3b1 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -5,7 +5,7 @@ | program/steps/settings/func.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2012, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -23,6 +23,30 @@ if (!$OUTPUT->ajax_call) { $OUTPUT->set_pagetitle($RCMAIL->gettext('preferences')); } +// register UI objects +$OUTPUT->add_handlers(array( + 'settingstabs' => 'rcmail_settings_tabs', + 'prefsframe' => 'rcmail_preferences_frame', + 'sectionslist' => 'rcmail_sections_list', + 'identitieslist' => 'rcmail_identities_list', +)); + +// register action aliases +$RCMAIL->register_action_map(array( + 'folders' => 'folders.inc', + 'rename-folder' => 'folders.inc', + 'delete-folder' => 'folders.inc', + 'subscribe' => 'folders.inc', + 'unsubscribe' => 'folders.inc', + 'purge' => 'folders.inc', + 'folder-size' => 'folders.inc', + 'add-identity' => 'edit_identity.inc', + 'add-response' => 'edit_response.inc', + 'save-response' => 'edit_response.inc', + 'delete-response' => 'responses.inc', +)); + + // similar function as /steps/settings/identities.inc::rcmail_identity_frame() function rcmail_preferences_frame($attrib) { @@ -1180,7 +1204,7 @@ function rcmail_user_prefs($current = null) $data = $RCMAIL->plugins->exec_hook('preferences_list', array('section' => $sect['id'], 'blocks' => $blocks, 'current' => $current)); - $advanced_prefs = $config['advanced_prefs']; + $advanced_prefs = (array) $RCMAIL->config->get('advanced_prefs'); // create output foreach ($data['blocks'] as $key => $block) { @@ -1273,12 +1297,14 @@ function rcmail_update_folder_row($name, $oldname=null, $subscribe=false, $class $display_name = str_repeat(' ', $level) . rcube::Q($protected ? $RCMAIL->localize_foldername($name) : rcube_charset::convert($foldersplit[$level], 'UTF7-IMAP')); - if ($oldname === null) + if ($oldname === null) { $OUTPUT->command('add_folder_row', $name_utf8, $display_name, $protected, $subscribe, false, $class_name); - else + } + else { $OUTPUT->command('replace_folder_row', rcube_charset::convert($oldname, 'UTF7-IMAP'), $name_utf8, $display_name, $protected, $class_name); + } } /** @@ -1295,18 +1321,18 @@ function rcmail_settings_tabs($attrib) array('command' => 'preferences', 'type' => 'link', 'label' => 'preferences', 'title' => 'editpreferences'), array('command' => 'folders', 'type' => 'link', 'label' => 'folders', 'title' => 'managefolders'), array('command' => 'identities', 'type' => 'link', 'label' => 'identities', 'title' => 'manageidentities'), - array('command' => 'responses', 'type' => 'link', 'label' => 'responses', 'title' => 'editresponses'), + array('command' => 'responses', 'type' => 'link', 'label' => 'responses', 'title' => 'editresponses'), ); // get all identites from DB and define list of cols to be displayed $plugin = $RCMAIL->plugins->exec_hook('settings_actions', array( 'actions' => $default_actions, - 'attrib' => $attrib, + 'attrib' => $attrib, )); - $attrib = $plugin['attrib']; + $attrib = $plugin['attrib']; $tagname = $attrib['tagname']; - $tabs = array(); + $tabs = array(); foreach ($plugin['actions'] as $k => $action) { if (!$action['command'] && !$action['href'] && $action['action']) { @@ -1314,13 +1340,15 @@ function rcmail_settings_tabs($attrib) } $button = $OUTPUT->button($action); - $attr = $attrib; + $attr = $attrib; $cmd = $action['action'] ? $action['action'] : $action['command']; - $id = $action['id'] ? $action['id'] : $cmd; + $id = $action['id'] ? $action['id'] : $cmd; + if (!empty($id)) { $attr['id'] = preg_replace('/[^a-z0-9]/i', '', $attrib['idprefix'] . $id); } + $classnames = array($attrib['class']); if (!empty($action['class'])) { $classnames[] = $action['class']; @@ -1331,33 +1359,10 @@ function rcmail_settings_tabs($attrib) if ($RCMAIL->action == $cmd) { $classnames[] = $attrib['selclass']; } + $attr['class'] = join(' ', $classnames); $tabs[] = html::tag($tagname, $attr, $button, html::$common_attrib); } return join('', $tabs); } - - -// register UI objects -$OUTPUT->add_handlers(array( - 'settingstabs' => 'rcmail_settings_tabs', - 'prefsframe' => 'rcmail_preferences_frame', - 'sectionslist' => 'rcmail_sections_list', - 'identitieslist' => 'rcmail_identities_list', -)); - -// register action aliases -$RCMAIL->register_action_map(array( - 'folders' => 'folders.inc', - 'rename-folder' => 'folders.inc', - 'delete-folder' => 'folders.inc', - 'subscribe' => 'folders.inc', - 'unsubscribe' => 'folders.inc', - 'purge' => 'folders.inc', - 'folder-size' => 'folders.inc', - 'add-identity' => 'edit_identity.inc', - 'add-response' => 'edit_response.inc', - 'save-response' => 'edit_response.inc', - 'delete-response' => 'responses.inc', -)); diff --git a/program/steps/settings/identities.inc b/program/steps/settings/identities.inc index 7072acf72..e19c16c79 100644 --- a/program/steps/settings/identities.inc +++ b/program/steps/settings/identities.inc @@ -5,7 +5,7 @@ | program/steps/settings/identities.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2007, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -24,20 +24,21 @@ define('IDENTITIES_LEVEL', intval($RCMAIL->config->get('identities_level', 0))); $OUTPUT->set_pagetitle($RCMAIL->gettext('identities')); $OUTPUT->include_script('list.js'); - -// similar function as /steps/addressbook/func.inc::rcmail_contact_frame() -function rcmail_identity_frame($attrib) - { - global $OUTPUT; - - if (!$attrib['id']) - $attrib['id'] = 'rcmIdentityFrame'; - - return $OUTPUT->frame($attrib, true); - } - $OUTPUT->add_handler('identityframe', 'rcmail_identity_frame'); $OUTPUT->set_env('identities_level', IDENTITIES_LEVEL); $OUTPUT->add_label('deleteidentityconfirm'); $OUTPUT->send('identities'); + + +// similar function as /steps/addressbook/func.inc::rcmail_contact_frame() +function rcmail_identity_frame($attrib) +{ + global $OUTPUT; + + if (!$attrib['id']) { + $attrib['id'] = 'rcmIdentityFrame'; + } + + return $OUTPUT->frame($attrib, true); +} diff --git a/program/steps/settings/responses.inc b/program/steps/settings/responses.inc index 45d1405f7..fcc9c9a10 100644 --- a/program/steps/settings/responses.inc +++ b/program/steps/settings/responses.inc @@ -51,7 +51,6 @@ if (!empty($_POST['_insert'])) { $RCMAIL->output->send(); } - if ($RCMAIL->action == 'delete-response') { if ($key = rcube_utils::get_input_value('_key', rcube_utils::INPUT_GPC)) { $responses = $RCMAIL->get_compose_responses(false, true); @@ -80,6 +79,14 @@ if ($RCMAIL->action == 'delete-response') { $OUTPUT->set_pagetitle($RCMAIL->gettext('responses')); $OUTPUT->include_script('list.js'); +$OUTPUT->add_handlers(array( + 'responseframe' => 'rcmail_response_frame', + 'responseslist' => 'rcmail_responses_list', +)); +$OUTPUT->add_label('deleteresponseconfirm'); + +$OUTPUT->send('responses'); + /** * @@ -105,7 +112,6 @@ function rcmail_responses_list($attrib) return $out; } - // similar function as /steps/addressbook/func.inc::rcmail_contact_frame() function rcmail_response_frame($attrib) { @@ -116,13 +122,6 @@ function rcmail_response_frame($attrib) } $OUTPUT->set_env('contentframe', $attrib['id']); + return $OUTPUT->frame($attrib, true); } - -$OUTPUT->add_handlers(array( - 'responseframe' => 'rcmail_response_frame', - 'responseslist' => 'rcmail_responses_list', -)); -$OUTPUT->add_label('deleteresponseconfirm'); - -$OUTPUT->send('responses'); diff --git a/program/steps/settings/save_folder.inc b/program/steps/settings/save_folder.inc index f876ff8e0..f720735e0 100644 --- a/program/steps/settings/save_folder.inc +++ b/program/steps/settings/save_folder.inc @@ -1,6 +1,6 @@ <?php -/** +/* +-----------------------------------------------------------------------+ | program/steps/settings/save_folder.inc | | | @@ -24,7 +24,6 @@ // init IMAP connection $STORAGE = $RCMAIL->get_storage(); - $name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST, true)); $old = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true); $path = rcube_utils::get_input_value('_parent', rcube_utils::INPUT_POST, true); @@ -98,7 +97,6 @@ else { // create a new mailbox if (!$error && !strlen($old)) { - $folder['subscribe'] = true; $plugin = $RCMAIL->plugins->exec_hook('folder_create', array('record' => $folder)); @@ -136,7 +134,6 @@ if (!$error && !strlen($old)) { $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error', null, false); } } - // update a mailbox else if (!$error) { $plugin = $RCMAIL->plugins->exec_hook('folder_update', array('record' => $folder)); diff --git a/program/steps/settings/save_identity.inc b/program/steps/settings/save_identity.inc index 5bd04003d..1584c5f00 100644 --- a/program/steps/settings/save_identity.inc +++ b/program/steps/settings/save_identity.inc @@ -5,7 +5,7 @@ | program/steps/settings/save_identity.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -21,161 +21,173 @@ define('IDENTITIES_LEVEL', intval($RCMAIL->config->get('identities_level', 0))); -$a_save_cols = array('name', 'email', 'organization', 'reply-to', 'bcc', 'standard', 'signature', 'html_signature'); +$a_save_cols = array('name', 'email', 'organization', 'reply-to', 'bcc', 'standard', 'signature', 'html_signature'); $a_boolean_cols = array('standard', 'html_signature'); $updated = $default_id = false; // check input if (IDENTITIES_LEVEL != 4 && (empty($_POST['_name']) || (empty($_POST['_email']) && IDENTITIES_LEVEL != 1 && IDENTITIES_LEVEL != 3))) { - $OUTPUT->show_message('formincomplete', 'warning'); - $RCMAIL->overwrite_action('edit-identity'); - return; + $OUTPUT->show_message('formincomplete', 'warning'); + $RCMAIL->overwrite_action('edit-identity'); + return; } $save_data = array(); foreach ($a_save_cols as $col) { - $fname = '_'.$col; - if (isset($_POST[$fname])) - $save_data[$col] = rcube_utils::get_input_value($fname, rcube_utils::INPUT_POST, true); + $fname = '_'.$col; + if (isset($_POST[$fname])) { + $save_data[$col] = rcube_utils::get_input_value($fname, rcube_utils::INPUT_POST, true); + } } // set "off" values for checkboxes that were not checked, and therefore // not included in the POST body. foreach ($a_boolean_cols as $col) { - $fname = '_' . $col; - if (!isset($_POST[$fname])) - $save_data[$col] = 0; + $fname = '_' . $col; + if (!isset($_POST[$fname])) { + $save_data[$col] = 0; + } } // unset email address if user has no rights to change it if (IDENTITIES_LEVEL == 1 || IDENTITIES_LEVEL == 3) { - unset($save_data['email']); + unset($save_data['email']); } // unset all fields except signature else if (IDENTITIES_LEVEL == 4) { - foreach ($save_data as $idx => $value) { - if ($idx != 'signature' && $idx != 'html_signature') { - unset($save_data[$idx]); + foreach ($save_data as $idx => $value) { + if ($idx != 'signature' && $idx != 'html_signature') { + unset($save_data[$idx]); + } } - } } // Validate e-mail addresses $email_checks = array(rcube_utils::idn_to_ascii($save_data['email'])); foreach (array('reply-to', 'bcc') as $item) { - foreach (rcube_mime::decode_address_list($save_data[$item], null, false) as $rcpt) - $email_checks[] = rcube_utils::idn_to_ascii($rcpt['mailto']); + foreach (rcube_mime::decode_address_list($save_data[$item], null, false) as $rcpt) { + $email_checks[] = rcube_utils::idn_to_ascii($rcpt['mailto']); + } } foreach ($email_checks as $email) { - if ($email && !rcube_utils::check_email($email)) { - // show error message - $OUTPUT->show_message('emailformaterror', 'error', array('email' => rcube_utils::idn_to_utf8($email)), false); - $RCMAIL->overwrite_action('edit-identity'); - return; - } + if ($email && !rcube_utils::check_email($email)) { + // show error message + $OUTPUT->show_message('emailformaterror', 'error', array('email' => rcube_utils::idn_to_utf8($email)), false); + $RCMAIL->overwrite_action('edit-identity'); + return; + } } // XSS protection in HTML signature (#1489251) if (!empty($save_data['signature']) && !empty($save_data['html_signature'])) { - $save_data['signature'] = rcmail_wash_html($save_data['signature']); + $save_data['signature'] = rcmail_wash_html($save_data['signature']); - // clear POST data of signature, we want to use safe content - // when the form is displayed again - unset($_POST['_signature']); + // clear POST data of signature, we want to use safe content + // when the form is displayed again + unset($_POST['_signature']); } // update an existing contact if ($_POST['_iid']) { - $iid = rcube_utils::get_input_value('_iid', rcube_utils::INPUT_POST); - - if (in_array(IDENTITIES_LEVEL, array(1,3,4))) { - // merge with old identity data, fixes #1488834 - $identity = $RCMAIL->user->get_identity($iid); - $save_data = array_merge($identity, $save_data); - unset($save_data['changed'], $save_data['del'], $save_data['user_id'], $save_data['identity_id']); - } - - $plugin = $RCMAIL->plugins->exec_hook('identity_update', array('id' => $iid, 'record' => $save_data)); - $save_data = $plugin['record']; - - if ($save_data['email']) - $save_data['email'] = rcube_utils::idn_to_ascii($save_data['email']); - if (!$plugin['abort']) - $updated = $RCMAIL->user->update_identity($iid, $save_data); - else - $updated = $plugin['result']; - - if ($updated) { - $OUTPUT->show_message('successfullysaved', 'confirmation'); - - if (!empty($save_data['standard'])) - $default_id = $iid; - - if ($_POST['_framed']) { - // update the changed col in list - $OUTPUT->command('parent.update_identity_row', $iid, rcube::Q(trim($save_data['name'] . ' <' . rcube_utils::idn_to_utf8($save_data['email']) .'>'))); + $iid = rcube_utils::get_input_value('_iid', rcube_utils::INPUT_POST); + + if (in_array(IDENTITIES_LEVEL, array(1,3,4))) { + // merge with old identity data, fixes #1488834 + $identity = $RCMAIL->user->get_identity($iid); + $save_data = array_merge($identity, $save_data); + + unset($save_data['changed'], $save_data['del'], $save_data['user_id'], $save_data['identity_id']); + } + + $plugin = $RCMAIL->plugins->exec_hook('identity_update', array('id' => $iid, 'record' => $save_data)); + $save_data = $plugin['record']; + + if ($save_data['email']) { + $save_data['email'] = rcube_utils::idn_to_ascii($save_data['email']); } - } - else { - // show error message - $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error', null, false); - $RCMAIL->overwrite_action('edit-identity'); - return; - } -} + if (!$plugin['abort']) + $updated = $RCMAIL->user->update_identity($iid, $save_data); + else + $updated = $plugin['result']; + + if ($updated) { + $OUTPUT->show_message('successfullysaved', 'confirmation'); + + if (!empty($save_data['standard'])) { + $default_id = $iid; + } + + if ($_POST['_framed']) { + // update the changed col in list + $name = $save_data['name'] . ' <' . rcube_utils::idn_to_utf8($save_data['email']) .'>'; + $OUTPUT->command('parent.update_identity_row', $iid, rcube::Q(trim($name))); + } + } + else { + // show error message + $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error', null, false); + $RCMAIL->overwrite_action('edit-identity'); + return; + } +} // insert a new identity record else if (IDENTITIES_LEVEL < 2) { - if (IDENTITIES_LEVEL == 1) { - $save_data['email'] = $RCMAIL->get_user_email(); - } + if (IDENTITIES_LEVEL == 1) { + $save_data['email'] = $RCMAIL->get_user_email(); + } - $plugin = $RCMAIL->plugins->exec_hook('identity_create', array('record' => $save_data)); - $save_data = $plugin['record']; + $plugin = $RCMAIL->plugins->exec_hook('identity_create', array('record' => $save_data)); + $save_data = $plugin['record']; - if ($save_data['email']) - $save_data['email'] = rcube_utils::idn_to_ascii($save_data['email']); + if ($save_data['email']) { + $save_data['email'] = rcube_utils::idn_to_ascii($save_data['email']); + } - if (!$plugin['abort']) - $insert_id = $save_data['email'] ? $RCMAIL->user->insert_identity($save_data) : null; - else - $insert_id = $plugin['result']; + if (!$plugin['abort']) + $insert_id = $save_data['email'] ? $RCMAIL->user->insert_identity($save_data) : null; + else + $insert_id = $plugin['result']; - if ($insert_id) { - $OUTPUT->show_message('successfullysaved', 'confirmation', null, false); + if ($insert_id) { + $OUTPUT->show_message('successfullysaved', 'confirmation', null, false); - $_GET['_iid'] = $insert_id; + $_GET['_iid'] = $insert_id; - if (!empty($save_data['standard'])) - $default_id = $insert_id; + if (!empty($save_data['standard'])) { + $default_id = $insert_id; + } - if ($_POST['_framed']) { - // add a new row to the list - $OUTPUT->command('parent.update_identity_row', $insert_id, rcube::Q(trim($save_data['name'] . ' <' . rcube_utils::idn_to_utf8($save_data['email']) .'>')), true); + if ($_POST['_framed']) { + // add a new row to the list + $name = $save_data['name'] . ' <' . rcube_utils::idn_to_utf8($save_data['email']) .'>'; + $OUTPUT->command('parent.update_identity_row', $insert_id, rcube::Q(trim($name)), true); + } + } + else { + // show error message + $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error', null, false); + $RCMAIL->overwrite_action('edit-identity'); + return; } - } - else { - // show error message - $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error', null, false); - $RCMAIL->overwrite_action('edit-identity'); - return; - } } -else - $OUTPUT->show_message('opnotpermitted', 'error'); - +else { + $OUTPUT->show_message('opnotpermitted', 'error'); +} // mark all other identities as 'not-default' -if ($default_id) - $RCMAIL->user->set_default($default_id); +if ($default_id) { + $RCMAIL->user->set_default($default_id); +} // go to next step if (!empty($_REQUEST['_framed'])) { - $RCMAIL->overwrite_action('edit-identity'); + $RCMAIL->overwrite_action('edit-identity'); +} +else { + $RCMAIL->overwrite_action('identities'); } -else - $RCMAIL->overwrite_action('identities'); /** @@ -190,11 +202,11 @@ function rcmail_wash_html($html) // clean HTML with washhtml by Frederic Motte $wash_opts = array( - 'show_washed' => false, - 'allow_remote' => 1, - 'charset' => RCUBE_CHARSET, + 'show_washed' => false, + 'allow_remote' => 1, + 'charset' => RCUBE_CHARSET, 'html_elements' => array('body', 'link'), - 'html_attribs' => array('rel', 'type'), + 'html_attribs' => array('rel', 'type'), ); // initialize HTML washer @@ -211,5 +223,5 @@ function rcmail_wash_html($html) // remove unwanted comments and tags (produced by washtml) $html = preg_replace(array('/<!--[^>]+-->/', '/<\/?body>/'), '', $html); - return $html; + return $html; } diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index 325c66ae8..f71eee39a 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -5,7 +5,7 @@ | program/steps/settings/save_prefs.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -20,190 +20,190 @@ */ $CURR_SECTION = rcube_utils::get_input_value('_section', rcube_utils::INPUT_POST); - $a_user_prefs = array(); // set options for specified section -switch ($CURR_SECTION) -{ - case 'general': +switch ($CURR_SECTION) { +case 'general': $a_user_prefs = array( - 'language' => isset($_POST['_language']) ? rcube_utils::get_input_value('_language', rcube_utils::INPUT_POST) : $CONFIG['language'], - 'timezone' => isset($_POST['_timezone']) ? rcube_utils::get_input_value('_timezone', rcube_utils::INPUT_POST) : $CONFIG['timezone'], - 'date_format' => isset($_POST['_date_format']) ? rcube_utils::get_input_value('_date_format', rcube_utils::INPUT_POST) : $CONFIG['date_format'], - 'time_format' => isset($_POST['_time_format']) ? rcube_utils::get_input_value('_time_format', rcube_utils::INPUT_POST) : ($CONFIG['time_format'] ? $CONFIG['time_format'] : 'H:i'), - 'prettydate' => isset($_POST['_pretty_date']) ? TRUE : FALSE, - 'refresh_interval' => isset($_POST['_refresh_interval']) ? intval($_POST['_refresh_interval'])*60 : $CONFIG['refresh_interval'], - 'standard_windows' => isset($_POST['_standard_windows']) ? TRUE : FALSE, - 'skin' => isset($_POST['_skin']) ? rcube_utils::get_input_value('_skin', rcube_utils::INPUT_POST) : $CONFIG['skin'], + 'language' => isset($_POST['_language']) ? rcube_utils::get_input_value('_language', rcube_utils::INPUT_POST) : $CONFIG['language'], + 'timezone' => isset($_POST['_timezone']) ? rcube_utils::get_input_value('_timezone', rcube_utils::INPUT_POST) : $CONFIG['timezone'], + 'date_format' => isset($_POST['_date_format']) ? rcube_utils::get_input_value('_date_format', rcube_utils::INPUT_POST) : $CONFIG['date_format'], + 'time_format' => isset($_POST['_time_format']) ? rcube_utils::get_input_value('_time_format', rcube_utils::INPUT_POST) : ($CONFIG['time_format'] ? $CONFIG['time_format'] : 'H:i'), + 'prettydate' => isset($_POST['_pretty_date']) ? true : false, + 'refresh_interval' => isset($_POST['_refresh_interval']) ? intval($_POST['_refresh_interval'])*60 : $CONFIG['refresh_interval'], + 'standard_windows' => isset($_POST['_standard_windows']) ? true : false, + 'skin' => isset($_POST['_skin']) ? rcube_utils::get_input_value('_skin', rcube_utils::INPUT_POST) : $CONFIG['skin'], ); // compose derived date/time format strings if ((isset($_POST['_date_format']) || isset($_POST['_time_format'])) && $a_user_prefs['date_format'] && $a_user_prefs['time_format']) { - $a_user_prefs['date_short'] = 'D ' . $a_user_prefs['time_format']; - $a_user_prefs['date_long'] = $a_user_prefs['date_format'] . ' ' . $a_user_prefs['time_format']; + $a_user_prefs['date_short'] = 'D ' . $a_user_prefs['time_format']; + $a_user_prefs['date_long'] = $a_user_prefs['date_format'] . ' ' . $a_user_prefs['time_format']; } - break; + break; - case 'mailbox': +case 'mailbox': $a_user_prefs = array( - 'preview_pane' => isset($_POST['_preview_pane']) ? TRUE : FALSE, - 'preview_pane_mark_read' => isset($_POST['_preview_pane_mark_read']) ? intval($_POST['_preview_pane_mark_read']) : $CONFIG['preview_pane_mark_read'], - 'autoexpand_threads' => isset($_POST['_autoexpand_threads']) ? intval($_POST['_autoexpand_threads']) : 0, - 'mdn_requests' => isset($_POST['_mdn_requests']) ? intval($_POST['_mdn_requests']) : 0, - 'check_all_folders' => isset($_POST['_check_all_folders']) ? TRUE : FALSE, - 'mail_pagesize' => is_numeric($_POST['_mail_pagesize']) ? max(2, intval($_POST['_mail_pagesize'])) : $CONFIG['mail_pagesize'], + 'preview_pane' => isset($_POST['_preview_pane']) ? true : false, + 'preview_pane_mark_read' => isset($_POST['_preview_pane_mark_read']) ? intval($_POST['_preview_pane_mark_read']) : $CONFIG['preview_pane_mark_read'], + 'autoexpand_threads' => isset($_POST['_autoexpand_threads']) ? intval($_POST['_autoexpand_threads']) : 0, + 'mdn_requests' => isset($_POST['_mdn_requests']) ? intval($_POST['_mdn_requests']) : 0, + 'check_all_folders' => isset($_POST['_check_all_folders']) ? true : false, + 'mail_pagesize' => is_numeric($_POST['_mail_pagesize']) ? max(2, intval($_POST['_mail_pagesize'])) : $CONFIG['mail_pagesize'], ); - break; + break; - case 'mailview': +case 'mailview': $a_user_prefs = array( - 'message_extwin' => intval($_POST['_message_extwin']), - 'message_show_email' => isset($_POST['_message_show_email']) ? TRUE : FALSE, - 'prefer_html' => isset($_POST['_prefer_html']) ? TRUE : FALSE, - 'inline_images' => isset($_POST['_inline_images']) ? TRUE : FALSE, - 'show_images' => isset($_POST['_show_images']) ? intval($_POST['_show_images']) : 0, - 'display_next' => isset($_POST['_display_next']) ? TRUE : FALSE, - 'default_charset' => rcube_utils::get_input_value('_default_charset', rcube_utils::INPUT_POST), + 'message_extwin' => intval($_POST['_message_extwin']), + 'message_show_email' => isset($_POST['_message_show_email']) ? true : false, + 'prefer_html' => isset($_POST['_prefer_html']) ? true : false, + 'inline_images' => isset($_POST['_inline_images']) ? true : false, + 'show_images' => isset($_POST['_show_images']) ? intval($_POST['_show_images']) : 0, + 'display_next' => isset($_POST['_display_next']) ? true : false, + 'default_charset' => rcube_utils::get_input_value('_default_charset', rcube_utils::INPUT_POST), ); - break; + break; - case 'compose': +case 'compose': $a_user_prefs = array( - 'compose_extwin' => intval($_POST['_compose_extwin']), - 'htmleditor' => intval($_POST['_htmleditor']), - 'draft_autosave' => isset($_POST['_draft_autosave']) ? intval($_POST['_draft_autosave']) : 0, - 'mime_param_folding' => isset($_POST['_mime_param_folding']) ? intval($_POST['_mime_param_folding']) : 0, - 'force_7bit' => isset($_POST['_force_7bit']) ? TRUE : FALSE, - 'mdn_default' => isset($_POST['_mdn_default']) ? TRUE : FALSE, - 'dsn_default' => isset($_POST['_dsn_default']) ? TRUE : FALSE, - 'reply_same_folder' => isset($_POST['_reply_same_folder']) ? TRUE : FALSE, - 'spellcheck_before_send' => isset($_POST['_spellcheck_before_send']) ? TRUE : FALSE, - 'spellcheck_ignore_syms' => isset($_POST['_spellcheck_ignore_syms']) ? TRUE : FALSE, - 'spellcheck_ignore_nums' => isset($_POST['_spellcheck_ignore_nums']) ? TRUE : FALSE, - 'spellcheck_ignore_caps' => isset($_POST['_spellcheck_ignore_caps']) ? TRUE : FALSE, - 'show_sig' => isset($_POST['_show_sig']) ? intval($_POST['_show_sig']) : 1, - 'reply_mode' => isset($_POST['_reply_mode']) ? intval($_POST['_reply_mode']) : 0, - 'strip_existing_sig' => isset($_POST['_strip_existing_sig']), - 'default_font' => rcube_utils::get_input_value('_default_font', rcube_utils::INPUT_POST), - 'default_font_size' => rcube_utils::get_input_value('_default_font_size', rcube_utils::INPUT_POST), - 'reply_all_mode' => intval($_POST['_reply_all_mode']), - 'forward_attachment' => !empty($_POST['_forward_attachment']), + 'compose_extwin' => intval($_POST['_compose_extwin']), + 'htmleditor' => intval($_POST['_htmleditor']), + 'draft_autosave' => isset($_POST['_draft_autosave']) ? intval($_POST['_draft_autosave']) : 0, + 'mime_param_folding' => isset($_POST['_mime_param_folding']) ? intval($_POST['_mime_param_folding']) : 0, + 'force_7bit' => isset($_POST['_force_7bit']) ? true : false, + 'mdn_default' => isset($_POST['_mdn_default']) ? true : false, + 'dsn_default' => isset($_POST['_dsn_default']) ? true : false, + 'reply_same_folder' => isset($_POST['_reply_same_folder']) ? true : false, + 'spellcheck_before_send' => isset($_POST['_spellcheck_before_send']) ? true : false, + 'spellcheck_ignore_syms' => isset($_POST['_spellcheck_ignore_syms']) ? true : false, + 'spellcheck_ignore_nums' => isset($_POST['_spellcheck_ignore_nums']) ? true : false, + 'spellcheck_ignore_caps' => isset($_POST['_spellcheck_ignore_caps']) ? true : false, + 'show_sig' => isset($_POST['_show_sig']) ? intval($_POST['_show_sig']) : 1, + 'reply_mode' => isset($_POST['_reply_mode']) ? intval($_POST['_reply_mode']) : 0, + 'strip_existing_sig' => isset($_POST['_strip_existing_sig']), + 'default_font' => rcube_utils::get_input_value('_default_font', rcube_utils::INPUT_POST), + 'default_font_size' => rcube_utils::get_input_value('_default_font_size', rcube_utils::INPUT_POST), + 'reply_all_mode' => intval($_POST['_reply_all_mode']), + 'forward_attachment' => !empty($_POST['_forward_attachment']), ); - break; + break; - case 'addressbook': +case 'addressbook': $a_user_prefs = array( - 'default_addressbook' => rcube_utils::get_input_value('_default_addressbook', rcube_utils::INPUT_POST, true), - 'autocomplete_single' => isset($_POST['_autocomplete_single']) ? TRUE : FALSE, - 'addressbook_sort_col' => rcube_utils::get_input_value('_addressbook_sort_col', rcube_utils::INPUT_POST), - 'addressbook_name_listing' => intval(rcube_utils::get_input_value('_addressbook_name_listing', rcube_utils::INPUT_POST)), - 'addressbook_pagesize' => is_numeric($_POST['_addressbook_pagesize']) ? max(2, intval($_POST['_addressbook_pagesize'])) : $CONFIG['addressbook_pagesize'], + 'default_addressbook' => rcube_utils::get_input_value('_default_addressbook', rcube_utils::INPUT_POST, true), + 'autocomplete_single' => isset($_POST['_autocomplete_single']) ? true : false, + 'addressbook_sort_col' => rcube_utils::get_input_value('_addressbook_sort_col', rcube_utils::INPUT_POST), + 'addressbook_name_listing' => intval(rcube_utils::get_input_value('_addressbook_name_listing', rcube_utils::INPUT_POST)), + 'addressbook_pagesize' => is_numeric($_POST['_addressbook_pagesize']) ? max(2, intval($_POST['_addressbook_pagesize'])) : $CONFIG['addressbook_pagesize'], ); - break; + break; - case 'server': +case 'server': $a_user_prefs = array( - 'read_when_deleted' => isset($_POST['_read_when_deleted']) ? TRUE : FALSE, - 'skip_deleted' => isset($_POST['_skip_deleted']) ? TRUE : FALSE, - 'flag_for_deletion' => isset($_POST['_flag_for_deletion']) ? TRUE : FALSE, - 'delete_always' => isset($_POST['_delete_always']) ? TRUE : FALSE, - 'delete_junk' => isset($_POST['_delete_junk']) ? TRUE : FALSE, - 'logout_purge' => isset($_POST['_logout_purge']) ? TRUE : FALSE, - 'logout_expunge' => isset($_POST['_logout_expunge']) ? TRUE : FALSE, + 'read_when_deleted' => isset($_POST['_read_when_deleted']) ? true : false, + 'skip_deleted' => isset($_POST['_skip_deleted']) ? true : false, + 'flag_for_deletion' => isset($_POST['_flag_for_deletion']) ? true : false, + 'delete_always' => isset($_POST['_delete_always']) ? true : false, + 'delete_junk' => isset($_POST['_delete_junk']) ? true : false, + 'logout_purge' => isset($_POST['_logout_purge']) ? true : false, + 'logout_expunge' => isset($_POST['_logout_expunge']) ? true : false, ); - break; + break; - case 'folders': +case 'folders': $a_user_prefs = array( - 'show_real_foldernames' => - isset($_POST['_show_real_foldernames']) ? TRUE : FALSE, - 'drafts_mbox' => rcube_utils::get_input_value('_drafts_mbox', rcube_utils::INPUT_POST, true), - 'sent_mbox' => rcube_utils::get_input_value('_sent_mbox', rcube_utils::INPUT_POST, true), - 'junk_mbox' => rcube_utils::get_input_value('_junk_mbox', rcube_utils::INPUT_POST, true), - 'trash_mbox' => rcube_utils::get_input_value('_trash_mbox', rcube_utils::INPUT_POST, true), + 'show_real_foldernames' => isset($_POST['_show_real_foldernames']) ? true : false, + 'drafts_mbox' => rcube_utils::get_input_value('_drafts_mbox', rcube_utils::INPUT_POST, true), + 'sent_mbox' => rcube_utils::get_input_value('_sent_mbox', rcube_utils::INPUT_POST, true), + 'junk_mbox' => rcube_utils::get_input_value('_junk_mbox', rcube_utils::INPUT_POST, true), + 'trash_mbox' => rcube_utils::get_input_value('_trash_mbox', rcube_utils::INPUT_POST, true), ); - break; + break; } $plugin = rcmail::get_instance()->plugins->exec_hook('preferences_save', - array('prefs' => $a_user_prefs, 'section' => $CURR_SECTION)); + array('prefs' => $a_user_prefs, 'section' => $CURR_SECTION)); $a_user_prefs = $plugin['prefs']; // don't override these parameters -foreach ((array)$CONFIG['dont_override'] as $p) - $a_user_prefs[$p] = $CONFIG[$p]; +foreach ((array)$CONFIG['dont_override'] as $p) { + $a_user_prefs[$p] = $CONFIG[$p]; +} // verify some options -switch ($CURR_SECTION) -{ - case 'general': - +switch ($CURR_SECTION) { +case 'general': // switch UI language if (isset($_POST['_language']) && $a_user_prefs['language'] != $_SESSION['language']) { - $RCMAIL->load_language($a_user_prefs['language']); - $OUTPUT->command('reload', 500); + $RCMAIL->load_language($a_user_prefs['language']); + $OUTPUT->command('reload', 500); } // switch skin (if valid, otherwise unset the pref and fall back to default) if (!$OUTPUT->set_skin($a_user_prefs['skin'])) - unset($a_user_prefs['skin']); + unset($a_user_prefs['skin']); else if ($RCMAIL->config->get('skin') != $a_user_prefs['skin']) - $OUTPUT->command('reload', 500); + $OUTPUT->command('reload', 500); $a_user_prefs['timezone'] = (string) $a_user_prefs['timezone']; if (!empty($a_user_prefs['refresh_interval']) && !empty($CONFIG['min_refresh_interval'])) { - if ($a_user_prefs['refresh_interval'] < $CONFIG['min_refresh_interval']) { - $a_user_prefs['refresh_interval'] = $CONFIG['min_refresh_interval']; - } + if ($a_user_prefs['refresh_interval'] < $CONFIG['min_refresh_interval']) { + $a_user_prefs['refresh_interval'] = $CONFIG['min_refresh_interval']; + } } break; - case 'mailbox': - +case 'mailbox': // force min size - if ($a_user_prefs['mail_pagesize'] < 1) - $a_user_prefs['mail_pagesize'] = 10; + if ($a_user_prefs['mail_pagesize'] < 1) { + $a_user_prefs['mail_pagesize'] = 10; + } - if (isset($CONFIG['max_pagesize']) && ($a_user_prefs['mail_pagesize'] > $CONFIG['max_pagesize'])) - $a_user_prefs['mail_pagesize'] = (int) $CONFIG['max_pagesize']; + if (isset($CONFIG['max_pagesize']) && ($a_user_prefs['mail_pagesize'] > $CONFIG['max_pagesize'])) { + $a_user_prefs['mail_pagesize'] = (int) $CONFIG['max_pagesize']; + } break; - case 'addressbook': - +case 'addressbook': // force min size - if ($a_user_prefs['addressbook_pagesize'] < 1) - $a_user_prefs['addressbook_pagesize'] = 10; + if ($a_user_prefs['addressbook_pagesize'] < 1) { + $a_user_prefs['addressbook_pagesize'] = 10; + } - if (isset($CONFIG['max_pagesize']) && ($a_user_prefs['addressbook_pagesize'] > $CONFIG['max_pagesize'])) - $a_user_prefs['addressbook_pagesize'] = (int) $CONFIG['max_pagesize']; + if (isset($CONFIG['max_pagesize']) && ($a_user_prefs['addressbook_pagesize'] > $CONFIG['max_pagesize'])) { + $a_user_prefs['addressbook_pagesize'] = (int) $CONFIG['max_pagesize']; + } break; - case 'folders': - +case 'folders': // special handling for 'default_folders' if (in_array('default_folders', (array)$CONFIG['dont_override'])) { - foreach (array('drafts_mbox','sent_mbox','junk_mbox','trash_mbox') as $p) - $a_user_prefs[$p] = $CONFIG[$p]; - } else { - $a_user_prefs['default_folders'] = array('INBOX'); - foreach (array('drafts_mbox','sent_mbox','junk_mbox','trash_mbox') as $p) { - if ($a_user_prefs[$p]) - $a_user_prefs['default_folders'][] = $a_user_prefs[$p]; - } + foreach (array('drafts_mbox','sent_mbox','junk_mbox','trash_mbox') as $p) { + $a_user_prefs[$p] = $CONFIG[$p]; + } + } + else { + $a_user_prefs['default_folders'] = array('INBOX'); + foreach (array('drafts_mbox','sent_mbox','junk_mbox','trash_mbox') as $p) { + if ($a_user_prefs[$p]) { + $a_user_prefs['default_folders'][] = $a_user_prefs[$p]; + } + } } break; @@ -211,14 +211,14 @@ switch ($CURR_SECTION) // Save preferences if (!$plugin['abort']) - $saved = $RCMAIL->user->save_prefs($a_user_prefs); + $saved = $RCMAIL->user->save_prefs($a_user_prefs); else - $saved = $plugin['result']; + $saved = $plugin['result']; if ($saved) - $OUTPUT->show_message('successfullysaved', 'confirmation'); + $OUTPUT->show_message('successfullysaved', 'confirmation'); else - $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error'); + $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error'); // display the form again $RCMAIL->overwrite_action('edit-prefs'); |