diff options
-rw-r--r-- | CHANGELOG | 5 | ||||
-rw-r--r-- | bin/modcss.php | 67 | ||||
-rw-r--r-- | program/include/main.inc | 45 | ||||
-rw-r--r-- | program/include/rcube_shared.inc | 4 | ||||
-rw-r--r-- | program/steps/mail/func.inc | 74 |
5 files changed, 152 insertions, 43 deletions
@@ -1,6 +1,11 @@ CHANGELOG RoundCube Webmail --------------------------- +2007/09/29 (thomasb) +---------- +- Filter linked/imported CSS files (closes #1484056) + + 2007/09/27 (tomekp) ---------- - Update brazilian portuguese localization (#1484580) diff --git a/bin/modcss.php b/bin/modcss.php new file mode 100644 index 000000000..e482389a8 --- /dev/null +++ b/bin/modcss.php @@ -0,0 +1,67 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/bin/modcss.php | + | | + | This file is part of the RoundCube Webmail client | + | Copyright (C) 2007, RoundCube Dev. - Switzerland | + | Licensed under the GNU GPL | + | | + | PURPOSE: | + | Modify CSS source from a URL | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $Id: $ + +*/ + +$INSTALL_PATH = realpath("./../") . "/"; +ini_set('include_path', $INSTALL_PATH.PATH_SEPARATOR.$INSTALL_PATH.'program'.PATH_SEPARATOR.ini_get('include_path')); + +require 'include/main.inc'; + +$source = ""; +if ($url = preg_replace('/[^a-z0-9.-_\?\$&=%]/i', '', $_GET['u'])) +{ + $a_uri = parse_url($url); + $port = $a_uri['port'] ? $a_uri['port'] : 80; + $host = $a_uri['host']; + $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : ''); + + + if ($fp = fsockopen($host, $port, $errno, $errstr, 30)) + { + $out = "GET $path HTTP/1.0\r\n"; + $out .= "Host: $host\r\n"; + $out .= "Connection: Close\r\n\r\n"; + fwrite($fp, $out); + + $header = true; + while (!feof($fp)) + { + $line = trim(fgets($fp, 4048)); + + if ($header && preg_match('/^HTTP\/1\..\s+(\d+)/', $line, $regs) && intval($regs[1]) != 200) + break; + else if (empty($line) && $header) + $header = false; + else if (!$header) + $source .= "$line\n"; + } + fclose($fp); + } +} + +if (!empty($source)) +{ + header("Content-Type: text/css"); + echo rcmail_mod_css_styles($source, preg_replace('/[^a-z0-9]/i', '', $_GET['c']), $url); +} +else + header("HTTP/1.0 404 Not Found"); + +?> diff --git a/program/include/main.inc b/program/include/main.inc index 9809865d4..db0ee6c07 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -29,6 +29,7 @@ require_once('lib/des.inc'); require_once('lib/utf7.inc'); require_once('lib/utf8.class.php'); +require_once('include/rcube_shared.inc'); require_once('include/rcmail_template.inc'); @@ -1450,6 +1451,50 @@ function rcmail_mail_domain($host) /** + * Replace all css definitions with #container [def] + * + * @param string CSS source code + * @param string Container ID to use as prefix + * @return string Modified CSS source + */ +function rcmail_mod_css_styles($source, $container_id, $base_url = '') + { + $a_css_values = array(); + $last_pos = 0; + + // 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); + $last_pos = $pos+2; + } + + // remove html commends 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" + ), + 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" + ), + $source); + + return $styles; + } + + +/** * Compose a valid attribute string for HTML tags * * @param array Named tag attributes diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index a5a3ca64e..05fa7a2bc 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -434,6 +434,10 @@ function make_absolute_url($path, $base_url) { $host_url = $base_url; $abs_path = $path; + + // check if path is an absolute URL + if (preg_match('/^[fhtps]+:\/\//', $path)) + return $path; // cut base_url to the last directory if (strpos($base_url, '/')>7) diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 0712ef8df..30d60e6da 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -946,16 +946,21 @@ function rcmail_sanitize_html($body, $container_id) // remove any null-byte characters before parsing $body = preg_replace('/\x00/', '', $body); + $base_url = ""; $last_style_pos = 0; $body_lc = strtolower($body); + // check for <base href> + if (preg_match(($base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i'), $body, $base_regs)) + $base_url = $base_regs[2]; + // find STYLE tags while (($pos = strpos($body_lc, '<style', $last_style_pos)) && ($pos2 = strpos($body_lc, '</style>', $pos))) { $pos = strpos($body_lc, '>', $pos)+1; // replace all css definitions with #container [def] - $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id); + $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id, $base_url); $body = substr($body, 0, $pos) . $styles . substr($body, $pos2); $body_lc = strtolower($body); @@ -983,17 +988,15 @@ function rcmail_sanitize_html($body, $container_id) } // resolve <base href> - $base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i'; - if (preg_match($base_reg, $body, $regs)) + if ($base_url) { - $base_url = $regs[2]; $body = preg_replace('/(src|background|href)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Uie', "'\\1=\"'.make_absolute_url('\\3', '$base_url').'\"'", $body); $body = preg_replace('/(url\s*\()(["\']?)([\.\/]+[^"\'\)\s]+)(\2)\)/Uie', "'\\1\''.make_absolute_url('\\3', '$base_url').'\')'", $body); $body = preg_replace($base_reg, '', $body); } // modify HTML links to open a new window if clicked - $body = preg_replace('/<a\s+([^>]+)>/Uie', "rcmail_alter_html_link('\\1');", $body); + $body = preg_replace('/<(a|link)\s+([^>]+)>/Uie', "rcmail_alter_html_link('\\1','\\2', '$container_id');", $body); // add comments arround html and other tags $out = preg_replace(array( @@ -1005,11 +1008,16 @@ function rcmail_sanitize_html($body, $container_id) '<!--\\1-->', $body); - $out = preg_replace(array('/<body([^>]*)>/i', - '/<\/body>/i'), - array('<div class="rcmBody"\\1>', - '</div>'), - $out); + $out = preg_replace( + array( + '/<body([^>]*)>/i', + '/<\/body>/i', + ), + array( + '<div class="rcmBody"\\1>', + '</div>', + ), + $out); // quote <? of php and xml files that are specified as text/html $out = preg_replace(array('/<\?/', '/\?>/'), array('<?', '?>'), $out); @@ -1019,44 +1027,24 @@ function rcmail_sanitize_html($body, $container_id) // parse link attributes and set correct target -function rcmail_alter_html_link($in) +function rcmail_alter_html_link($tag, $attrs, $container_id) { $in = preg_replace('/=([^("|\'|\s)]+)(\s|$)/', '="\1"', $in); - $attrib = parse_attrib_string($in); - - if (stristr((string)$attrib['href'], 'mailto:')) - $attrib['onclick'] = sprintf("return %s.command('compose','%s',this)", - JS_OBJECT_NAME, - JQ(substr($attrib['href'], 7))); - else if (!empty($attrib['href']) && $attrib['href']{0}!='#') - $attrib['target'] = '_blank'; + $attrib = parse_attrib_string($attrs); - return '<a' . create_attrib_string($attrib, array('href', 'name', 'target', 'onclick', 'id', 'class', 'style', 'title')) . '>'; - } - - -// replace all css definitions with #container [def] -function rcmail_mod_css_styles($source, $container_id) - { - $a_css_values = array(); - $last_pos = 0; + if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href'])) + $attrib['href'] = "./bin/modcss.php?u=" . urlencode($attrib['href']) . "&c=" . urlencode($container_id); + + else if (stristr((string)$attrib['href'], 'mailto:')) + $attrib['onclick'] = sprintf( + "return %s.command('compose','%s',this)", + JS_OBJECT_NAME, + JQ(substr($attrib['href'], 7))); - // 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); - $last_pos = $pos+2; - } - - // remove html commends 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', '/<<str_replacement\[([0-9]+)\]>>/e', "/$container_id\s+body/i"), - array('', "\\1#$container_id \\2", "\$a_css_values[\\1]", "$container_id div.rcmBody"), - $source); + else if (!empty($attrib['href']) && $attrib['href']{0}!='#') + $attrib['target'] = '_blank'; - return $styles; + return "<$tag" . create_attrib_string($attrib, array('href','name','target','onclick','id','class','style','title','rel','type','media')) . ' />'; } |