* This contains the functions necessary to detect and decode MIME
* messages.
*
- * @copyright 1999-2021 The SquirrelMail Project Team
+ * @copyright 1999-2024 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id$
* @package squirrelmail
if (count($flags)) {
foreach ($flags as $flag) {
//FIXME: please document why it is we have to check the first char of the flag but we then go ahead and do a full string comparison anyway. Is this a speed enhancement? If not, let's keep it simple and just compare the full string and forget the switch block.
- $char = strtoupper($flag{1});
+ $char = strtoupper($flag[1]);
switch ($char) {
case 'S':
if (strtolower($flag) == '\\seen') {
/* There is some information in the content info header that could be important
* in order to parse html messages. Let's get them here.
*/
-// if ($ret{0} == '<') {
+// if ($ret[0] == '<') {
// $data = sqimap_run_command ($imap_stream, "FETCH $id BODY[$ent_id.MIME]", true, $response, $message, TRUE);
// }
} else if (preg_match('/"([^"]*)"/', $topline, $regs)) {
return $ret;
}
-function mime_print_body_lines ($imap_stream, $id, $ent_id=1, $encoding, $rStream='php://stdout', $force_crlf='') {
+// TODO: Needs documentation. $ent_id default is usually 1
+function mime_print_body_lines ($imap_stream, $id, $ent_id, $encoding, $rStream='php://stdout', $force_crlf='') {
/* Don't kill the connection if the browser is over a dialup
* and it would take over 30 seconds to download it.
*/
if ($body_message->header->type1 == 'html') {
- if ($show_html_default <> 1) {
+ // Do we need to make an HTML part viewable as non-HTML plain text?
+ if ($show_html_default != 1) {
$entity_conv = array(' ' => ' ',
- '<p>' => "\n",
- '<P>' => "\n",
- '<br>' => "\n",
- '<BR>' => "\n",
- '<br />' => "\n",
- '<BR />' => "\n",
+ // These are better done by regex (below)
+ // '<p>' => "\n",
+ // '<P>' => "\n",
+ // '<br>' => "\n",
+ // '<BR>' => "\n",
+ // '<br />' => "\n",
+ // '<BR />' => "\n",
+ // '<tr>' => "\n",
+ // '<div>' => "\n",
'>' => '>',
- '<' => '<');
+ '<' => '<',
+ '&' => '&',
+ '©' => '©');
+ // first, completely remove <style> tags as they aren't useful in this context
+ $body = preg_replace('/<style.*>.*<\/style.*>/isU', '', $body);
+ // emulate how newlines are treated as spaces in HTML
+ $body = preg_replace('/(\r|\n)+/', ' ', $body);
+ // now replace the tags listed just above
$body = strtr($body, $entity_conv);
+ // <p>, <br>, <tr> and <div> are best replaced by a newline
+ $body = preg_replace('/<(p|br|tr|div).*>/isU', "\n", $body);
+ // remove the rest of the HTML tags
$body = strip_tags($body);
+ // condense multiple spaces into one
+ $body = preg_replace('/[ \t]+/', ' ', $body);
+ // trim each line
+ $body = preg_replace('/ *\n */', "\n", $body);
+ // allow maximum two newlines
+ $body = preg_replace('/\n\n\n+/', "\n\n", $body);
$body = trim($body);
translateText($body, $wrap_at,
$body_message->header->getParameter('charset'));
case 'Q':
$replace = str_replace('_', ' ', $res[4]);
$replace = preg_replace_callback('/=([0-9a-f]{2})/i',
- create_function ('$matches', 'return chr(hexdec($matches[1]));'),
- $replace);
+ (check_php_version(5, 3, 0)
+ ? function($matches) { return chr(hexdec($matches[1])); }
+ : create_function ('$matches', 'return chr(hexdec($matches[1]));')
+ ),
+ $replace);
if ($utfencode) {
if ($can_be_encoded) {
/* convert string to different charset,
$iEncStart = $enc_init = false;
$cur_l = $iOffset = 0;
for($i = 0; $i < $j; ++$i) {
- switch($string{$i})
+ switch($string[$i])
{
case '"':
case '=':
$ret = '';
$iEncStart = false;
} else {
- $ret .= sprintf("=%02X",ord($string{$i}));
+ $ret .= sprintf("=%02X",ord($string[$i]));
}
break;
case '(':
}
break;
default:
- $k = ord($string{$i});
+ $k = ord($string[$i]);
if ($k > 126) {
if ($iEncStart === false) {
// do not start encoding in the middle of a string, also take the rest of the word.
$cur_l = 0;
$ret = '';
} else {
- $ret .= $string{$i};
+ $ret .= $string[$i];
}
}
}
$matches = Array();
$retarr = Array();
preg_match("%^(.*?)($reg)%si", substr($body, $offset), $matches);
- if (!isset($matches{0}) || !$matches{0}){
+ if (!isset($matches[0]) || !$matches[0]){
$retarr = false;
} else {
- $retarr{0} = $offset + strlen($matches{1});
- $retarr{1} = $matches{1};
- $retarr{2} = $matches{2};
+ $retarr[0] = $offset + strlen($matches[1]);
+ $retarr[1] = $matches[1];
+ $retarr[2] = $matches[2];
}
return $retarr;
}
/**
* Yep. So we did.
*/
- $pos += strlen($matches{1});
- if ($matches{2} == "/>"){
+ $pos += strlen($matches[1]);
+ if ($matches[2] == "/>"){
$tagtype = 3;
$pos++;
}
return $retary;
}
case '>':
- $attary{$attname} = '"yes"';
+ $attary[$attname] = '"yes"';
return Array($tagname, $attary, $tagtype, $lt, $pos);
break;
default:
}
list($pos, $attval, $match) = $regary;
$pos++;
- $attary{$attname} = "'" . $attval . "'";
+ $attary[$attname] = "'" . $attval . "'";
} else if ($quot == '"'){
$regary = sq_findnxreg($body, $pos+1, '\"');
if ($regary == false){
}
list($pos, $attval, $match) = $regary;
$pos++;
- $attary{$attname} = '"' . $attval . '"';
+ $attary[$attname] = '"' . $attval . '"';
} else {
/**
* These are hateful. Look for \s, or >.
* If it's ">" it will be caught at the top.
*/
$attval = preg_replace("/\"/s", """, $attval);
- $attary{$attname} = '"' . $attval . '"';
+ $attary[$attname] = '"' . $attval . '"';
}
} else if (preg_match("|[\w/>]|", $char)) {
/**
* That was attribute type 4.
*/
- $attary{$attname} = '"yes"';
+ $attary[$attname] = '"yes"';
} else {
/**
* An illegal character. Find next '>' and return.
if ($hex){
$numval = hexdec($numval);
}
- $repl{$matches[0][$i]} = chr($numval);
+ $repl[$matches[0][$i]] = chr($numval);
}
$attvalue = strtr($attvalue, $repl);
return true;
if (preg_match($matchtag, $tagname)){
foreach ($matchattrs as $matchattr){
if (preg_match($matchattr, $attname)){
- unset($attary{$attname});
+ unset($attary[$attname]);
continue;
}
}
// entities are used in the attribute value. In 99% of the cases it's there as XSS
// i.e.<div style="{ left:expʀessioɴ( alert('XSS') ) }">
$attvalue = "idiocy";
- $attary{$attname} = $attvalue;
+ $attary[$attname] = $attvalue;
}
sq_unspace($attvalue);
$newvalue =
preg_replace($valmatch, $valrepl, $attvalue);
if ($newvalue != $attvalue){
- $attary{$attname} = $newvalue;
+ $attary[$attname] = $newvalue;
$attvalue = $newvalue;
}
}
if ($attname == 'style') {
if (preg_match('/[\0-\37\200-\377]+/',$attvalue)) {
// 8bit and control characters in style attribute values can be used for XSS, remove them
- $attary{$attname} = '"disallowed character"';
+ $attary[$attname] = '"disallowed character"';
}
preg_match_all("/url\s*\((.+)\)/si",$attvalue,$aMatch);
if (count($aMatch)) {
// url value
$urlvalue = $sMatch;
sq_fix_url($attname, $urlvalue, $message, $id, $mailbox,"'");
- $attary{$attname} = str_replace($sMatch,$urlvalue,$attvalue);
+ $attary[$attname] = str_replace($sMatch,$urlvalue,$attvalue);
}
}
}
|| $attname == 'poster' || $attname == 'formaction'
|| $attname == 'background' || $attname == 'action') {
sq_fix_url($attname, $attvalue, $message, $id, $mailbox);
- $attary{$attname} = $attvalue;
+ $attary[$attname] = $attvalue;
}
}
/**
$bSucces = false;
$bEndTag = false;
for ($i=$pos,$iCount=strlen($body);$i<$iCount;++$i) {
- $char = $body{$i};
+ $char = $body[$i];
switch ($char) {
case '<':
$sToken = $char;
case '!':
if ($sToken == '<') {
// possible comment
- if (isset($body{$i+2}) && substr($body,$i,3) == '!--') {
+ if (isset($body[$i+2]) && substr($body,$i,3) == '!--') {
$i = strpos($body,'-->',$i+3);
if ($i === false) { // no end comment
$i = strlen($body);
$styledef .= "color: $text; ";
}
if (strlen($styledef) > 0){
- $divattary{"style"} = "\"$styledef\"";
+ $divattary["style"] = "\"$styledef\"";
}
}
return $divattary;
if ($tagname == "body"){
$tagname = "div";
}
- if (isset($open_tags{$tagname}) &&
- $open_tags{$tagname} > 0){
- $open_tags{$tagname}--;
+ if (isset($open_tags[$tagname]) &&
+ $open_tags[$tagname] > 0){
+ $open_tags[$tagname]--;
} else {
$tagname = false;
}
$message, $id);
}
if ($tagtype == 1){
- if (isset($open_tags{$tagname})){
- $open_tags{$tagname}++;
+ if (isset($open_tags[$tagname])){
+ $open_tags[$tagname]++;
} else {
- $open_tags{$tagname}=1;
+ $open_tags[$tagname]=1;
}
}
/**
* Remove any references to http/https if view_unsafe_images set
* to false.
*/
- array_push($bad_attvals{'/.*/'}{'/^src|background/i'}[0],
+ array_push($bad_attvals['/.*/']['/^src|background/i'][0],
'/^([\'\"])\s*https*:.*([\'\"])/si');
- array_push($bad_attvals{'/.*/'}{'/^src|background/i'}[1],
+ array_push($bad_attvals['/.*/']['/^src|background/i'][1],
"\\1$secremoveimg\\1");
- array_push($bad_attvals{'/.*/'}{'/^style/i'}[0],
+ array_push($bad_attvals['/.*/']['/^style/i'][0],
'/url\([\'\"]?https?:[^\)]*[\'\"]?\)/si');
- array_push($bad_attvals{'/.*/'}{'/^style/i'}[1],
+ array_push($bad_attvals['/.*/']['/^style/i'][1],
"url(\\1$secremoveimg\\1)");
}