X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=functions%2Fmime.php;h=1d7f0321136923d0039f953174bf4180e9dceb7a;hb=ffdae6e7ca11112273750f5ad80882164375a7e4;hp=ccbfd2900a44c03a6c75cb1e6f21357b7679efe3;hpb=8bd0068d630a8bfca396e936e5f34b9bd452fba8;p=squirrelmail.git diff --git a/functions/mime.php b/functions/mime.php index ccbfd290..1d7f0321 100644 --- a/functions/mime.php +++ b/functions/mime.php @@ -3,21 +3,41 @@ /** * mime.php * - * Copyright (c) 1999-2005 The SquirrelMail Project Team - * Licensed under the GNU GPL. For full terms see the file COPYING. - * * This contains the functions necessary to detect and decode MIME * messages. * + * @copyright © 1999-2006 The SquirrelMail Project Team + * @license http://opensource.org/licenses/gpl-license.php GNU Public License * @version $Id$ * @package squirrelmail */ -/** The typical includes... */ -require_once(SM_PATH . 'functions/imap.php'); -require_once(SM_PATH . 'functions/attachment_common.php'); -/** add sqm_baseuri()*/ -include_once(SM_PATH . 'functions/display_messages.php'); +/** + * dependency information + functions dependency + mime_structure + class/mime/Message.class.php + Message::parseStructure + functions/page_header.php + displayPageHeader + functions/display_messages.php + plain_error_message + mime_fetch_body + functions/imap_general.php + sqimap_run_command + mime_print_body_lines + + + +functions/imap.php +functions/attachment_common.php +functions/display_messages.php + +magicHtml => url_parser +translateText => url_parser + +*/ + /* -------------------------------------------------------------------------- */ /* MIME DECODING */ @@ -38,7 +58,6 @@ function mime_structure ($bodystructure, $flags=array()) { $i = 0; $msg = Message::parseStructure($read,$i); if (!is_object($msg)) { - include_once(SM_PATH . 'functions/display_messages.php'); global $color, $mailbox; /* removed urldecode because $_GET is auto urldecoded ??? */ displayPageHeader( $color, $mailbox ); @@ -265,7 +284,7 @@ function translateText(&$body, $wrap_at, $charset) { global $where, $what; /* from searching */ global $color; /* color theme */ - require_once(SM_PATH . 'functions/url_parser.php'); + // require_once(SM_PATH . 'functions/url_parser.php'); $body_ary = explode("\n", $body); for ($i=0; $i < count($body_ary); $i++) { @@ -335,7 +354,8 @@ function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $ma * order that is their priority. */ global $startMessage, $languages, $squirrelmail_language, - $show_html_default, $sort, $has_unsafe_images, $passed_ent_id, $use_iframe,$iframe_height; + $show_html_default, $sort, $has_unsafe_images, $passed_ent_id, + $use_iframe, $iframe_height, $download_and_unsafe_link; // workaround for not updated config.php if (! isset($use_iframe)) $use_iframe = false; @@ -388,7 +408,9 @@ function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $ma * If we don't add html message between iframe tags, * we must detect unsafe images and modify $has_unsafe_images. */ - $html_body = magicHTML($body, $id, $message, $mailbox); + $html_body = magicHTML($body, $id, $message, $mailbox); + // Convert character set in order to display html mails in different character set + $html_body = charset_decode($body_message->header->getParameter('charset'),$html_body,false,true); // creating iframe url $iframeurl=sqm_baseuri().'src/view_html.php?' @@ -427,6 +449,12 @@ function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $ma } else { // old way of html rendering $body = magicHTML($body, $id, $message, $mailbox); + /** + * convert character set. charset_decode does not remove html special chars + * applied by magicHTML functions and does not sanitize them second time if + * fourth argument is true. + */ + $body = charset_decode($body_message->header->getParameter('charset'),$body,false,true); } } else { translateText($body, $wrap_at, @@ -438,13 +466,15 @@ function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $ma return $body; } + $download_and_unsafe_link = ''; + $link = 'passed_id=' . $id . '&ent_id='.$ent_num. '&mailbox=' . $urlmailbox .'&sort=' . $sort . '&startMessage=' . $startMessage . '&show_more=0'; if (isset($passed_ent_id)) { $link .= '&passed_ent_id='.$passed_ent_id; } - $body .= '
' . _("Download this as a file") . ''; if ($view_unsafe_images) { $text = _("Hide Unsafe Images"); @@ -457,9 +487,8 @@ function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $ma } } if($text != '') { - $body .= ' | ' . $text . ''; + $download_and_unsafe_link .= ' | ' . $text . ''; } - $body .= '

' . "\n"; } return $body; } @@ -480,7 +509,7 @@ function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $ma * @return string html formated attachment information. */ function formatAttachments($message, $exclude_id, $mailbox, $id) { - global $where, $what, $startMessage, $color, $passed_ent_id; + global $where, $what, $startMessage, $color, $passed_ent_id, $base_uri; $att_ar = $message->getAttachments($exclude_id); @@ -497,10 +526,10 @@ function formatAttachments($message, $exclude_id, $mailbox, $id) { $type1 = strtolower($header->type1); $name = ''; $links['download link']['text'] = _("Download"); - $links['download link']['href'] = sqm_baseuri() . + $links['download link']['href'] = $base_uri . "src/download.php?absolute_dl=true&passed_id=$id&mailbox=$urlMailbox&ent_id=$ent"; if ($type0 =='message' && $type1 == 'rfc822') { - $default_page = sqm_baseuri() . 'src/read_body.php'; + $default_page = $base_uri . 'src/read_body.php'; $rfc822_header = $att->rfc822_header; $filename = $rfc822_header->subject; if (trim( $filename ) == '') { @@ -509,12 +538,19 @@ function formatAttachments($message, $exclude_id, $mailbox, $id) { $from_o = $rfc822_header->from; if (is_object($from_o)) { $from_name = decodeHeader($from_o->getAddress(false)); + } elseif (is_array($from_o) && count($from_o) && is_object($from_o[0])) { + // something weird happens when a digest message is opened and you return to the digest + // now the from object is part of an array. Probably the parseHeader call overwrites the info + // retrieved from the bodystructure in a different way. We need to fix this later. + // possible starting point, do not fetch header we already have and inspect how + // the rfc822_header object behaves. + $from_name = decodeHeader($from_o[0]->getAddress(false)); } else { $from_name = _("Unknown sender"); } $description = $from_name; } else { - $default_page = sqm_baseuri() . 'src/download.php'; + $default_page = $base_uri . 'src/download.php'; $filename = $att->getFilename(); if ($header->description) { $description = decodeHeader($header->description); @@ -606,10 +642,18 @@ function sqimap_base64_decode(&$string) { return $sStringRem; } - -/* This function decodes the body depending on the encoding type. */ +/** + * Decodes encoded message body + * + * This function decodes the body depending on the encoding type. + * Currently quoted-printable and base64 encodings are supported. + * decode_body hook was added to this function in 1.4.2/1.5.0 + * @param string $body encoded message body + * @param string $encoding used encoding + * @return string decoded string + * @since 1.0 + */ function decodeBody($body, $encoding) { - global $show_html_default; $body = str_replace("\r\n", "\n", $body); $encoding = strtolower($encoding); @@ -622,15 +666,16 @@ function decodeBody($body, $encoding) { if (!empty($encoding_handler) && function_exists($encoding_handler)) { $body = $encoding_handler('decode', $body); - } else if ($encoding == 'quoted-printable' || + } elseif ($encoding == 'quoted-printable' || $encoding == 'quoted_printable') { + /** + * quoted_printable_decode() function is broken in older + * php versions. Text with \r\n decoding was fixed only + * in php 4.3.0. Minimal code requirement 4.0.4 + + * str_replace("\r\n", "\n", $body); call. + */ $body = quoted_printable_decode($body); - - while (ereg("=\n", $body)) { - $body = ereg_replace ("=\n", '', $body); - } - - } else if ($encoding == 'base64') { + } elseif ($encoding == 'base64') { $body = base64_decode($body); } @@ -714,7 +759,7 @@ function decodeHeader ($string, $utfencode=true,$htmlsave=true,$decide=false) { /* convert string to different charset, * if functions asks for it (usually in compose) */ - $ret .= charset_convert($res[2],$replace,$default_charset); + $ret .= charset_convert($res[2],$replace,$default_charset,$htmlsave); } else { // convert string to html codes in order to display it $ret .= charset_decode($res[2],$replace); @@ -735,7 +780,7 @@ function decodeHeader ($string, $utfencode=true,$htmlsave=true,$decide=false) { /* convert string to different charset, * if functions asks for it (usually in compose) */ - $replace = charset_convert($res[2], $replace,$default_charset); + $replace = charset_convert($res[2], $replace,$default_charset,$htmlsave); } else { // convert string to html codes in order to display it $replace = charset_decode($res[2], $replace); @@ -781,14 +826,22 @@ function decodeHeader ($string, $utfencode=true,$htmlsave=true,$decide=false) { } /** - * Encodes header as quoted-printable + * Encodes header + * + * Function uses XTRA_CODE _encodeheader function, if such function exists. + * + * Function uses Q encoding by default and encodes a string according to RFC + * 1522 for use in headers if it contains 8-bit characters or anything that + * looks like it should be encoded. * - * Encode a string according to RFC 1522 for use in headers if it - * contains 8-bit characters or anything that looks like it should - * be encoded. + * Function switches to B encoding and encodeHeaderBase64() function, if + * string is 8bit and multibyte character set supported by mbstring extension + * is used. It can cause E_USER_NOTICE errors, if interface is used with + * multibyte character set unsupported by mbstring extension. * * @param string $string header string, that has to be encoded * @return string quoted-printable encoded string + * @todo make $mb_charsets system wide constant */ function encodeHeader ($string) { global $default_charset, $languages, $squirrelmail_language; @@ -798,6 +851,19 @@ function encodeHeader ($string) { return call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_encodeheader', $string); } + // Use B encoding for multibyte charsets + $mb_charsets = array('utf-8','big5','gb2313','euc-kr'); + if (in_array($default_charset,$mb_charsets) && + in_array($default_charset,sq_mb_list_encodings()) && + sq_is8bit($string)) { + return encodeHeaderBase64($string,$default_charset); + } elseif (in_array($default_charset,$mb_charsets) && + sq_is8bit($string) && + ! in_array($default_charset,sq_mb_list_encodings())) { + // Add E_USER_NOTICE error here (can cause 'Cannot add header information' warning in compose.php) + // trigger_error('encodeHeader: Multibyte character set unsupported by mbstring extension.',E_USER_NOTICE); + } + // Encode only if the string contains 8-bit characters or =? $j = strlen($string); $max_l = 75 - strlen($default_charset) - 7; @@ -911,6 +977,100 @@ function encodeHeader ($string) { return $string; } +/** + * Encodes string according to rfc2047 B encoding header formating rules + * + * It is recommended way to encode headers with character sets that store + * symbols in more than one byte. + * + * Function requires mbstring support. If required mbstring functions are missing, + * function returns false and sets E_USER_WARNING level error message. + * + * Minimal requirements - php 4.0.6 with mbstring extension. Please note, + * that mbstring functions will generate E_WARNING errors, if unsupported + * character set is used. mb_encode_mimeheader function provided by php + * mbstring extension is not used in order to get better control of header + * encoding. + * + * Used php code functions - function_exists(), trigger_error(), strlen() + * (is used with charset names and base64 strings). Used php mbstring + * functions - mb_strlen and mb_substr. + * + * Related documents: rfc 2045 (BASE64 encoding), rfc 2047 (mime header + * encoding), rfc 2822 (header folding) + * + * @param string $string header string that must be encoded + * @param string $charset character set. Must be supported by mbstring extension. + * Use sq_mb_list_encodings() to detect supported charsets. + * @return string string encoded according to rfc2047 B encoding formating rules + * @since 1.5.1 + * @todo First header line can be wrapped to $iMaxLength - $HeaderFieldLength - 1 + * @todo Do we want to control max length of header? + * @todo Do we want to control EOL (end-of-line) marker? + * @todo Do we want to translate error message? + */ +function encodeHeaderBase64($string,$charset) { + /** + * Check mbstring function requirements. + */ + if (! function_exists('mb_strlen') || + ! function_exists('mb_substr')) { + // set E_USER_WARNING + trigger_error('encodeHeaderBase64: Required mbstring functions are missing.',E_USER_WARNING); + // return false + return false; + } + + // initial return array + $aRet = array(); + + /** + * header length = 75 symbols max (same as in encodeHeader) + * remove $charset length + * remove =? ? ?= (5 chars) + * remove 2 more chars (\r\n ?) + */ + $iMaxLength = 75 - strlen($charset) - 7; + + // set first character position + $iStartCharNum = 0; + + // loop through all characters. count characters and not bytes. + for ($iCharNum=1; $iCharNum<=mb_strlen($string,$charset); $iCharNum++) { + // encode string from starting character to current character. + $encoded_string = base64_encode(mb_substr($string,$iStartCharNum,$iCharNum-$iStartCharNum,$charset)); + + // Check encoded string length + if(strlen($encoded_string)>$iMaxLength) { + // if string exceeds max length, reduce number of encoded characters and add encoded string part to array + $aRet[] = base64_encode(mb_substr($string,$iStartCharNum,$iCharNum-$iStartCharNum-1,$charset)); + + // set new starting character + $iStartCharNum = $iCharNum-1; + + // encode last char (in case it is last character in string) + $encoded_string = base64_encode(mb_substr($string,$iStartCharNum,$iCharNum-$iStartCharNum,$charset)); + } // if string is shorter than max length - add next character + } + + // add last encoded string to array + $aRet[] = $encoded_string; + + // set initial return string + $sRet = ''; + + // loop through encoded strings + foreach($aRet as $string) { + // TODO: Do we want to control EOL (end-of-line) marker + if ($sRet!='') $sRet.= " "; + + // add header tags and encoded string to return string + $sRet.= '=?'.$charset.'?B?'.$string.'?='; + } + + return $sRet; +} + /* This function trys to locate the entity_id of a specific mime element */ function find_ent_id($id, $message) { for ($i = 0, $ret = ''; $ret == '' && $i < count($message->entities); $i++) { @@ -949,23 +1109,30 @@ function sq_check_save_extension($message) { */ /** - * This function is more or less a wrapper around stripslashes. Apparently - * Explorer is stupid enough to just remove the backslashes and then - * execute the content of the attribute as if nothing happened. - * Who does that? + * This function checks attribute values for entity-encoded values + * and returns them translated into 8-bit strings so we can run + * checks on them. * - * @param attvalue The value of the attribute - * @return attvalue The value of the attribute stripslashed. + * @param $attvalue A string to run entity check against. + * @return Nothing, modifies a reference value. */ -function sq_unbackslash($attvalue){ +function sq_defang(&$attvalue){ + $me = 'sq_defang'; /** - * Remove any backslashes. See if there are any first. + * Skip this if there aren't ampersands or backslashes. */ - - if (strstr($attvalue, '\\') !== false){ - $attvalue = stripslashes($attvalue); + if (strpos($attvalue, '&') === false + && strpos($attvalue, '\\') === false){ + return; } - return $attvalue; + $m = false; + do { + $m = false; + $m = $m || sq_deent($attvalue, '/\�*(\d+);*/s'); + $m = $m || sq_deent($attvalue, '/\�*((\d|[a-f])+);*/si', true); + $m = $m || sq_deent($attvalue, '/\\\\(\d+)/s', true); + } while ($m == true); + $attvalue = stripslashes($attvalue); } /** @@ -974,14 +1141,14 @@ function sq_unbackslash($attvalue){ * be funny to make "java[tab]script" be just as good as "javascript". * * @param attvalue The attribute value before extraneous spaces removed. - * @return attvalue The attribute value after extraneous spaces removed. + * @return attvalue Nothing, modifies a reference value. */ -function sq_unspace($attvalue){ - if (strcspn($attvalue, "\t\r\n") != strlen($attvalue)){ - $attvalue = str_replace(Array("\t", "\r", "\n"), Array('', '', ''), - $attvalue); +function sq_unspace(&$attvalue){ + $me = 'sq_unspace'; + if (strcspn($attvalue, "\t\r\n\0 ") != strlen($attvalue)){ + $attvalue = str_replace(Array("\t", "\r", "\n", "\0", " "), + Array('', '', '', '', ''), $attvalue); } - return $attvalue; } /** @@ -1168,6 +1335,7 @@ function sq_getnxtag($body, $offset){ break; } + $tag_start = $pos; $tagname = ''; /** * Look for next [\W-_], which will indicate the end of the tag name. @@ -1227,6 +1395,7 @@ function sq_getnxtag($body, $offset){ * At this point we loop in order to find all attributes. */ $attname = ''; + $atttype = false; $attary = Array(); while ($pos <= strlen($body)){ @@ -1385,51 +1554,31 @@ function sq_getnxtag($body, $offset){ } /** - * This function checks attribute values for entity-encoded values - * and returns them translated into 8-bit strings so we can run - * checks on them. + * Translates entities into literal values so they can be checked. * - * @param $attvalue A string to run entity check against. - * @return Translated value. + * @param $attvalue the by-ref value to check. + * @param $regex the regular expression to check against. + * @param $hex whether the entites are hexadecimal. + * @return True or False depending on whether there were matches. */ - -function sq_deent($attvalue){ +function sq_deent(&$attvalue, $regex, $hex=false){ $me = 'sq_deent'; - /** - * See if we have to run the checks first. All entities must start - * with "&". - */ - if (strpos($attvalue, '&') === false){ - return $attvalue; - } - /** - * Check named entities first. - */ - $trans = get_html_translation_table(HTML_ENTITIES); - /** - * Leave " in, as it can mess us up. - */ - $trans = array_flip($trans); - unset($trans{'"'}); - while (list($ent, $val) = each($trans)){ - $attvalue = preg_replace('/' . $ent . '*/si', $val, $attvalue); - } - /** - * Now translate numbered entities from 1 to 255 if needed. - */ - if (strpos($attvalue, '#') !== false){ - $omit = Array(34, 39); - for ($asc = 256; $asc >= 0; $asc--){ - if (!in_array($asc, $omit)){ - $chr = chr($asc); - $octrule = '/\�*' . $asc . ';*/si'; - $hexrule = '/\�*' . dechex($asc) . ';*/si'; - $attvalue = preg_replace($octrule, $chr, $attvalue); - $attvalue = preg_replace($hexrule, $chr, $attvalue); + $ret_match = false; + preg_match_all($regex, $attvalue, $matches); + if (is_array($matches) && sizeof($matches[0]) > 0){ + $repl = Array(); + for ($i = 0; $i < sizeof($matches[0]); $i++){ + $numval = $matches[1][$i]; + if ($hex){ + $numval = hexdec($numval); } + $repl{$matches[0][$i]} = chr($numval); } + $attvalue = strtr($attvalue, $repl); + return true; + } else { + return false; } - return $attvalue; } /** @@ -1471,15 +1620,8 @@ function sq_fixatts($tagname, /** * Remove any backslashes, entities, and extraneous whitespace. */ - $attvalue = sq_unbackslash($attvalue); - $attvalue = sq_deent($attvalue); - $attvalue = sq_unspace($attvalue); - - /** - * Remove \r \n \t \0 " " "\\" - */ - $attvalue = str_replace(Array("\r", "\n", "\t", "\0", " ", "\\"), - Array('', '','','','',''), $attvalue); + sq_defang($attvalue); + sq_unspace($attvalue); /** * Now let's run checks on the attvalues. @@ -1565,51 +1707,91 @@ function sq_fixstyle($body, $pos, $message, $id, $mailbox){ $newpos = $ret[0] + strlen($ret[2]); $content = $ret[1]; /** - * First look for general BODY style declaration, which would be - * like so: - * body {background: blah-blah} - * and change it to .bodyclass so we can just assign it to a
- */ + * First look for general BODY style declaration, which would be + * like so: + * body {background: blah-blah} + * and change it to .bodyclass so we can just assign it to a
+ */ $content = preg_replace("|body(\s*\{.*?\})|si", ".bodyclass\\1", $content); $secremoveimg = '../images/' . _("sec_remove_eng.png"); /** - * Fix url('blah') declarations. - */ - $content = preg_replace("|url\s*\(\s*([\'\"])\s*\S+script\s*:.*?([\'\"])\s*\)|si", - "url(\\1$secremoveimg\\2)", $content); - /** - * Fix url('https*://.*) declarations but only if $view_unsafe_images - * is false. - */ - if (!$view_unsafe_images){ - $content = preg_replace("|url\s*\(\s*([\'\"])\s*https*:.*?([\'\"])\s*\)|si", - "url(\\1$secremoveimg\\2)", $content); - } + * Fix url('blah') declarations. + */ + // $content = preg_replace("|url\s*\(\s*([\'\"])\s*\S+script\s*:.*?([\'\"])\s*\)|si", + // "url(\\1$secremoveimg\\2)", $content); + // remove NUL + $content = str_replace("\0", "", $content); + // translate ur\l and variations (IE parses that) + $content = preg_replace("/(\\\\)?u(\\\\)?r(\\\\)?l(\\\\)?/i", 'url', $content); + // NB I insert NUL characters to keep to avoid an infinite loop. They are removed after the loop. + while (preg_match("/url\s*\(\s*[\'\"]?([^:]+):(.*)?[\'\"]?\s*\)/si", $content, $matches)) { + $sProto = strtolower($matches[1]); + switch ($sProto) { + /** + * Fix url('https*://.*) declarations but only if $view_unsafe_images + * is false. + */ + case 'https': + case 'http': + if (!$view_unsafe_images){ - /** - * Fix urls that refer to cid: - */ - while (preg_match("|url\s*\(\s*([\'\"]\s*cid:.*?[\'\"])\s*\)|si", - $content, $matches)){ - $cidurl = $matches{1}; - $httpurl = sq_cid2http($message, $id, $cidurl, $mailbox); - $content = preg_replace("|url\s*\(\s*$cidurl\s*\)|si", - "url($httpurl)", $content); + $sExpr = "/url\s*\(\s*[\'\"]?\s*$sProto*:.*[\'\"]?\s*\)/si"; + $content = preg_replace($sExpr, "u\0r\0l(\\1$secremoveimg\\2)", $content); + + } else { + $content = preg_replace('/url/i',"u\0r\0l",$content); + } + break; + /** + * Fix urls that refer to cid: + */ + case 'cid': + $cidurl = 'cid:'. $matches[2]; + $httpurl = sq_cid2http($message, $id, $cidurl, $mailbox); + // escape parentheses that can modify the regular expression + $cidurl = str_replace(array('(',')'),array('\\(','\\)'),$cidurl); + $content = preg_replace("|url\s*\(\s*$cidurl\s*\)|si", + "u\0r\0l($httpurl)", $content); + break; + default: + /** + * replace url with protocol other then the white list + * http,https and cid by an empty string. + */ + $content = preg_replace("/url\s*\(\s*[\'\"]?([^:]+):(.*)?[\'\"]?\s*\)/si", + "", $content); + break; + } } + // remove NUL + $content = str_replace("\0", "", $content); + /** + * Remove any backslashes, entities, and extraneous whitespace. + */ + $contentTemp = $content; + sq_defang($contentTemp); + sq_unspace($contentTemp); /** * Fix stupid css declarations which lead to vulnerabilities * in IE. */ - $match = Array('/expression/i', - '/behaviou*r/i', - '/binding/i', - '/include-source/i'); - $replace = Array('idiocy', 'idiocy', 'idiocy', 'idiocy'); - $content = preg_replace($match, $replace, $content); + $match = Array('/\/\*.*\*\//', + '/expression/i', + '/behaviou*r/i', + '/binding/i', + '/include-source/i'); + $replace = Array('','idiocy', 'idiocy', 'idiocy', 'idiocy'); + $contentNew = preg_replace($match, $replace, $contentTemp); + if ($contentNew !== $contentTemp) { + // insecure css declarations are used. From now on we don't care + // anymore if the css is destroyed by sq_deent, sq_unspace or sq_unbackslash + $content = $contentNew; + } return array($content, $newpos); } + /** * This function converts cid: url's into the ones that can be viewed in * the browser. @@ -1631,6 +1813,11 @@ function sq_cid2http($message, $id, $cidurl, $mailbox){ $quotchar = ''; } $cidurl = substr(trim($cidurl), 4); + + $match_str = '/\{.*?\}\//'; + $str_rep = ''; + $cidurl = preg_replace($match_str, $str_rep, $cidurl); + $linkurl = find_ent_id($cidurl, $message); /* in case of non-save cid links $httpurl should be replaced by a sort of unsave link image */ @@ -1663,7 +1850,7 @@ function sq_cid2http($message, $id, $cidurl, $mailbox){ * If we couldn't generate a proper img url, drop in a blank image * instead of sending back empty, otherwise it causes unusual behaviour */ - $httpurl = $quotchar . SM_PATH . 'images/blank.png'; + $httpurl = $quotchar . SM_PATH . 'images/blank.png' . $quotchar; } return $httpurl; @@ -1896,6 +2083,7 @@ function sq_sanitize($body, * * @param $body the body of the message * @param $id the id of the message + * @param $message * @param $mailbox * @param boolean $take_mailto_links When TRUE, converts mailto: links @@ -1903,13 +2091,12 @@ function sq_sanitize($body, * (optional; default = TRUE) * @return a string with html safe to display in the browser. */ -function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links = true) { +function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links =true) { - require_once(SM_PATH . 'functions/url_parser.php'); // for $MailTo_PReg_Match + // require_once(SM_PATH . 'functions/url_parser.php'); // for $MailTo_PReg_Match global $attachment_common_show_images, $view_unsafe_images, $has_unsafe_images; - /** * Don't display attached images in HTML mode. */ @@ -1934,6 +2121,7 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links "embed", "title", "frameset", + "xmp", "xml" ); @@ -1973,7 +2161,6 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links "\\1$secremoveimg\\2", "\\1$secremoveimg\\2", "\\1$secremoveimg\\2", - "\\1$secremoveimg\\2" ) ), "/^href|action/i" => @@ -1984,7 +2171,6 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links "/^([\'\"])\s*about\s*:.*([\'\"])/si" ), Array( - "\\1#\\1", "\\1#\\1", "\\1#\\1", "\\1#\\1" @@ -1993,23 +2179,26 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links "/^style/i" => Array( Array( + "/\/\*.*\*\//", "/expression/i", "/binding/i", "/behaviou*r/i", "/include-source/i", "/position\s*:\s*absolute/i", + "/(\\\\)?u(\\\\)?r(\\\\)?l(\\\\)?/i", "/url\s*\(\s*([\'\"])\s*\S+script\s*:.*([\'\"])\s*\)/si", "/url\s*\(\s*([\'\"])\s*mocha\s*:.*([\'\"])\s*\)/si", "/url\s*\(\s*([\'\"])\s*about\s*:.*([\'\"])\s*\)/si", "/(.*)\s*:\s*url\s*\(\s*([\'\"]*)\s*\S+script\s*:.*([\'\"]*)\s*\)/si" ), Array( + "", "idiocy", "idiocy", "idiocy", "idiocy", "", - "url(\\1#\\1)", + "url", "url(\\1#\\1)", "url(\\1#\\1)", "url(\\1#\\1)", @@ -2031,7 +2220,7 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links array_push($bad_attvals{'/.*/'}{'/^src|background/i'}[1], "\\1$secremoveimg\\1"); array_push($bad_attvals{'/.*/'}{'/^style/i'}[0], - '/url\(([\'\"])\s*https*:.*([\'\"])\)/si'); + '/url\([\'\"]?https?:[^\)]*[\'\"]?\)/si'); array_push($bad_attvals{'/.*/'}{'/^style/i'}[1], "url(\\1$secremoveimg\\1)"); } @@ -2058,7 +2247,6 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links $has_unsafe_images = true; } - // we want to parse mailto's in HTML output, change to SM compose links // this is a modified version of code from url_parser.php... but Marc is // right: we need a better filtering implementation; adding this randomly @@ -2067,11 +2255,10 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links if ($take_mailto_links) { // parseUrl($trusted); // this even parses URLs inside of tags... too aggressive global $MailTo_PReg_Match; - $MailTo_PReg_Match = '/mailto:' . substr($MailTo_PReg_Match, 1); + $MailTo_PReg_Match = '/mailto:' . substr($MailTo_PReg_Match, 1) ; if ((preg_match_all($MailTo_PReg_Match, $trusted, $regs)) && ($regs[0][0] != '')) { foreach ($regs[0] as $i => $mailto_before) { $mailto_params = $regs[10][$i]; - // get rid of any tailing quote since we have to add send_to to the end // if (substr($mailto_before, strlen($mailto_before) - 1) == '"') @@ -2131,18 +2318,18 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX', $take_mailto_links */ function SendDownloadHeaders($type0, $type1, $filename, $force, $filesize=0) { global $languages, $squirrelmail_language; - $isIE = $isIE6 = 0; + $isIE = $isIE6plus = false; sqgetGlobalVar('HTTP_USER_AGENT', $HTTP_USER_AGENT, SQ_SERVER); if (strstr($HTTP_USER_AGENT, 'compatible; MSIE ') !== false && strstr($HTTP_USER_AGENT, 'Opera') === false) { - $isIE = 1; + $isIE = true; } - if (strstr($HTTP_USER_AGENT, 'compatible; MSIE 6') !== false && - strstr($HTTP_USER_AGENT, 'Opera') === false) { - $isIE6 = 1; + if (preg_match('/compatible; MSIE ([0-9]+)/', $HTTP_USER_AGENT, $match) && + ((int)$match[1]) >= 6 && strstr($HTTP_USER_AGENT, 'Opera') === false) { + $isIE6plus = true; } if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && @@ -2199,7 +2386,7 @@ function SendDownloadHeaders($type0, $type1, $filename, $force, $filesize=0) { // "attachment"... does it apply to inline too? header ("Content-Disposition: attachment; filename=\"$filename\""); - if ($isIE && !$isIE6) { + if ($isIE && !$isIE6plus) { // This combination seems to work mostly. IE 5.5 SP 1 has // known issues (see the Microsoft Knowledge Base) @@ -2222,5 +2409,3 @@ function SendDownloadHeaders($type0, $type1, $filename, $force, $filesize=0) { } } // end fn SendDownloadHeaders - -?> \ No newline at end of file