From 2b017e7f79be26563ab767bb9e97fee5d88a01f4 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Fri, 09 Dec 2011 16:13:54 -0500
Subject: [PATCH] Allow clean background:url(...) styles in safe mode. This will make Roundcube pass the Email Standards Acid Test

---
 program/include/main.inc |  126 +++++++++++++++++++++++++++++-------------
 1 files changed, 87 insertions(+), 39 deletions(-)

diff --git a/program/include/main.inc b/program/include/main.inc
index 83b3087..2d18567 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,18 +883,18 @@
  * @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' . (!$allow_remote ? '|url\(|import[^a]' : '');
+  if (preg_match("/$evilexpr/i", $stripped) // don't accept No-Gos
+      || (strpos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Ui', $source))) // only allow clean urls
     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)))
@@ -926,7 +937,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;
 }
 
@@ -1281,11 +1292,6 @@
   $path .= $prefix.$currentFolder;
 
   if (!isset($arrFolders[$currentFolder])) {
-    // Check \Noselect attribute (if attributes are in cache)
-    if (!$virtual && ($attrs = $RCMAIL->imap->mailbox_attributes($path))) {
-      $virtual = in_array('\\Noselect', $attrs);
-    }
-
     $arrFolders[$currentFolder] = array(
       'id' => $path,
       'name' => rcube_charset_convert($currentFolder, 'UTF7-IMAP'),
@@ -1336,7 +1342,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
@@ -1594,7 +1600,7 @@
  */
 function rcube_html_editor($mode='')
 {
-  global $RCMAIL, $CONFIG;
+  global $RCMAIL;
 
   $hook = $RCMAIL->plugins->exec_hook('html_editor', array('mode' => $mode));
 
@@ -1603,8 +1609,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';
@@ -1616,8 +1625,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');
 }
 
@@ -1842,6 +1851,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;
 }
 
 
@@ -2384,3 +2408,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