X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=functions%2Fmime.php;h=57ab298121fddc10171f21ccc5a026973688da7a;hb=78bc908d4b41bc0c707237e8449fce2dc22e54c6;hp=1419d58854dd7a859d3140abc07a842c07a9886a;hpb=09f4707eb2e7aad4d822ea42e9b42f4c0d7b7396;p=squirrelmail.git diff --git a/functions/mime.php b/functions/mime.php index 1419d588..57ab2981 100644 --- a/functions/mime.php +++ b/functions/mime.php @@ -3,7 +3,7 @@ /** * mime.php * - * Copyright (c) 1999-2002 The SquirrelMail Project Team + * Copyright (c) 1999-2003 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 @@ -29,23 +29,22 @@ function mime_structure ($bodystructure, $flags=array()) { /* Isolate the body structure and remove beginning and end parenthesis. */ $read = trim(substr ($bodystructure, strpos(strtolower($bodystructure), 'bodystructure') + 13)); $read = trim(substr ($read, 0, -1)); - $msg =& new Message(); - $res = $msg->parseStructure($read); - $msg = $res[0]; + $i = 0; + $msg = Message::parseStructure($read,$i); if (!is_object($msg)) { include_once(SM_PATH . 'functions/display_messages.php'); global $color, $mailbox; - displayPageHeader( $color, urldecode($mailbox) ); + /* removed urldecode because $_GET is auto urldecoded ??? */ + displayPageHeader( $color, $mailbox ); echo "\n\n" . '
'; - $errormessage = _("Squirrelmail could not decode the bodystructure of the message"); + $errormessage = _("SquirrelMail could not decode the bodystructure of the message"); $errormessage .= '
'._("the provided bodystructure by your imap-server").':

'; $errormessage .= '
' . htmlspecialchars($read) . '
'; plain_error_message( $errormessage, $color ); echo ''; exit; } - $msg->setEnt('0'); if (count($flags)) { foreach ($flags as $flag) { $char = strtoupper($flag{1}); @@ -84,6 +83,8 @@ function mime_structure ($bodystructure, $flags=array()) { return $msg; } + + /* This starts the parsing of a particular structure. It is called recursively, * so it can be passed different structures. It returns an object of type * $message. @@ -93,15 +94,16 @@ function mime_structure ($bodystructure, $flags=array()) { * to mime_get_elements() */ -function mime_fetch_body($imap_stream, $id, $ent_id) { +function mime_fetch_body($imap_stream, $id, $ent_id=1) { global $uid_support; /* Do a bit of error correction. If we couldn't find the entity id, just guess * that it is the first one. That is usually the case anyway. */ if (!$ent_id) { - $ent_id = 1; + $cmd = "FETCH $id BODY[]"; + } else { + $cmd = "FETCH $id BODY[$ent_id]"; } - $cmd = "FETCH $id BODY[$ent_id]"; $data = sqimap_run_command ($imap_stream, $cmd, true, $response, $message, $uid_support); do { @@ -114,9 +116,9 @@ function mime_fetch_body($imap_stream, $id, $ent_id) { /* 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} == '<') { - $data = sqimap_run_command ($imap_stream, "FETCH $id BODY[$ent_id.MIME]", true, $response, $message, $uid_support); - } +// if ($ret{0} == '<') { +// $data = sqimap_run_command ($imap_stream, "FETCH $id BODY[$ent_id.MIME]", true, $response, $message, $uid_support); +// } } else if (ereg('"([^"]*)"', $topline, $regs)) { $ret = $regs[1]; } else { @@ -134,14 +136,12 @@ function mime_fetch_body($imap_stream, $id, $ent_id) { echo '
' . '' . '' . - '" . - '" . - '" . - '" . + '" . + '" . + '" . + '" . "
' . - _("Body retrieval error. The reason for this is most probably that the message is malformed. Please help us making future versions better by submitting this message to the developers knowledgebase!") . - "
" . - _("Submit message") . '

 ' . + _("Body retrieval error. The reason for this is most probably that the message is malformed.") . '
' . _("Command:") . "$cmd
' . _("Response:") . "$response
' . _("Message:") . "$message
' . _("FETCH line:") . "$topline
' . _("Command:") . "$cmd
' . _("Response:") . "$response
' . _("Message:") . "$message
' . _("FETCH line:") . "$topline


"; $data = sqimap_run_command ($imap_stream, "FETCH $passed_id BODY[]", true, $response, $message, $uid_support); @@ -153,14 +153,9 @@ function mime_fetch_body($imap_stream, $id, $ent_id) { return $ret; } -function mime_print_body_lines ($imap_stream, $id, $ent_id, $encoding) { +function mime_print_body_lines ($imap_stream, $id, $ent_id=1, $encoding) { global $uid_support; - /* Do a bit of error correction. If we couldn't find the entity id, just guess - * that it is the first one. That is usually the case anyway. - */ - if (!$ent_id) { - $ent_id = 1; - } + $sid = sqimap_session_id($uid_support); /* Don't kill the connection if the browser is over a dialup * and it would take over 30 seconds to download it. @@ -296,16 +291,16 @@ function translateText(&$body, $wrap_at, $charset) { } } - if ($quotes > 1) { - if (!isset($color[14])) { - $color[14] = '#FF0000'; - } - $line = '' . $line . ''; - } elseif ($quotes) { + if ($quotes % 2) { if (!isset($color[13])) { $color[13] = '#800000'; } - $line = '' . $line . ''; + $line = '' . $line . ''; + } elseif ($quotes) { + if (!isset($color[14])) { + $color[14] = '#FF0000'; + } + $line = '' . $line . ''; } $body_ary[$i] = $line; @@ -313,7 +308,6 @@ function translateText(&$body, $wrap_at, $charset) { $body = '
' . implode("\n", $body_ary) . '
'; } - /* This returns a parsed string called $body. That string can then * be displayed as the actual message in the HTML. It contains * everything needed, including HTML Tags, Attachments at the @@ -325,9 +319,13 @@ function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $ma * order that is their priority. */ global $startMessage, $username, $key, $imapServerAddress, $imapPort, - $show_html_default, $has_unsafe_images, $view_unsafe_images, $sort; + $show_html_default, $sort, $has_unsafe_images, $passed_ent_id; + global $languages, $squirrelmail_language; + + if( !sqgetGlobalVar('view_unsafe_images', $view_unsafe_images, SQ_GET) ) { + $view_unsafe_images = false; + } - $has_unsafe_images= 0; $body = ''; $urlmailbox = urlencode($mailbox); $body_message = getEntity($message, $ent_num); @@ -335,6 +333,13 @@ function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $ma ($body_message->header->type0 == 'rfc822')) { $body = mime_fetch_body ($imap_stream, $id, $ent_num); $body = decodeBody($body, $body_message->header->encoding); + + if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && + function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) { + if (mb_detect_encoding($body) != 'ASCII') { + $body = $languages[$squirrelmail_language]['XTRA_CODE']('decode', $body); + } + } $hookResults = do_hook("message_body", $body); $body = $hookResults[1]; @@ -363,18 +368,24 @@ function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $ma translateText($body, $wrap_at, $body_message->header->getParameter('charset')); } - - if ($has_unsafe_images) { - if ($view_unsafe_images) { - $untext = '">' . _("Hide Unsafe Images"); + $link = 'read_body.php?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; + } + if ($view_unsafe_images) { + $text = _("Hide Unsafe Images"); + } else { + if (isset($has_unsafe_images) && $has_unsafe_images) { + $link .= '&view_unsafe_images=1'; + $text = _("View Unsafe Images"); } else { - $untext = '&view_unsafe_images=1">' . _("View Unsafe Images"); + $text = ''; } - $body .= '
'.$text. + '

' . "\n"; } return $body; } @@ -393,54 +404,63 @@ function formatAttachments($message, $exclude_id, $mailbox, $id) { $urlMailbox = urlencode($mailbox); foreach ($att_ar as $att) { - $ent = urldecode($att->entity_id); + $ent = $att->entity_id; $header = $att->header; $type0 = strtolower($header->type0); $type1 = strtolower($header->type1); $name = ''; $links['download link']['text'] = _("download"); - $links['download link']['href'] = - "../src/download.php?absolute_dl=true&passed_id=$id&mailbox=$urlMailbox&ent_id=$ent"; + $links['download link']['href'] = SM_PATH . + "src/download.php?absolute_dl=true&passed_id=$id&mailbox=$urlMailbox&ent_id=$ent"; $ImageURL = ''; if ($type0 =='message' && $type1 == 'rfc822') { - $default_page = '../src/read_body.php'; + $default_page = SM_PATH . 'src/read_body.php'; $rfc822_header = $att->rfc822_header; - $filename = decodeHeader($rfc822_header->subject); - + $filename = $rfc822_header->subject; + if (trim( $filename ) == '') { + $filename = 'untitled-[' . $ent . ']' ; + } $from_o = $rfc822_header->from; if (is_object($from_o)) { $from_name = $from_o->getAddress(false); } else { $from_name = _("Unknown sender"); } - $from_name = decodeHeader(htmlspecialchars($from_name)); + $from_name = decodeHeader(($from_name)); $description = $from_name; } else { - $default_page = '../src/download.php'; + $default_page = SM_PATH . 'src/download.php'; if (is_object($header->disposition)) { - $filename = decodeHeader($header->disposition->getProperty('filename')); + $filename = $header->disposition->getProperty('filename'); if (trim($filename) == '') { $name = decodeHeader($header->disposition->getProperty('name')); if (trim($name) == '') { - if (trim( $header->id ) == '') { - $filename = 'untitled-[' . $ent . ']' ; + $name = $header->getParameter('name'); + if(trim($name) == '') { + if (trim( $header->id ) == '') { + $filename = 'untitled-[' . $ent . ']' ; + } else { + $filename = 'cid: ' . $header->id; + } } else { - $filename = 'cid: ' . $header->id; + $filename = $name; } } else { $filename = $name; } } } else { - if (trim( $header->id ) == '') { - $filename = 'untitled-[' . $ent . ']' ; - } else { - $filename = 'cid: ' . $header->id; + $filename = $header->getParameter('name'); + if (!trim($filename)) { + if (trim( $header->id ) == '') { + $filename = 'untitled-[' . $ent . ']' ; + } else { + $filename = 'cid: ' . $header->id; + } } } - if ($header->description) { - $description = htmlspecialchars($header->description); + $description = decodeHeader($header->description); } else { $description = ''; } @@ -475,7 +495,7 @@ function formatAttachments($message, $exclude_id, $mailbox, $id) { $defaultlink = $hookresults[6]; $attachments .= '' . - "$display_filename " . + ''.decodeHeader($display_filename).' ' . '' . show_readable_size($header->size) . '  ' . "[ $type0/$type1 ] " . @@ -500,7 +520,6 @@ function formatAttachments($message, $exclude_id, $mailbox, $id) { /* This function decodes the body depending on the encoding type. */ function decodeBody($body, $encoding) { - global $languages, $squirrelmail_language; global $show_html_default; $body = str_replace("\r\n", "\n", $body); @@ -518,11 +537,6 @@ function decodeBody($body, $encoding) { $body = base64_decode($body); } - if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && - function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) { - $body = $languages[$squirrelmail_language]['XTRA_CODE']('decode', $body); - } - // All other encodings are returned raw. return $body; } @@ -532,43 +546,102 @@ function decodeBody($body, $encoding) { * RFC1522 (MIME Part Two: Message Header Extensions for Non-ASCII Text). * Patched by Christian Schmidt 23/03/2002 */ -function decodeHeader ($string, $utfencode=true) { +function decodeHeader ($string, $utfencode=true,$htmlsave=true) { global $languages, $squirrelmail_language; if (is_array($string)) { $string = implode("\n", $string); } - + if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) { $string = $languages[$squirrelmail_language]['XTRA_CODE']('decodeheader', $string); + // Do we need to return at this point? + // return $string; } - $i = 0; - while (preg_match('/^(.{' . $i . '})(.*)=\?([^?]*)\?(Q|B)\?([^?]*)\?=/Ui', - $string, $res)) { - $prefix = $res[1]; - /* Ignore white-space between consecutive encoded-words. */ - if (strspn($res[2], " \t") != strlen($res[2])) { - $prefix .= $res[2]; - } + $iLastMatch = -2; + $encoded = false; - if (ucfirst($res[4]) == 'B') { - $replace = base64_decode($res[5]); - } else { - $replace = str_replace('_', ' ', $res[5]); - $replace = preg_replace('/=([0-9a-f]{2})/ie', 'chr(hexdec("\1"))', + $aString = explode(' ',$string); + $ret = ''; + foreach ($aString as $chunk) { + if ($encoded && !$chunk) { + continue; + } elseif (!$chunk) { + $ret .= ' '; + continue; + } + $encoded = false; + /* if encoded words are not separated by a linear-space-white we still catch them */ + $j = $i-1; + if ($chunk{0} === '=') { /* performance, saves an unnessecarry preg call */ + while ($match = preg_match('/^(.*)=\?([^?]*)\?(Q|B)\?([^?]*)\?=(.*)$/Ui',$chunk,$res)) { + /* if the last chunk isn't an encoded string then put back the space, otherwise don't */ + if ($iLastMatch !== $j) { + if ($htmlsave) { + $ret .= ' '; + } else { + $ret .= ' '; + } + } + $iLastMatch = $i; + $j = $i; + $ret .= $res[1]; + $encoding = ucfirst($res[3]); + switch ($encoding) + { + case 'B': + $replace = base64_decode($res[4]); + $ret .= charset_decode($res[2],$replace); + break; + case 'Q': + $replace = str_replace('_', ' ', $res[4]); + $replace = preg_replace('/=([0-9a-f]{2})/ie', 'chr(hexdec("\1"))', $replace); - /* Only encode into entities by default. Some places - * don't need the encoding, like the compose form. - */ - if ($utfencode) { - $replace = charset_decode($res[3], $replace); + /* Only encode into entities by default. Some places + * don't need the encoding, like the compose form. + */ + if ($utfencode) { + $replace = charset_decode($res[2], $replace); + } else { + if ($htmlsave) { + $replace = htmlspecialchars($replace); + } + } + $ret .= $replace; + break; + default: + break; } + $chunk = $res[5]; + $encoded = true; + } + } + if (!$encoded) { + if ($htmlsave) { + $ret .= ' '; + } else { + $ret .= ' '; + } + } + + if (!$encoded && $htmlsave) { + $ret .= htmlspecialchars($chunk); + } else { + $ret .= $chunk; } - $string = $prefix . $replace . substr($string, strlen($res[0])); - $i = strlen($prefix) + strlen($replace); + ++$i; } - return $string; + /* remove the first added space */ + if ($ret) { + if ($htmlsave) { + $ret = substr($ret,6); + } else { + $ret = substr($ret,1); + } + } + + return $ret; } /* @@ -583,41 +656,114 @@ function encodeHeader ($string) { function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) { return $languages[$squirrelmail_language]['XTRA_CODE']('encodeheader', $string); } + if (strtolower($default_charset) == 'iso-8859-1') { + $string = str_replace("\240",' ',$string); + } // Encode only if the string contains 8-bit characters or =? $j = strlen($string); - $l = strstr($string, '=?'); // Must be encoded ? + $max_l = 75 - strlen($default_charset) - 7; + $aRet = array(); $ret = ''; + $iEncStart = $enc_init = false; + $cur_l = $iOffset = 0; for($i = 0; $i < $j; ++$i) { - switch($string{$i}) { - case '=': - $ret .= '=3D'; - break; - case '?': - $ret .= '=3F'; - break; - case '_': - $ret .= '=5F'; - break; - case ' ': - $ret .= '_'; - break; - default: - $k = ord($string{$i}); - if ($k > 126) { - $ret .= sprintf("=%02X", $k); - $l = TRUE; + switch($string{$i}) + { + case '=': + case '<': + case '>': + case ',': + case '?': + case '_': + if ($iEncStart === false) { + $iEncStart = $i; + } + $cur_l+=3; + if ($cur_l > ($max_l-2)) { + /* if there is an stringpart that doesn't need encoding, add it */ + $aRet[] = substr($string,$iOffset,$iEncStart-$iOffset); + $aRet[] = "=?$default_charset?Q?$ret?="; + $iOffset = $i; + $cur_l = 0; + $ret = ''; + $iEncStart = false; + } else { + $ret .= sprintf("=%02X",ord($string{$i})); + } + break; + case '(': + case ')': + if ($iEncStart !== false) { + $aRet[] = substr($string,$iOffset,$iEncStart-$iOffset); + $aRet[] = "=?$default_charset?Q?$ret?="; + $iOffset = $i; + $cur_l = 0; + $ret = ''; + $iEncStart = false; + } + break; + case ' ': + if ($iEncStart !== false) { + $cur_l++; + if ($cur_l > $max_l) { + $aRet[] = substr($string,$iOffset,$iEncStart-$iOffset); + $aRet[] = "=?$default_charset?Q?$ret?="; + $iOffset = $i; + $cur_l = 0; + $ret = ''; + $iEncStart = false; } else { - $ret .= $string{$i}; + $ret .= '_'; } - break; + } + break; + default: + $k = ord($string{$i}); + if ($k > 126) { + if ($iEncStart === false) { + $iEncStart = $i; + } + $cur_l += 3; + /* first we add the encoded string that reached it's max size */ + if ($cur_l > ($max_l-2)) { + $aRet[] = substr($string,$iOffset,$iEncStart-$iOffset); + $aRet[] = "=?$default_charset?Q?$ret?= "; /* the next part is also encoded => separate by space */ + $cur_l = 3; + $ret = ''; + $iOffset = $i; + $iEncStart = $i; + } + $enc_init = true; + $ret .= sprintf("=%02X", $k); + } else { + if ($iEncStart !== false) { + $cur_l++; + if ($cur_l > $max_l) { + $aRet[] = substr($string,$iOffset,$iEncStart-$iOffset); + $aRet[] = "=?$default_charset?Q?$ret?="; + $iEncStart = false; + $iOffset = $i; + $cur_l = 0; + $ret = ''; + } else { + $ret .= $string{$i}; + } + } + } + break; } } - if ($l) { - $string = "=?$default_charset?Q?$ret?="; + if ($enc_init) { + if ($iEncStart !== false) { + $aRet[] = substr($string,$iOffset,$iEncStart-$iOffset); + $aRet[] = "=?$default_charset?Q?$ret?="; + } else { + $aRet[] = substr($string,$iOffset); + } + $string = implode('',$aRet); } - return $string; } @@ -628,9 +774,9 @@ function find_ent_id($id, $message) { $ret = find_ent_id($id, $message->entities[$i]); } else { if (strcasecmp($message->entities[$i]->header->id, $id) == 0) { - if (sq_check_save_extension($message->entities[$i])) { +// if (sq_check_save_extension($message->entities[$i])) { return $message->entities[$i]->entity_id; - } +// } } } } @@ -1215,7 +1361,7 @@ function sq_fixstyle($message, $id, $content){ $content = preg_replace("|url\(([\'\"])\s*https*:.*?([\'\"])\)|si", "url(\\1$secremoveimg\\2)", $content); } - + /** * Fix urls that refer to cid: */ @@ -1231,9 +1377,9 @@ function sq_fixstyle($message, $id, $content){ * Fix stupid css declarations which lead to vulnerabilities * in IE. */ - $match = Array('/expression/si', - '/behaviou*r/si', - '/binding/si'); + $match = Array('/expression/i', + '/behaviou*r/i', + '/binding/i'); $replace = Array('idiocy', 'idiocy', 'idiocy'); $content = preg_replace($match, $replace, $content); return $content; @@ -1260,7 +1406,7 @@ function sq_cid2http($message, $id, $cidurl, $mailbox){ unsave link image */ $httpurl = ''; if ($linkurl) { - $httpurl = $quotchar . '../src/download.php?absolute_dl=true&' . + $httpurl = $quotchar . SM_PATH . 'src/download.php?absolute_dl=true&' . "passed_id=$id&mailbox=" . urlencode($mailbox) . '&ent_id=' . $linkurl . $quotchar; } @@ -1482,7 +1628,7 @@ function sq_sanitize($body, * @param $id the id of the message * @return a string with html safe to display in the browser. */ -function magicHTML($body, $id, $message, $mailbox = 'INBOX'){ +function magicHTML($body, $id, $message, $mailbox = 'INBOX') { global $attachment_common_show_images, $view_unsafe_images, $has_unsafe_images; /** @@ -1497,8 +1643,8 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX'){ "head", "base", "link", - "frame", - "iframe" + "frame", + "iframe" ); $rm_tags_with_content = Array( @@ -1520,10 +1666,11 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX'){ $rm_attnames = Array( "/.*/" => Array( - "/target/si", - "/^on.*/si", - "/^dynsrc/si", - "/^data.*/si" + "/target/i", + "/^on.*/i", + "/^dynsrc/i", + "/^data.*/i", + "/^lowsrc.*/i" ) ); @@ -1561,12 +1708,12 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX'){ "\\1#\\2" ) ), - "/^style/si" => + "/^style/i" => Array( Array( - "/expression/si", - "/binding/si", - "/behaviou*r/si", + "/expression/i", + "/binding/i", + "/behaviou*r/i", "|url\(([\'\"])\s*\.\./.*([\'\"])\)|si", "/url\(([\'\"])\s*\S+script\s*:.*([\'\"])\)/si", "/url\(([\'\"])\s*mocha\s*:.*([\'\"])\)/si", @@ -1584,6 +1731,9 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX'){ ) ) ); + if( !sqgetGlobalVar('view_unsafe_images', $view_unsafe_images, SQ_GET) ) { + $view_unsafe_images = false; + } if (!$view_unsafe_images){ /** * Remove any references to http/https if view_unsafe_images set @@ -1593,14 +1743,14 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX'){ '/^([\'\"])\s*https*:.*([\'\"])/si'); array_push($bad_attvals{'/.*/'}{'/^src|background/i'}[1], "\\1$secremoveimg\\2"); - array_push($bad_attvals{'/.*/'}{'/^style/si'}[0], + array_push($bad_attvals{'/.*/'}{'/^style/i'}[0], '/url\(([\'\"])\s*https*:.*([\'\"])\)/si'); - array_push($bad_attvals{'/.*/'}{'/^style/si'}[1], + array_push($bad_attvals{'/.*/'}{'/^style/i'}[1], "url(\\1$secremoveimg\\2)"); } $add_attr_to_tag = Array( - "/^a$/si" => Array('target'=>'"_new"') + "/^a$/i" => Array('target'=>'"_new"') ); $trusted = sq_sanitize($body, $tag_list, @@ -1614,7 +1764,7 @@ function magicHTML($body, $id, $message, $mailbox = 'INBOX'){ $id, $mailbox ); - if (preg_match("|$secremoveimg|si", $trusted)){ + if (preg_match("|$secremoveimg|i", $trusted)){ $has_unsafe_images = true; } return $trusted;