diff options
author | Aleksander Machniak <alec@alec.pl> | 2020-11-01 13:25:38 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-01 13:25:38 +0300 |
commit | 545a1569f115b5c8aa0be78061258d5f116d7b4b (patch) | |
tree | a76645a856cf148f839a74a9de5cedd21054922e /program/include/rcmail.php | |
parent | 2829f302755f8492fb095735f3fc89688727e1a3 (diff) |
Steps -> Actions refactoring (#7688)
* Move action handling code to rcmail class
* Add rcmail_action class
* Add action aliases
* Get rid of $OUTPUT global
* Move some methods from rcmail to rcmail_action
* PHP8 compat. fixes
* Add framework for testing actions
* Fix obvious code mistakes
Diffstat (limited to 'program/include/rcmail.php')
-rw-r--r-- | program/include/rcmail.php | 1180 |
1 files changed, 145 insertions, 1035 deletions
diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 7d30673ad..f0ca1d275 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -52,10 +52,11 @@ class rcmail extends rcube public $filename = ''; public $default_skin; public $login_error; + public $oauth; - private $address_books = array(); - private $action_map = array(); - + private $address_books = []; + private $action_map = []; + private $action_args = []; const ERROR_STORAGE = -2; const ERROR_INVALID_REQUEST = 1; @@ -136,10 +137,10 @@ class rcmail extends rcube // init output class (not in CLI mode) if (!empty($_REQUEST['_remote'])) { - $GLOBALS['OUTPUT'] = $this->json_init(); + $this->json_init(); } else if (!empty($_SERVER['REMOTE_ADDR'])) { - $GLOBALS['OUTPUT'] = $this->load_gui(!empty($_REQUEST['_framed'])); + $this->load_gui(!empty($_REQUEST['_framed'])); } // load oauth manager @@ -209,6 +210,87 @@ class rcmail extends rcube } /** + * Handle the request. All request pre-checks are NOT done here. + */ + public function action_handler() + { + // we're ready, user is authenticated and the request is safe + $plugin = $this->plugins->exec_hook('ready', ['task' => $this->task, 'action' => $this->action]); + + $this->set_task($plugin['task']); + $this->action = $plugin['action']; + + // handle special actions + if ($this->action == 'keep-alive') { + $this->output->reset(); + $this->plugins->exec_hook('keep_alive', []); + $this->output->send(); + } + + $task = $this->action == 'save-pref' ? 'utils' : $this->task; + $task = $task == 'addressbook' ? 'contacts' : $task; + $task_class = "rcmail_action_{$task}_index"; + + // execute the action index handler + if (class_exists($task_class)) { + $task_handler = new $task_class; + $task_handler->run(); + } + + // allow 5 "redirects" to another action + $redirects = 0; + while ($redirects < 5) { + // execute a plugin action + if (preg_match('/^plugin\./', $this->action)) { + $this->plugins->exec_action($this->action); + break; + } + + // execute action registered to a plugin task + if ($this->plugins->is_plugin_task($this->task)) { + if (!$this->action) $this->action = 'index'; + $this->plugins->exec_action("{$this->task}.{$this->action}"); + break; + } + + $action = !empty($this->action) ? $this->action : 'index'; + + // handle deprecated action names + if (!empty($task_handler) && !empty($task_handler::$aliases[$action])) { + $action = $task_handler::$aliases[$action]; + } + + $action = str_replace('-', '_', $action); + $class = "rcmail_action_{$task}_{$action}"; + + // Run the action (except the index) + if ($class != $task_class && class_exists($class)) { + $handler = new $class; + if (!$handler->checks()) { + break; + } + $handler->run($this->action_args); + $redirects++; + } + else { + break; + } + } + + if ($this->action == 'refresh') { + $last = intval(rcube_utils::get_input_value('_last', rcube_utils::INPUT_GPC)); + $this->plugins->exec_hook('refresh', ['last' => $last]); + } + + // parse main template (default) + $this->output->send($this->task); + + // if we arrive here, something went wrong + $error = ['code' => 404, 'line' => __LINE__, 'file' => __FILE__, 'message' => "Invalid request"]; + rcmail::raise_error($error, true, true); + } + + /** * Return instance of the internal address book class * * @param string $id Address book identifier. It accepts also special values: @@ -514,7 +596,7 @@ class rcmail extends rcube public function json_init() { if (!($this->output instanceof rcmail_output_json)) { - $this->output = new rcmail_output_json($this->task); + $this->output = new rcmail_output_json(); } return $this->output; @@ -1055,34 +1137,6 @@ class rcmail extends rcube } /** - * 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]; - } - - 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. @@ -1184,10 +1238,12 @@ class rcmail extends rcube * Overwrite action variable * * @param string $action New action value + * @param array $args Arguments to be passed to the next action */ - public function overwrite_action($action) + public function overwrite_action($action, $args = []) { - $this->action = $action; + $this->action = $action; + $this->action_args = array_merge($this->action_args, $args); $this->output->set_env('action', $action); } @@ -1195,14 +1251,12 @@ class rcmail extends rcube * Set environment variables for specified config options * * @param array $options List of configuration option names + * + * @deprecated since 1.5-beta, use rcmail_action::set_env_config() */ public function set_env_config($options) { - foreach ((array) $options as $option) { - if ($this->config->get($option)) { - $this->output->set_env($option, true); - } - } + rcmail_action::set_env_config($options); } /** @@ -1420,47 +1474,11 @@ class rcmail extends rcube * @param string $id_col Name of the identifier col * * @return string HTML table code + * @deprecated since 1.5-beta, use rcmail_action::table_output() */ public function table_output($attrib, $table_data, $show_cols, $id_col) { - $table = new html_table($attrib); - - // add table header - if (!$attrib['noheader']) { - foreach ($show_cols as $col) { - $table->add_header($col, $this->Q($this->gettext($col))); - } - } - - if (!is_array($table_data)) { - $db = $this->get_dbh(); - while ($table_data && ($sql_arr = $db->fetch_assoc($table_data))) { - $table->add_row(array('id' => 'rcmrow' . rcube_utils::html_identifier($sql_arr[$id_col]))); - - // format each col - foreach ($show_cols as $col) { - $table->add($col, $this->Q($sql_arr[$col])); - } - } - } - else { - foreach ($table_data as $row_data) { - $class = !empty($row_data['class']) ? $row_data['class'] : null; - if (!empty($attrib['rowclass'])) - $class = trim($class . ' ' . $attrib['rowclass']); - $rowid = 'rcmrow' . rcube_utils::html_identifier($row_data[$id_col]); - - $table->add_row(array('id' => $rowid, 'class' => $class)); - - // format each col - foreach ($show_cols as $col) { - $val = is_array($row_data[$col]) ? $row_data[$col][0] : $row_data[$col]; - $table->add($col, empty($attrib['ishtml']) ? $this->Q($val) : $val); - } - } - } - - return $table->show($attrib); + return rcmail_action::table_output($attrib, $table_data, $show_cols, $id_col); } /** @@ -1600,96 +1618,11 @@ class rcmail extends rcube * @param array $attrib Named parameters * * @return string HTML code for the gui object + * @deprecated since 1.5-beta, use rcmail_action::folder_list() */ public function folder_list($attrib) { - static $a_mailboxes; - - $attrib += array('maxlength' => 100, 'realnames' => false, 'unreadwrap' => ' (%s)'); - - $type = !empty($attrib['type']) ? $attrib['type'] : 'ul'; - unset($attrib['type']); - - if ($type == 'ul' && empty($attrib['id'])) { - $attrib['id'] = 'rcmboxlist'; - } - - if (empty($attrib['folder_name'])) { - $attrib['folder_name'] = '*'; - } - - // get current folder - $storage = $this->get_storage(); - $mbox_name = $storage->get_folder(); - $delimiter = $storage->get_hierarchy_delimiter(); - - // build the folders tree - if (empty($a_mailboxes)) { - // get mailbox list - $a_mailboxes = array(); - $a_folders = $storage->list_folders_subscribed( - '', - $attrib['folder_name'], - isset($attrib['folder_filter']) ? $attrib['folder_filter'] : null - ); - - foreach ($a_folders as $folder) { - $this->build_folder_tree($a_mailboxes, $folder, $delimiter); - } - } - - // allow plugins to alter the folder tree or to localize folder names - $hook = $this->plugins->exec_hook('render_mailboxlist', array( - 'list' => $a_mailboxes, - 'delimiter' => $delimiter, - 'type' => $type, - 'attribs' => $attrib, - )); - - $a_mailboxes = $hook['list']; - $attrib = $hook['attribs']; - - if ($type == 'select') { - $attrib['is_escaped'] = true; - $select = new html_select($attrib); - - // add no-selection option - if (!empty($attrib['noselection'])) { - $select->add(html::quote($this->gettext($attrib['noselection'])), ''); - } - - $maxlength = isset($attrib['maxlength']) ? $attrib['maxlength'] : null; - $realnames = isset($attrib['realnames']) ? $attrib['realnames'] : null; - $default = isset($attrib['default']) ? $attrib['default'] : null; - - $this->render_folder_tree_select($a_mailboxes, $mbox_name, $maxlength, $select, $realnames); - $out = $select->show($default); - } - else { - $out = ''; - $js_mailboxlist = array(); - $tree = $this->render_folder_tree_html($a_mailboxes, $mbox_name, $js_mailboxlist, $attrib); - - if ($type != 'js') { - $out = html::tag('ul', $attrib, $tree, html::$common_attrib); - - $this->output->include_script('treelist.js'); - $this->output->add_gui_object('mailboxlist', $attrib['id']); - $this->output->set_env('unreadwrap', isset($attrib['unreadwrap']) ? $attrib['unreadwrap'] : false); - $this->output->set_env('collapsed_folders', (string) $this->config->get('collapsed_folders')); - } - - $this->output->set_env('mailboxes', $js_mailboxlist); - - // we can't use object keys in javascript because they are unordered - // we need sorted folders list for folder-selector widget - $this->output->set_env('mailboxes_list', array_keys($js_mailboxlist)); - } - - // add some labels to client - $this->output->add_label('purgefolderconfirm', 'deletemessagesconfirm'); - - return $out; + return rcmail_action::folder_list($attrib); } /** @@ -1698,268 +1631,11 @@ class rcmail extends rcube * @param array $p Named parameters * * @return html_select HTML drop-down object + * @deprecated since 1.5-beta, use rcmail_action::folder_selector() */ - public function folder_selector($p = array()) - { - $realnames = $this->config->get('show_real_foldernames'); - $p += array('maxlength' => 100, 'realnames' => $realnames, 'is_escaped' => true); - $a_mailboxes = array(); - $storage = $this->get_storage(); - - if (empty($p['folder_name'])) { - $p['folder_name'] = '*'; - } - - if ($p['unsubscribed']) { - $list = $storage->list_folders('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']); - } - else { - $list = $storage->list_folders_subscribed('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']); - } - - $delimiter = $storage->get_hierarchy_delimiter(); - - if (!empty($p['exceptions'])) { - $list = array_diff($list, (array) $p['exceptions']); - } - - if (!empty($p['additional'])) { - foreach ($p['additional'] as $add_folder) { - $add_items = explode($delimiter, $add_folder); - $folder = ''; - while (count($add_items)) { - $folder .= array_shift($add_items); - - // @TODO: sorting - if (!in_array($folder, $list)) { - $list[] = $folder; - } - - $folder .= $delimiter; - } - } - } - - foreach ($list as $folder) { - $this->build_folder_tree($a_mailboxes, $folder, $delimiter); - } - - // allow plugins to alter the folder tree or to localize folder names - $hook = $this->plugins->exec_hook('render_folder_selector', array( - 'list' => $a_mailboxes, - 'delimiter' => $delimiter, - 'attribs' => $p, - )); - - $a_mailboxes = $hook['list']; - $p = $hook['attribs']; - - $select = new html_select($p); - - if ($p['noselection']) { - $select->add(html::quote($p['noselection']), ''); - } - - $this->render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p); - - return $select; - } - - /** - * Create a hierarchical array of the mailbox list - */ - public function build_folder_tree(&$arrFolders, $folder, $delm = '/', $path = '') + public function folder_selector($p = []) { - // Handle namespace prefix - $prefix = ''; - if (!$path) { - $n_folder = $folder; - $folder = $this->storage->mod_folder($folder); - - if ($n_folder != $folder) { - $prefix = substr($n_folder, 0, -strlen($folder)); - } - } - - $pos = strpos($folder, $delm); - - if ($pos !== false) { - $subFolders = substr($folder, $pos+1); - $currentFolder = substr($folder, 0, $pos); - - // sometimes folder has a delimiter as the last character - if (!strlen($subFolders)) { - $virtual = false; - } - else if (!isset($arrFolders[$currentFolder])) { - $virtual = true; - } - else { - $virtual = $arrFolders[$currentFolder]['virtual']; - } - } - else { - $subFolders = false; - $currentFolder = $folder; - $virtual = false; - } - - $path .= $prefix . $currentFolder; - - if (!isset($arrFolders[$currentFolder])) { - $arrFolders[$currentFolder] = array( - 'id' => $path, - 'name' => rcube_charset::convert($currentFolder, 'UTF7-IMAP'), - 'virtual' => $virtual, - 'folders' => array() - ); - } - else { - $arrFolders[$currentFolder]['virtual'] = $virtual; - } - - if (strlen($subFolders)) { - $this->build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm); - } - } - - /** - * Return html for a structured list <ul> for the mailbox tree - */ - public function render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $attrib, $nestLevel = 0) - { - $maxlength = intval($attrib['maxlength']); - $realnames = (bool)$attrib['realnames']; - $msgcounts = $this->storage->get_cache('messagecount'); - $collapsed = $this->config->get('collapsed_folders'); - $realnames = $this->config->get('show_real_foldernames'); - - $out = ''; - foreach ($arrFolders as $folder) { - $title = null; - $folder_class = $this->folder_classname($folder['id']); - $is_collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false; - $unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0; - - if ($folder_class && !$realnames && $this->text_exists($folder_class)) { - $foldername = $this->gettext($folder_class); - } - else { - $foldername = $folder['name']; - - // shorten the folder name to a given length - if ($maxlength && $maxlength > 1) { - $fname = abbreviate_string($foldername, $maxlength); - if ($fname != $foldername) { - $title = $foldername; - } - $foldername = $fname; - } - } - - // make folder name safe for ids and class names - $folder_id = rcube_utils::html_identifier($folder['id'], true); - $classes = array('mailbox'); - - // set special class for Sent, Drafts, Trash and Junk - if ($folder_class) { - $classes[] = $folder_class; - } - - if ($folder['id'] == $mbox_name) { - $classes[] = 'selected'; - } - - if ($folder['virtual']) { - $classes[] = 'virtual'; - } - else if ($unread) { - $classes[] = 'unread'; - } - - $js_name = $this->JQ($folder['id']); - $html_name = $this->Q($foldername) . ($unread ? html::span('unreadcount skip-content', sprintf($attrib['unreadwrap'], $unread)) : ''); - $link_attrib = $folder['virtual'] ? array() : array( - 'href' => $this->url(array('_mbox' => $folder['id'])), - 'onclick' => sprintf("return %s.command('list','%s',this,event)", rcmail_output::JS_OBJECT_NAME, $js_name), - 'rel' => $folder['id'], - 'title' => $title, - ); - - $out .= html::tag('li', array( - 'id' => "rcmli" . $folder_id, - 'class' => implode(' ', $classes), - 'noclose' => true - ), - html::a($link_attrib, $html_name)); - - if (!empty($folder['folders'])) { - $out .= html::div('treetoggle ' . ($is_collapsed ? 'collapsed' : 'expanded'), ' '); - } - - $jslist[$folder['id']] = array( - 'id' => $folder['id'], - 'name' => $foldername, - 'virtual' => $folder['virtual'], - ); - - if (!empty($folder_class)) { - $jslist[$folder['id']]['class'] = $folder_class; - } - - if (!empty($folder['folders'])) { - $out .= html::tag('ul', array('style' => ($is_collapsed ? "display:none;" : null)), - $this->render_folder_tree_html($folder['folders'], $mbox_name, $jslist, $attrib, $nestLevel+1)); - } - - $out .= "</li>\n"; - } - - return $out; - } - - /** - * Return html for a flat list <select> for the mailbox tree - */ - public function render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames = false, $nestLevel = 0, $opts = array()) - { - $out = ''; - - foreach ($arrFolders as $folder) { - // skip exceptions (and its subfolders) - if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) { - continue; - } - - // skip folders in which it isn't possible to create subfolders - if (!empty($opts['skip_noinferiors'])) { - $attrs = $this->storage->folder_attributes($folder['id']); - if ($attrs && in_array_nocase('\\Noinferiors', $attrs)) { - continue; - } - } - - if (!$realnames && ($folder_class = $this->folder_classname($folder['id'])) && $this->text_exists($folder_class)) { - $foldername = $this->gettext($folder_class); - } - else { - $foldername = $folder['name']; - - // shorten the folder name to a given length - if ($maxlength && $maxlength > 1) { - $foldername = abbreviate_string($foldername, $maxlength); - } - } - - $select->add(str_repeat(' ', $nestLevel*4) . html::quote($foldername), $folder['id']); - - if (!empty($folder['folders'])) { - $out .= $this->render_folder_tree_select($folder['folders'], $mbox_name, $maxlength, - $select, $realnames, $nestLevel+1, $opts); - } - } - - return $out; + return rcmail_action::folder_selector($p); } /** @@ -1969,37 +1645,11 @@ class rcmail extends rcube * @param string $folder_id IMAP Folder name * * @return string|null CSS class name + * @deprecated since 1.5-beta, use rcmail_action::folder_classname() */ public function folder_classname($folder_id) { - static $classes; - - if ($classes === null) { - $classes = array('INBOX' => 'inbox'); - - // for these mailboxes we have css classes - foreach (array('sent', 'drafts', 'trash', 'junk') as $type) { - if (($mbox = $this->config->get($type . '_mbox')) && !isset($classes[$mbox])) { - $classes[$mbox] = $type; - } - } - - $storage = $this->get_storage(); - - // add classes for shared/other user namespace roots - foreach (array('other', 'shared') as $ns_name) { - if ($ns = $storage->get_namespace($ns_name)) { - foreach ($ns as $root) { - $root = substr($root[0], 0, -1); - if (strlen($root) && !isset($classes[$root])) { - $classes[$root] = "ns-$ns_name"; - } - } - } - } - } - - return !empty($classes[$folder_id]) ? $classes[$folder_id] : null; + return rcmail_action::folder_classname($folder_id); } /** @@ -2011,70 +1661,21 @@ class rcmail extends rcube * @param bool $path_remove Remove the path * * @return string Localized folder name in UTF-8 encoding + * @deprecated since 1.5-beta, use rcmail_action::localize_foldername() */ public function localize_foldername($name, $with_path = false, $path_remove = false) { - $realnames = $this->config->get('show_real_foldernames'); - - if (!$realnames && ($folder_class = $this->folder_classname($name)) && $this->text_exists($folder_class)) { - return $this->gettext($folder_class); - } - - $storage = $this->get_storage(); - $delimiter = $storage->get_hierarchy_delimiter(); - - // Remove the path - if ($path_remove) { - if (strpos($name, $delimiter)) { - $path = explode($delimiter, $name); - $name = array_pop($path); - } - } - // try to localize path of the folder - else if ($with_path && !$realnames) { - $path = explode($delimiter, $name); - $count = count($path); - - if ($count > 1) { - for ($i = 1; $i < $count; $i++) { - $folder = implode($delimiter, array_slice($path, 0, -$i)); - $folder_class = $this->folder_classname($folder); - - if ($folder_class && $this->text_exists($folder_class)) { - $name = implode($delimiter, array_slice($path, $count - $i)); - $name = rcube_charset::convert($name, 'UTF7-IMAP'); - - return $this->gettext($folder_class) . $delimiter . $name; - } - } - } - } - - return rcube_charset::convert($name, 'UTF7-IMAP'); + return rcmail_action::localize_foldername($name, $with_path, $path_remove); } /** * Localize folder path + * + * @deprecated since 1.5-beta, use rcmail_action::localize_folderpath() */ public function localize_folderpath($path) { - $protect_folders = $this->config->get('protect_default_folders'); - $delimiter = $this->storage->get_hierarchy_delimiter(); - $path = explode($delimiter, $path); - $result = array(); - - foreach ($path as $idx => $dir) { - $directory = implode($delimiter, array_slice($path, 0, $idx+1)); - if ($protect_folders && $this->storage->is_special_folder($directory)) { - unset($result); - $result[] = $this->localize_foldername($directory); - } - else { - $result[] = rcube_charset::convert($dir, 'UTF7-IMAP'); - } - } - - return implode($delimiter, $result); + return rcmail_action::localize_folderpath($path); } /** @@ -2083,24 +1684,11 @@ class rcmail extends rcube * @param array $attrib Named parameters * * @return string HTML code for the quota indicator object + * @deprecated since 1.5-beta, use rcmail_action::quota_display() */ public static function quota_display($attrib) { - $rcmail = rcmail::get_instance(); - - if (empty($attrib['id'])) { - $attrib['id'] = 'rcmquotadisplay'; - } - - $_SESSION['quota_display'] = !empty($attrib['display']) ? $attrib['display'] : 'text'; - - $rcmail->output->add_gui_object('quotadisplay', $attrib['id']); - - $quota = $rcmail->quota_content($attrib); - - $rcmail->output->add_script('rcmail.set_quota('.rcube_output::json_serialize($quota).');', 'docready'); - - return html::span($attrib, ' '); + return rcmail_action::quota_display($attrib); } /** @@ -2110,81 +1698,11 @@ class rcmail extends rcube * @param array $folder Current folder * * @return array Quota information + * @deprecated since 1.5-beta, use rcmail_action::quota_content() */ public function quota_content($attrib = null, $folder = null) { - $quota = $this->storage->get_quota($folder); - $quota = $this->plugins->exec_hook('quota', $quota); - - $quota_result = (array) $quota; - $quota_result['type'] = isset($_SESSION['quota_display']) ? $_SESSION['quota_display'] : ''; - $quota_result['folder'] = $folder !== null && $folder !== '' ? $folder : 'INBOX'; - - if ($quota['total'] > 0) { - if (!isset($quota['percent'])) { - $quota_result['percent'] = min(100, round(($quota['used']/max(1,$quota['total']))*100)); - } - - $title = $this->gettext('quota') . ': ' . sprintf('%s / %s (%.0f%%)', - $this->show_bytes($quota['used'] * 1024), - $this->show_bytes($quota['total'] * 1024), - $quota_result['percent'] - ); - - $quota_result['title'] = $title; - - if (!empty($attrib['width'])) { - $quota_result['width'] = $attrib['width']; - } - if (!empty($attrib['height'])) { - $quota_result['height'] = $attrib['height']; - } - - // build a table of quota types/roots info - if (($root_cnt = count($quota_result['all'])) > 1 || count($quota_result['all'][key($quota_result['all'])]) > 1) { - $table = new html_table(array('cols' => 3, 'class' => 'quota-info')); - - $table->add_header(null, self::Q($this->gettext('quotatype'))); - $table->add_header(null, self::Q($this->gettext('quotatotal'))); - $table->add_header(null, self::Q($this->gettext('quotaused'))); - - foreach ($quota_result['all'] as $root => $data) { - if ($root_cnt > 1 && $root) { - $table->add(array('colspan' => 3, 'class' => 'root'), self::Q($root)); - } - - if ($storage = $data['storage']) { - $percent = min(100, round(($storage['used']/max(1,$storage['total']))*100)); - - $table->add('name', self::Q($this->gettext('quotastorage'))); - $table->add(null, $this->show_bytes($storage['total'] * 1024)); - $table->add(null, sprintf('%s (%.0f%%)', $this->show_bytes($storage['used'] * 1024), $percent)); - } - if ($message = $data['message']) { - $percent = min(100, round(($message['used']/max(1,$message['total']))*100)); - - $table->add('name', self::Q($this->gettext('quotamessage'))); - $table->add(null, intval($message['total'])); - $table->add(null, sprintf('%d (%.0f%%)', $message['used'], $percent)); - } - } - - $quota_result['table'] = $table->show(); - } - } - else { - $unlimited = $this->config->get('quota_zero_as_unlimited'); - $quota_result['title'] = $this->gettext($unlimited ? 'unlimited' : 'unknown'); - $quota_result['percent'] = 0; - } - - // cleanup - unset($quota_result['abort']); - if (empty($quota_result['table'])) { - unset($quota_result['all']); - } - - return $quota_result; + return rcmail_action::quota_content($attrib, $folder); } /** @@ -2194,170 +1712,34 @@ class rcmail extends rcube * @param array $fallback_args Fallback message label arguments * @param string $suffix Message label suffix * @param array $params Additional parameters (type, prefix) + * + * @deprecated since 1.5-beta, use rcmail_action::display_server_error() */ - public function display_server_error($fallback = null, $fallback_args = null, $suffix = '', $params = array()) + public function display_server_error($fallback = null, $fallback_args = null, $suffix = '', $params = []) { - $err_code = $this->storage->get_error_code(); - $res_code = $this->storage->get_response_code(); - $args = array(); - - if ($res_code == rcube_storage::NOPERM) { - $error = 'errornoperm'; - } - else if ($res_code == rcube_storage::READONLY) { - $error = 'errorreadonly'; - } - else if ($res_code == rcube_storage::OVERQUOTA) { - $error = 'erroroverquota'; - } - else if ($err_code && ($err_str = $this->storage->get_error_str())) { - // try to detect access rights problem and display appropriate message - if (stripos($err_str, 'Permission denied') !== false) { - $error = 'errornoperm'; - } - // try to detect full mailbox problem and display appropriate message - // there can be e.g. "Quota exceeded" / "quotum would exceed" / "Over quota" - else if (stripos($err_str, 'quot') !== false && preg_match('/exceed|over/i', $err_str)) { - $error = 'erroroverquota'; - } - else { - $error = 'servererrormsg'; - $args = array('msg' => rcube::Q($err_str)); - } - } - else if ($err_code < 0) { - $error = 'storageerror'; - } - else if ($fallback) { - $error = $fallback; - $args = $fallback_args; - $params['prefix'] = false; - } - - if (!empty($error)) { - if ($suffix && $this->text_exists($error . $suffix)) { - $error .= $suffix; - } - - $msg = $this->gettext(array('name' => $error, 'vars' => $args)); - - if ($params['prefix'] && $fallback) { - $msg = $this->gettext(array('name' => $fallback, 'vars' => $fallback_args)) . ' ' . $msg; - } - - $this->output->show_message($msg, $params['type'] ?: 'error'); - } + rcmail_action::display_server_error($fallback, $fallback_args, $suffix, $params); } /** * Displays an error message on storage fatal errors + * + * @deprecated since 1.5-beta, use rcmail_action::storage_fatal_error() */ public function storage_fatal_error() { - $err_code = $this->storage->get_error_code(); - switch ($err_code) { - // Not all are really fatal, but these should catch - // connection/authentication errors the best we can - case rcube_imap_generic::ERROR_NO: - case rcube_imap_generic::ERROR_BAD: - case rcube_imap_generic::ERROR_BYE: - $this->display_server_error(); - } + rcmail_action::storage_fatal_error(); } /** * Output HTML editor scripts * * @param string $mode Editor mode + * + * @deprecated since 1.5-beta, use rcmail_action::html_editor() */ public function html_editor($mode = '') { - $spellcheck = intval($this->config->get('enable_spellcheck')); - $spelldict = intval($this->config->get('spellcheck_dictionary')); - $disabled_plugins = array(); - $disabled_buttons = array(); - $extra_plugins = array(); - $extra_buttons = array(); - - if (!$spellcheck) { - $disabled_plugins[] = 'spellchecker'; - } - - $hook = $this->plugins->exec_hook('html_editor', array( - 'mode' => $mode, - 'disabled_plugins' => $disabled_plugins, - 'disabled_buttons' => $disabled_buttons, - 'extra_plugins' => $extra_plugins, - 'extra_buttons' => $extra_buttons, - )); - - if ($hook['abort']) { - return; - } - - $lang_codes = array($_SESSION['language']); - $assets_dir = $this->config->get('assets_dir') ?: INSTALL_PATH; - $skin_path = $this->output->get_skin_path(); - - if ($pos = strpos($_SESSION['language'], '_')) { - $lang_codes[] = substr($_SESSION['language'], 0, $pos); - } - - foreach ($lang_codes as $code) { - if (file_exists("$assets_dir/program/js/tinymce/langs/$code.js")) { - $lang = $code; - break; - } - } - - if (empty($lang)) { - $lang = 'en'; - } - - $config = array( - 'mode' => $mode, - 'lang' => $lang, - 'skin_path' => $skin_path, - 'spellcheck' => $spellcheck, // deprecated - 'spelldict' => $spelldict, - 'content_css' => 'program/resources/tinymce/content.css', - 'disabled_plugins' => $hook['disabled_plugins'], - 'disabled_buttons' => $hook['disabled_buttons'], - 'extra_plugins' => $hook['extra_plugins'], - 'extra_buttons' => $hook['extra_buttons'], - ); - - if ($path = $this->config->get('editor_css_location')) { - if ($path = $this->find_asset($skin_path . $path)) { - $config['content_css'] = $path; - } - } - - $font_family = $this->output->get_env('default_font'); - $font_size = $this->output->get_env('default_font_size'); - $style = array(); - - if ($font_family) { - $style[] = "font-family: $font_family;"; - } - if ($font_size) { - $style[] = "font-size: $font_size;"; - } - if (!empty($style)) { - $config['content_style'] = "body {" . implode(' ', $style) . "}"; - } - - $this->output->set_env('editor_config', $config); - $this->output->add_label('selectimage', 'addimage', 'selectmedia', 'addmedia', 'close'); - - if ($path = $this->config->get('media_browser_css_location', 'program/resources/tinymce/browser.css')) { - if ($path != 'none' && ($path = $this->find_asset($path))) { - $this->output->include_css($path); - } - } - - $this->output->include_script('tinymce/tinymce.min.js'); - $this->output->include_script('editor.js'); + rcmail_action::html_editor($mode); } /** @@ -2377,29 +1759,11 @@ class rcmail extends rcube * @param int $max_size Optional maximum file size in bytes * * @return string Human-readable file size limit + * @deprecated since 1.5-beta, use rcmail_action::upload_init() */ public function upload_init($max_size = null) { - // find max filesize value - $max_filesize = rcube_utils::max_upload_size(); - if ($max_size && $max_size < $max_filesize) { - $max_filesize = $max_size; - } - - $max_filesize_txt = $this->show_bytes($max_filesize); - $this->output->set_env('max_filesize', $max_filesize); - $this->output->set_env('filesizeerror', $this->gettext(array( - 'name' => 'filesizeerror', 'vars' => array('size' => $max_filesize_txt)))); - - if ($max_filecount = ini_get('max_file_uploads')) { - $this->output->set_env('max_filecount', $max_filecount); - $this->output->set_env('filecounterror', $this->gettext(array( - 'name' => 'filecounterror', 'vars' => array('count' => $max_filecount)))); - } - - $this->output->add_label('uploadprogress', 'GB', 'MB', 'KB', 'B'); - - return $max_filesize_txt; + return rcmail_action::upload_init($max_size); } /** @@ -2412,164 +1776,33 @@ class rcmail extends rcube * @param int $max_size Maximum upload size * * @return string HTML output + * @deprecated since 1.5-beta, use rcmail_action::upload_form() */ - public function upload_form($attrib, $name, $action, $input_attr = array(), $max_size = null) + public function upload_form($attrib, $name, $action, $input_attr = [], $max_size = null) { - // Get filesize, enable upload progress bar - $max_filesize = $this->upload_init($max_size); - - $hint = html::div('hint', $this->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))); - - if (!empty($attrib['mode']) && $attrib['mode'] == 'hint') { - return $hint; - } - - // set defaults - $attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes'); - - $event = rcmail_output::JS_OBJECT_NAME . ".command('$action', this.form)"; - $form_id = $attrib['id'] . 'Frm'; - - // Default attributes of file input and form - $input_attr += array( - 'id' => $attrib['id'] . 'Input', - 'type' => 'file', - 'name' => '_attachments[]', - 'class' => 'form-control', - ); - - $form_attr = array( - 'id' => $form_id, - 'name' => $name, - 'method' => 'post', - 'enctype' => 'multipart/form-data' - ); - - if (!empty($attrib['mode']) && $attrib['mode'] == 'smart') { - unset($attrib['buttons']); - $form_attr['class'] = 'smart-upload'; - $input_attr = array_merge($input_attr, array( - // #5854: Chrome does not execute onchange when selecting the same file. - // To fix this we reset the input using null value. - 'onchange' => "$event; this.value=null", - 'class' => 'smart-upload', - 'tabindex' => '-1', - )); - } - - $input = new html_inputfield($input_attr); - $content = $attrib['prefix'] . $input->show(); - - if (empty($attrib['mode']) || $attrib['mode'] != 'smart') { - $content = html::div(null, $content . $hint); - } - - if (rcube_utils::get_boolean($attrib['buttons'])) { - $button = new html_inputfield(array('type' => 'button')); - $content .= html::div('buttons', - $button->show($this->gettext('close'), array('class' => 'button', 'onclick' => "$('#{$attrib['id']}').hide()")) . ' ' . - $button->show($this->gettext('upload'), array('class' => 'button mainaction', 'onclick' => $event)) - ); - } - - $this->output->add_gui_object($name, $form_id); - - return html::div($attrib, $this->output->form_tag($form_attr, $content)); + return rcmail_action::upload_form($attrib, $name, $action, $input_attr, $max_size); } /** * Outputs uploaded file content (with image thumbnails support * * @param array $file Upload file data + * + * @deprecated since 1.5-beta, use rcmail_action::display_uploaded_file() */ public function display_uploaded_file($file) { - if (empty($file)) { - return; - } - - $file = $this->plugins->exec_hook('attachment_display', $file); - - if ($file['status']) { - if (empty($file['size'])) { - $file['size'] = $file['data'] ? strlen($file['data']) : @filesize($file['path']); - } - - // generate image thumbnail for file browser in HTML editor - if (!empty($_GET['_thumbnail'])) { - $thumbnail_size = 80; - $mimetype = $file['mimetype']; - $file_ident = $file['id'] . ':' . $file['mimetype'] . ':' . $file['size']; - $thumb_name = 'thumb' . md5($file_ident . ':' . $this->user->ID . ':' . $thumbnail_size); - $cache_file = rcube_utils::temp_filename($thumb_name, false, false); - - // render thumbnail image if not done yet - if (!is_file($cache_file)) { - if (!$file['path']) { - $orig_name = $filename = $cache_file . '.tmp'; - file_put_contents($orig_name, $file['data']); - } - else { - $filename = $file['path']; - } - - $image = new rcube_image($filename); - if ($imgtype = $image->resize($thumbnail_size, $cache_file, true)) { - $mimetype = 'image/' . $imgtype; - - if (!empty($orig_name)) { - unlink($orig_name); - } - } - } - - if (is_file($cache_file)) { - // cache for 1h - $this->output->future_expire_header(3600); - header('Content-Type: ' . $mimetype); - header('Content-Length: ' . filesize($cache_file)); - - readfile($cache_file); - exit; - } - } - - header('Content-Type: ' . $file['mimetype']); - header('Content-Length: ' . $file['size']); - - if ($file['data']) { - echo $file['data']; - } - else if ($file['path']) { - readfile($file['path']); - } - } + rcmail_action::display_uploaded_file($file); } /** * Initializes client-side autocompletion. + * + * @deprecated since 1.5-beta, use rcmail_action::autocomplete_init() */ public function autocomplete_init() { - static $init; - - if ($init) { - return; - } - - $init = 1; - - if (($threads = (int)$this->config->get('autocomplete_threads')) > 0) { - $book_types = (array) $this->config->get('autocomplete_addressbooks', 'sql'); - if (count($book_types) > 1) { - $this->output->set_env('autocomplete_threads', $threads); - $this->output->set_env('autocomplete_sources', $book_types); - } - } - - $this->output->set_env('autocomplete_max', (int)$this->config->get('autocomplete_max', 15)); - $this->output->set_env('autocomplete_min_length', $this->config->get('autocomplete_min_length')); - $this->output->add_label('autocompletechars', 'autocompletemore'); + rcmail_action::autocomplete_init(); } /** @@ -2577,31 +1810,12 @@ class rcmail extends rcube * * @param string $font Font name * - * @param string|array Font-family specification array or string (if $font is used) + * @return string|array Font-family specification array or string (if $font is used) + * @deprecated since 1.5-beta, use rcmail_action::autocomplete_init() */ public static function font_defs($font = null) { - $fonts = array( - 'Andale Mono' => '"Andale Mono",Times,monospace', - 'Arial' => 'Arial,Helvetica,sans-serif', - 'Arial Black' => '"Arial Black","Avant Garde",sans-serif', - 'Book Antiqua' => '"Book Antiqua",Palatino,serif', - 'Courier New' => '"Courier New",Courier,monospace', - 'Georgia' => 'Georgia,Palatino,serif', - 'Helvetica' => 'Helvetica,Arial,sans-serif', - 'Impact' => 'Impact,Chicago,sans-serif', - 'Tahoma' => 'Tahoma,Arial,Helvetica,sans-serif', - 'Terminal' => 'Terminal,Monaco,monospace', - 'Times New Roman' => '"Times New Roman",Times,serif', - 'Trebuchet MS' => '"Trebuchet MS",Geneva,sans-serif', - 'Verdana' => 'Verdana,Geneva,sans-serif', - ); - - if ($font) { - return $fonts[$font]; - } - - return $fonts; + return rcmail_action::font_defs($font); } /** @@ -2611,38 +1825,11 @@ class rcmail extends rcube * @param string &$unit Size unit * * @return string Byte string + * @deprecated since 1.5-beta, use rcmail_action::show_bytes() */ public function show_bytes($bytes, &$unit = null) { - // Plugins may want to display different units - $plugin = $this->plugins->exec_hook('show_bytes', array('bytes' => $bytes, 'unit' => null)); - - $unit = $plugin['unit']; - - if (isset($plugin['result'])) { - return $plugin['result']; - } - - if ($bytes >= 1073741824) { - $unit = 'GB'; - $gb = $bytes/1073741824; - $str = sprintf($gb >= 10 ? "%d " : "%.1f ", $gb) . $this->gettext($unit); - } - else if ($bytes >= 1048576) { - $unit = 'MB'; - $mb = $bytes/1048576; - $str = sprintf($mb >= 10 ? "%d " : "%.1f ", $mb) . $this->gettext($unit); - } - else if ($bytes >= 1024) { - $unit = 'KB'; - $str = sprintf("%d ", round($bytes/1024)) . $this->gettext($unit); - } - else { - $unit = 'B'; - $str = sprintf('%d ', $bytes) . $this->gettext($unit); - } - - return $str; + return rcmail_action::show_bytes($bytes, $unit); } /** @@ -2651,31 +1838,11 @@ class rcmail extends rcube * @param rcube_message_part $part Message part * * @return string Part size (and unit) + * @deprecated since 1.5-beta, use rcmail_action::message_part_size() */ public function message_part_size($part) { - if (isset($part->d_parameters['size'])) { - $size = $this->show_bytes((int)$part->d_parameters['size']); - } - else { - $size = $part->size; - - if ($size === 0) { - $part->exact_size = true; - } - - if ($part->encoding == 'base64') { - $size = $size / 1.33; - } - - $size = $this->show_bytes($size); - } - - if (!$part->exact_size) { - $size = '~' . $size; - } - - return $size; + return rcmail_action::message_part_size($part); } /** @@ -2687,56 +1854,11 @@ class rcmail extends rcube * @param int $mode Request mode. Default: rcube_utils::INPUT_GPC. * * @return array List of message UIDs per folder + * @deprecated since 1.5-beta, use rcmail_action::get_uids() */ public static function get_uids($uids = null, $mbox = null, &$is_multifolder = false, $mode = null) { - // message UID (or comma-separated list of IDs) is provided in - // the form of <ID>-<MBOX>[,<ID>-<MBOX>]* - - $_uid = $uids ?: rcube_utils::get_input_value('_uid', $mode ?: rcube_utils::INPUT_GPC); - $_mbox = $mbox ?: (string) rcube_utils::get_input_value('_mbox', $mode ?: rcube_utils::INPUT_GPC); - - // already a hash array - if (is_array($_uid) && !isset($_uid[0])) { - return $_uid; - } - - $result = array(); - - // special case: * - if ($_uid == '*' && is_object($_SESSION['search'][1]) && $_SESSION['search'][1]->multi) { - $is_multifolder = true; - // extract the full list of UIDs per folder from the search set - foreach ($_SESSION['search'][1]->sets as $subset) { - $mbox = $subset->get_parameters('MAILBOX'); - $result[$mbox] = $subset->get(); - } - } - else { - if (is_string($_uid)) { - $_uid = explode(',', $_uid); - } - - // create a per-folder UIDs array - foreach ((array)$_uid as $uid) { - list($uid, $mbox) = explode('-', $uid, 2); - if (!strlen($mbox)) { - $mbox = $_mbox; - } - else { - $is_multifolder = true; - } - - if ($uid == '*') { - $result[$mbox] = $uid; - } - else if (preg_match('/^[0-9:.]+$/', $uid)) { - $result[$mbox][] = $uid; - } - } - } - - return $result; + return rcmail_action::get_uids($uids, $mbox, $is_multifolder, $mode); } /** @@ -2745,23 +1867,11 @@ class rcmail extends rcube * @param string $name File name * * @return string File content + * @deprecated since 1.5-beta, use rcmail_action::get_resource_content() */ public function get_resource_content($name) { - if (!strpos($name, '/')) { - $name = "program/resources/$name"; - } - - $assets_dir = $this->config->get('assets_dir'); - - if ($assets_dir) { - $path = slashify($assets_dir) . $name; - if (@file_exists($path)) { - $name = $path; - } - } - - return file_get_contents($name, false); + return rcmail_action::get_resource_content($name); } /** |