From c9a2fa9db0b3cc9edee0b4ee82d02849b5263766 Mon Sep 17 00:00:00 2001 From: thomascube <thomas@roundcube.net> Date: Wed, 11 Mar 2009 17:43:18 -0400 Subject: [PATCH] Fix charset conversion error logging --- program/include/main.inc | 175 +++++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 112 insertions(+), 63 deletions(-) diff --git a/program/include/main.inc b/program/include/main.inc index e531bd8..b22be1a 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -5,7 +5,7 @@ | program/include/main.inc | | | | This file is part of the RoundCube Webmail client | - | Copyright (C) 2005-2008, RoundCube Dev, - Switzerland | + | Copyright (C) 2005-2009, RoundCube Dev, - Switzerland | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -151,19 +151,19 @@ * Garbage collector for cache entries. * Remove all expired message cache records */ -function rcmail_message_cache_gc() +function rcmail_cache_gc() { - global $DB, $CONFIG; - - // no cache lifetime configured - if (empty($CONFIG['message_cache_lifetime'])) - return; + $rcmail = rcmail::get_instance(); + $db = $rcmail->get_dbh(); // get target timestamp - $ts = get_offset_time($CONFIG['message_cache_lifetime'], -1); + $ts = get_offset_time($rcmail->config->get('message_cache_lifetime', '30d'), -1); - $DB->query("DELETE FROM ".get_table_name('messages')." - WHERE created < ".$DB->fromunixtime($ts)); + $db->query("DELETE FROM ".get_table_name('messages')." + WHERE created < " . $db->fromunixtime($ts)); + + $db->query("DELETE FROM ".get_table_name('cache')." + WHERE created < " . $db->fromunixtime($ts)); } @@ -178,13 +178,21 @@ */ function rcube_charset_convert($str, $from, $to=NULL) { - static $mbstring_loaded = null, $convert_warning = false; + static $mbstring_loaded = null; + static $mbstring_list = null; + static $convert_warning = false; $from = strtoupper($from); $to = $to==NULL ? strtoupper(RCMAIL_CHARSET) : strtoupper($to); $error = false; $conv = null; - if ($from==$to || $str=='' || empty($from)) + # RFC1642 + if ($from == 'UNICODE-1-1-UTF-7') + $from = 'UTF-7'; + if ($to == 'UNICODE-1-1-UTF-7') + $to = 'UTF-7'; + + if ($from == $to || empty($str) || empty($from)) return $str; $aliases = array( @@ -199,73 +207,84 @@ ); // convert charset using iconv module - if (function_exists('iconv') && $from != 'UTF-7' && $to != 'UTF-7') - { + if (function_exists('iconv') && $from != 'UTF-7' && $to != 'UTF-7') { $aliases['GB2312'] = 'GB18030'; $_iconv = iconv(($aliases[$from] ? $aliases[$from] : $from), ($aliases[$to] ? $aliases[$to] : $to) . "//IGNORE", $str); - if ($_iconv !== false) - { + if ($_iconv !== false) { return $_iconv; - } } - + } if (is_null($mbstring_loaded)) $mbstring_loaded = extension_loaded('mbstring'); // convert charset using mbstring module - if ($mbstring_loaded) - { + if ($mbstring_loaded) { $aliases['UTF-7'] = 'UTF7-IMAP'; $aliases['WINDOWS-1257'] = 'ISO-8859-13'; - // return if convert succeeded - if (($out = mb_convert_encoding($str, ($aliases[$to] ? $aliases[$to] : $to), ($aliases[$from] ? $aliases[$from] : $from))) != '') - return $out; + if (is_null($mbstring_list)) { + $mbstring_list = mb_list_encodings(); + $mbstring_list = array_map('strtoupper', $mbstring_list); } - + $mb_from = $aliases[$from] ? $aliases[$from] : $from; + $mb_to = $aliases[$to] ? $aliases[$to] : $to; + + // return if encoding found, string matches encoding and convert succeeded + if (in_array($mb_from, $mbstring_list) && in_array($mb_to, $mbstring_list)) { + if (mb_check_encoding($str, $mb_from) && ($out = mb_convert_encoding($str, $mb_to, $mb_from))) + return $out; + } + } + + # try to convert with custom classes if (class_exists('utf8')) $conv = new utf8(); // convert string to UTF-8 - if ($from == 'UTF-7') - $str = utf7_to_utf8($str); - else if (($from == 'ISO-8859-1') && function_exists('utf8_encode')) + if ($from == 'UTF-7') { + if ($_str = utf7_to_utf8($str)) + $str = $_str; + else + $error = true; + } + else if (($from == 'ISO-8859-1') && function_exists('utf8_encode')) { $str = utf8_encode($str); - else if ($from != 'UTF-8' && $conv) - { + } + else if ($from != 'UTF-8' && $conv) { $conv->loadCharset($from); $str = $conv->strToUtf8($str); - } + } else if ($from != 'UTF-8') $error = true; // encode string for output - if ($to == 'UTF-7') + if ($to == 'UTF-7') { return utf8_to_utf7($str); - else if ($to == 'ISO-8859-1' && function_exists('utf8_decode')) + } + else if ($to == 'ISO-8859-1' && function_exists('utf8_decode')) { return utf8_decode($str); - else if ($to != 'UTF-8' && $conv) - { + } + else if ($to != 'UTF-8' && $conv) { $conv->loadCharset($to); return $conv->utf8ToStr($str); - } - else if ($to != 'UTF-8') + } + else if ($to != 'UTF-8') { $error = true; - + } + // report error - if ($error && !$convert_warning) - { + if ($error && !$convert_warning){ raise_error(array( 'code' => 500, 'type' => 'php', 'file' => __FILE__, - 'message' => "Could not convert string charset. Make sure iconv is installed or lib/utf8.class is available" + 'message' => "Could not convert string from $from to $to. Make sure iconv is installed or lib/utf8.class is available" ), true, false); $convert_warning = true; - } + } // return UTF-8 string return $str; @@ -575,43 +594,41 @@ * @param string Container ID to use as prefix * @return string Modified CSS source */ -function rcmail_mod_css_styles($source, $container_id, $base_url = '') +function rcmail_mod_css_styles($source, $container_id) { - $a_css_values = array(); $last_pos = 0; + $replacements = new rcube_string_replacer; // ignore the whole block if evil styles are detected $stripped = preg_replace('/[^a-z\(:]/', '', rcmail_xss_entitiy_decode($source)); if (preg_match('/expression|behavior|url\(|import/', $stripped)) - return ''; + return '/* evil! */'; // cut out all contents between { and } while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { - $key = sizeof($a_css_values); - $a_css_values[$key] = substr($source, $pos+1, $pos2-($pos+1)); - $source = substr($source, 0, $pos+1) . "<<str_replacement[$key]>>" . substr($source, $pos2, strlen($source)-$pos2); + $key = $replacements->add(substr($source, $pos+1, $pos2-($pos+1))); + $source = substr($source, 0, $pos+1) . $replacements->get_replacement($key) . substr($source, $pos2, strlen($source)-$pos2); $last_pos = $pos+2; } - + // remove html comments and add #container to each tag selector. // also replace body definition because we also stripped off the <body> tag $styles = preg_replace( array( '/(^\s*<!--)|(-->\s*$)/', '/(^\s*|,\s*|\}\s*)([a-z0-9\._#][a-z0-9\.\-_]*)/im', - '/@import\s+(url\()?[\'"]?([^\)\'"]+)[\'"]?(\))?/ime', - '/<<str_replacement\[([0-9]+)\]>>/e', - "/$container_id\s+body/i" + "/$container_id\s+body/i", ), array( '', "\\1#$container_id \\2", - "sprintf(\"@import url('./bin/modcss.php?u=%s&c=%s')\", urlencode(make_absolute_url('\\2','$base_url')), urlencode($container_id))", - "\$a_css_values[\\1]", - "$container_id div.rcmBody" + "$container_id div.rcmBody", ), $source); + + // put block contents back in + $styles = $replacements->resolve($styles); return $styles; } @@ -627,11 +644,22 @@ function rcmail_xss_entitiy_decode($content) { $out = html_entity_decode(html_entity_decode($content)); - $out = preg_replace('/\\\([0-9a-f]{4})/ie', "chr(hexdec('\\1'))", $out); + $out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entitiy_decode_callback', $out); $out = preg_replace('#/\*.*\*/#Um', '', $out); return $out; } + +/** + * preg_replace_callback callback for rcmail_xss_entitiy_decode_callback + * + * @param array matches result from preg_replace_callback + * @return string decoded entity + */ +function rcmail_xss_entitiy_decode_callback($matches) +{ + return chr(hexdec($matches[1])); +} /** * Compose a valid attribute string for HTML tags @@ -692,6 +720,8 @@ $ts = $date; else if (!empty($date)) { + // support non-standard "GMTXXXX" literal + $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); // if date parsing fails, we have a date in non-rfc format. // remove token from the end and try again while ((($ts = @strtotime($date))===false) || ($ts < 0)) @@ -1143,17 +1173,15 @@ { global $CONFIG; - $cname = null; - $folder_lc = strtolower($folder_id); - // for these mailboxes we have localized labels and css classes - foreach (array('inbox', 'sent', 'drafts', 'trash', 'junk') as $smbx) + foreach (array('sent', 'drafts', 'trash', 'junk') as $smbx) { - if ($folder_lc == $smbx || $folder_id == $CONFIG[$smbx.'_mbox']) - $cname = $smbx; + if ($folder_id == $CONFIG[$smbx.'_mbox']) + return $smbx; } - - return $cname; + + if ($folder_id == 'INBOX') + return 'inbox'; } @@ -1191,4 +1219,25 @@ $OUTPUT->add_script('rcmail_editor_init("$__skin_path", "'.JQ($tinylang).'", '.intval($CONFIG['enable_spellcheck']).', "'.$mode.'");'); } + + +/** + * Helper class to turn relative urls into absolute ones + * using a predefined base + */ +class rcube_base_replacer +{ + private $base_url; + + public function __construct($base) + { + $this->base_url = $base; + } + + public function callback($matches) + { + return $matches[1] . '="' . make_absolute_url($matches[3], $this->base_url) . '"'; + } +} + ?> -- Gitblit v1.9.1