From f94e442469deca30b39f3fa08aade83cbd0ede70 Mon Sep 17 00:00:00 2001 From: thomascube <thomas@roundcube.net> Date: Fri, 16 Dec 2011 13:38:59 -0500 Subject: [PATCH] Add more classes and options to HTML elements for better styleability --- program/include/main.inc | 166 ++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 127 insertions(+), 39 deletions(-) diff --git a/program/include/main.inc b/program/include/main.inc index c84e5ad..012ee8d 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -640,20 +640,23 @@ function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL) { $value = NULL; - - if ($source==RCUBE_INPUT_GET && isset($_GET[$fname])) - $value = $_GET[$fname]; - else if ($source==RCUBE_INPUT_POST && isset($_POST[$fname])) - $value = $_POST[$fname]; - else if ($source==RCUBE_INPUT_GPC) - { + + if ($source == RCUBE_INPUT_GET) { + if (isset($_GET[$fname])) + $value = $_GET[$fname]; + } + else if ($source == RCUBE_INPUT_POST) { + if (isset($_POST[$fname])) + $value = $_POST[$fname]; + } + else if ($source == RCUBE_INPUT_GPC) { if (isset($_POST[$fname])) $value = $_POST[$fname]; else if (isset($_GET[$fname])) $value = $_GET[$fname]; else if (isset($_COOKIE[$fname])) $value = $_COOKIE[$fname]; - } + } return parse_input_value($value, $allow_html, $charset); } @@ -661,7 +664,7 @@ /** * Parse/validate input value. See get_input_value() * Performs stripslashes() and charset conversion if necessary - * + * * @param string Input value * @param boolean Allow HTML tags in field value * @param string Charset to convert into @@ -687,15 +690,21 @@ else if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) $value = stripslashes($value); - // remove HTML tags if not allowed + // remove HTML tags if not allowed if (!$allow_html) $value = strip_tags($value); - + + $output_charset = is_object($OUTPUT) ? $OUTPUT->get_charset() : null; + + // remove invalid characters (#1488124) + if ($output_charset == 'UTF-8') + $value = rc_utf8_clean($value); + // convert to internal charset - if (is_object($OUTPUT) && $charset) - return rcube_charset_convert($value, $OUTPUT->get_charset(), $charset); - else - return $value; + if ($charset && $output_charset) + $value = rcube_charset_convert($value, $output_charset, $charset); + + return $value; } /** @@ -711,10 +720,10 @@ $src = $mode == RCUBE_INPUT_GET ? $_GET : ($mode == RCUBE_INPUT_POST ? $_POST : $_REQUEST); foreach ($src as $key => $value) { $fname = $key[0] == '_' ? substr($key, 1) : $key; - if ($ignore && !preg_match("/($ignore)/", $fname)) + if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) $out[$fname] = get_input_value($key, $mode); } - + return $out; } @@ -730,12 +739,14 @@ /** * Convert the given string into a valid HTML identifier - * Same functionality as done in app.js with this.identifier_expr - * + * Same functionality as done in app.js with rcube_webmail.html_identifier() */ -function html_identifier($str) +function html_identifier($str, $encode=false) { - return asciiwords($str, true, '_'); + if ($encode) + return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); + else + return asciiwords($str, true, '_'); } /** @@ -872,23 +883,37 @@ * @param string Container ID to use as prefix * @return string Modified CSS source */ -function rcmail_mod_css_styles($source, $container_id) +function rcmail_mod_css_styles($source, $container_id, $allow_remote=false) { $last_pos = 0; $replacements = new rcube_string_replacer; // ignore the whole block if evil styles are detected - $stripped = preg_replace('/[^a-z\(:;]/', '', rcmail_xss_entity_decode($source)); - if (preg_match('/expression|behavior|url\(|import[^a]/', $stripped)) + $source = rcmail_xss_entity_decode($source); + $stripped = preg_replace('/[^a-z\(:;]/i', '', $source); + $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : ''); + if (preg_match("/$evilexpr/i", $stripped)) return '/* evil! */'; - // remove css comments (sometimes used for some ugly hacks) - $source = preg_replace('!/\*(.+)\*/!Ums', '', $source); - // cut out all contents between { and } - while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) - { - $key = $replacements->add(substr($source, $pos+1, $pos2-($pos+1))); + while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { + $styles = substr($source, $pos+1, $pos2-($pos+1)); + + // check every line of a style block... + if ($allow_remote) { + $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY); + foreach ($a_styles as $line) { + $stripped = preg_replace('/[^a-z\(:;]/i', '', $line); + // ... and only allow strict url() values + if (stripos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims', $line)) { + $a_styles = array('/* evil! */'); + break; + } + } + $styles = join(";\n", $a_styles); + } + + $key = $replacements->add($styles); $source = substr($source, 0, $pos+1) . $replacements->get_replacement($key) . substr($source, $pos2, strlen($source)-$pos2); $last_pos = $pos+2; } @@ -926,7 +951,7 @@ { $out = html_entity_decode(html_entity_decode($content)); $out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entity_decode_callback', $out); - $out = preg_replace('#/\*.*\*/#Um', '', $out); + $out = preg_replace('#/\*.*\*/#Ums', '', $out); return $out; } @@ -1145,7 +1170,7 @@ global $RCMAIL; static $a_mailboxes; - $attrib += array('maxlength' => 100, 'realnames' => false); + $attrib += array('maxlength' => 100, 'realnames' => false, 'unreadwrap' => ' (%s)'); // add some labels to client $RCMAIL->output->add_label('purgefolderconfirm', 'deletemessagesconfirm'); @@ -1192,6 +1217,7 @@ $RCMAIL->output->add_gui_object('mailboxlist', $attrib['id']); $RCMAIL->output->set_env('mailboxes', $js_mailboxlist); + $RCMAIL->output->set_env('unreadwrap', $attrib['unreadwrap']); $RCMAIL->output->set_env('collapsed_folders', (string)$RCMAIL->config->get('collapsed_folders')); } @@ -1331,7 +1357,7 @@ } // make folder name safe for ids and class names - $folder_id = html_identifier($folder['id']); + $folder_id = html_identifier($folder['id'], true); $classes = array('mailbox'); // set special class for Sent, Drafts, Trash and Junk @@ -1347,7 +1373,7 @@ $classes[] = 'unread'; $js_name = JQ($folder['id']); - $html_name = Q($foldername) . ($unread ? html::span('unreadcount', " ($unread)") : ''); + $html_name = Q($foldername) . ($unread ? html::span('unreadcount', sprintf($attrib['unreadwrap'], $unread)) : ''); $link_attrib = $folder['virtual'] ? array() : array( 'href' => rcmail_url('', array('_mbox' => $folder['id'])), 'onclick' => sprintf("return %s.command('list','%s',this)", JS_OBJECT_NAME, $js_name), @@ -1582,6 +1608,26 @@ /** + * Generate CSS classes from mimetype and filename extension + * + * @param string Mimetype + * @param string The filename + * @return string CSS classes separated by space + */ +function rcmail_filetype2classname($mimetype, $filename) +{ + list($primary, $secondary) = explode('/', $mimetype); + + $classes = array($primary ? $primary : 'unknown'); + if ($secondary) + $classes[] = $secondary; + if (preg_match('/\.([a-z0-9]+)$/', $filename, $m)) + $classes[] = $m[1]; + + return join(" ", $classes); +} + +/** * Output HTML editor scripts * * @param string Editor mode @@ -1589,7 +1635,7 @@ */ function rcube_html_editor($mode='') { - global $RCMAIL, $CONFIG; + global $RCMAIL; $hook = $RCMAIL->plugins->exec_hook('html_editor', array('mode' => $mode)); @@ -1598,8 +1644,11 @@ $lang = strtolower($_SESSION['language']); - // TinyMCE uses 'tw' for zh_TW (which is wrong, because tw is a code of Twi language) - $lang = ($lang == 'zh_tw') ? 'tw' : substr($lang, 0, 2); + // TinyMCE uses two-letter lang codes, with exception of Chinese + if (strpos($lang, 'zh_') === 0) + $lang = str_replace('_', '-', $lang); + else + $lang = substr($lang, 0, 2); if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$lang.'.js')) $lang = 'en'; @@ -1611,8 +1660,8 @@ 'mode' => $mode, 'skin_path' => '$__skin_path', 'lang' => $lang, - 'spellcheck' => intval($CONFIG['enable_spellcheck']), - 'spelldict' => intval($CONFIG['spellcheck_dictionary']), + 'spellcheck' => intval($RCMAIL->config->get('enable_spellcheck')), + 'spelldict' => intval($RCMAIL->config->get('spellcheck_dictionary')), ))), 'foot'); } @@ -1837,6 +1886,21 @@ $date = preg_replace('/[+-][0-9]{4}$/', $tz, $date); return $date; +} + + +/** + * Check if we can process not exceeding memory_limit + * + * @param integer Required amount of memory + * @return boolean + */ +function rcmail_mem_check($need) +{ + $mem_limit = parse_bytes(ini_get('memory_limit')); + $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB + + return $mem_limit && $memory + $need > $mem_limit ? false : true; } @@ -2379,3 +2443,27 @@ $RCMAIL->output->set_env('autocomplete_min_length', $RCMAIL->config->get('autocomplete_min_length')); $RCMAIL->output->add_label('autocompletechars', 'autocompletemore'); } + +function rcube_fontdefs($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; +} -- Gitblit v1.9.1