X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=functions%2Fmime.php;h=0a7326c491a9cbd2ca5db47d95df84aa3764cb26;hb=7e235a1a75c0544d1b41270f54568990b3af112a;hp=5745addd54cfc49c02a63c8751f42e9950b61b64;hpb=451f74a279b4ccf8205e1a2038e5750daaf1cd86;p=squirrelmail.git diff --git a/functions/mime.php b/functions/mime.php index 5745addd..0a7326c4 100644 --- a/functions/mime.php +++ b/functions/mime.php @@ -20,12 +20,11 @@ class msg_header { /** msg_header contains generic variables for values that **/ /** could be in a header. **/ - var $type0 = '', $type1 = '', $boundary = '', $charset = ''; - var $encoding = '', $size = 0, $to = array(), $from = '', $date = ''; - var $cc = array(), $bcc = array(), $reply_to = '', $subject = ''; - var $id = 0, $mailbox = '', $description = '', $filename = ''; - var $entity_id = 0, $message_id = 0, $name = ''; - // var $priority = ""; + var $type0 = '', $type1 = '', $boundary = '', $charset = '', + $encoding = '', $size = 0, $to = array(), $from = '', $date = '', + $cc = array(), $bcc = array(), $reply_to = '', $subject = '', + $id = 0, $mailbox = '', $description = '', $filename = '', + $entity_id = 0, $message_id = 0, $name = '', $priority = 3; } class message { @@ -34,9 +33,8 @@ class message { more objects of type message. See documentation in mime.txt for a better description of how this works. **/ - var $header = ''; - var $entities = array(); - + var $header = '', $entities = array(); + function addEntity ($msg) { $this->entities[] = $msg; } @@ -60,15 +58,15 @@ function mime_structure ($imap_stream, $header) { // // This should use sqimap_read_data instead of reading it itself // - $read = fgets ($imap_stream, 10000); + $read = fgets ($imap_stream, 9216); $bodystructure = ''; while ( substr($read, 0, $lsid) <> $ssid && !feof( $imap_stream ) ) { $bodystructure .= $read; - $read = fgets ($imap_stream, 10000); + $read = fgets ($imap_stream, 9216); } $read = $bodystructure; - + // isolate the body structure and remove beginning and end parenthesis $read = trim(substr ($read, strpos(strtolower($read), 'bodystructure') + 13)); $read = trim(substr ($read, 0, -1)); @@ -78,10 +76,10 @@ function mime_structure ($imap_stream, $header) { $read = trim(substr ($read, 1)); $end = mime_match_parenthesis(0, $read); } - + $msg = mime_parse_structure ($read, 0); $msg->header = $header; - + return( $msg ); } @@ -121,15 +119,15 @@ function mime_parse_structure ($structure, $ent_id) { */ function mime_increment_id ($id) { - if (strpos($id, ".")) { - $first = substr($id, 0, strrpos($id, ".")); - $last = substr($id, strrpos($id, ".")+1); + if (strpos($id, '.')) { + $first = substr($id, 0, strrpos($id, '.')); + $last = substr($id, strrpos($id, '.')+1); $last++; - $new = $first . "." .$last; + $new = $first . '.' .$last; } else { $new = $id + 1; } - + return $new; } @@ -143,13 +141,13 @@ function mime_increment_id ($id) { */ function mime_new_element_level ($id) { - if (!$id) { - $id = 0; - } else { - $id = $id . '.0'; - } + if (!$id) { + $id = 0; + } else { + $id = $id . '.0'; + } - return( $id ); + return( $id ); } function mime_get_element (&$structure, $msg, $ent_id) { @@ -371,78 +369,91 @@ function mime_match_parenthesis ($pos, $structure) { return( $pos ); } -function mime_fetch_body ($imap_stream, $id, $ent_id ) { - // 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) +function mime_fetch_body($imap_stream, $id, $ent_id ) { + + /* + * 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(); - fputs ($imap_stream, "$sid FETCH $id BODY[$ent_id]\r\n"); - $data = sqimap_read_data ($imap_stream, $sid, true, $response, $message); - $topline = array_shift($data); - while (! ereg('\\* [0-9]+ FETCH ', $topline) && $data) - $topline = array_shift($data); + } + + $cmd = "FETCH $id BODY[$ent_id]"; + $data = sqimap_run_command ($imap_stream, $cmd, true, $response, $message); + + do { + $topline = array_shift( $data ); + } while( $topline && $topline == '*' && !preg_match( '/\\* [0-9] FETCH.*/i', $topline )) ; $wholemessage = implode('', $data); if (ereg('\\{([^\\}]*)\\}', $topline, $regs)) { + $ret = substr( $wholemessage, 0, $regs[1] ); /* 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} == '<' ) { - fputs ($imap_stream, "$sid FETCH $id BODY[$ent_id.MIME]\r\n"); - $data = sqimap_read_data ($imap_stream, $sid, true, $response, $message); - $base = ''; - $k = 10; - foreach( $data as $d ) { - if ( substr( $d, 0, 13 ) == 'Content-Base:' ) { - $j = strlen( $d ); - $i = 13; - $base = ''; - while ( $i < $j && - ( !isNoSep( $d{$i} ) || $d{$i} == '"' ) ) - $i++; - while ( $i < $j ) { - if ( isNoSep( $d{$i} ) ) - $base .= $d{$i}; - $i++; - } - $k = 0; - } elseif ( $k == 1 && !isnosep( $d{0} ) ) { - $base .= substr( $d, 1 ); - } - $k++; - } - if ( $base <> '' ) - $ret = "" . $ret; + $data = sqimap_run_command ($imap_stream, "FETCH $id BODY[$ent_id.MIME]", true, $response, $message); + /* BASE within HTML documents is illegal (see w3 spec) +* $base = ''; +* $k = 10; +* foreach( $data as $d ) { +* if ( substr( $d, 0, 13 ) == 'Content-Base:' ) { +* $j = strlen( $d ); +* $i = 13; +* $base = ''; +* while ( $i < $j && +* ( !isNoSep( $d{$i} ) || $d{$i} == '"' ) ) +* $i++; +* while ( $i < $j ) { +* if ( isNoSep( $d{$i} ) ) +* $base .= $d{$i}; +* $i++; +* } +* $k = 0; +* } elseif ( $k == 1 && !isnosep( $d{0} ) ) { +* $base .= substr( $d, 1 ); +* } +* $k++; +* } +* if ( $base <> '' ) { +* $ret = "" . $ret; +* } +* */ } } else if (ereg('"([^"]*)"', $topline, $regs)) { $ret = $regs[1]; } else { global $where, $what, $mailbox, $passed_id, $startMessage; - $par = "mailbox=".urlencode($mailbox)."&passed_id=$passed_id"; + $par = 'mailbox=' . urlencode($mailbox) . "&passed_id=$passed_id"; if (isset($where) && isset($what)) { - $par .= "&where=".urlencode($where)."&what=".urlencode($what); + $par .= '&where='. urlencode($where) . "&what=" . urlencode($what); } else { - $par .= "&startMessage=$startMessage&show_more=0"; + $par .= "&startMessage=$startMessage&show_more=0"; } - $par .= '&response='.urlencode($response).'&message='.urlencode($message). - '&topline='.urlencode($topline); + $par .= '&response=' . urlencode($response) . + '&message=' . urlencode($message). + '&topline=' . urlencode($topline); - echo '' . + 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
" . - '' . _("Response:") . "$response
" . - _("Message:") . " $message
" . - _("FETCH line:") . " $topline
"; - - fputs ($imap_stream, "$sid FETCH $passed_id BODY[]\r\n"); - $data = sqimap_read_data ($imap_stream, $sid, true, $response, $message); + "
" . + _("Submit message") . '

 ' . + '
' . _("Command:") . "$cmd
' . _("Response:") . "$response
' . _("Message:") . "$message
' . _("FETCH line:") . "$topline


"; + + $data = sqimap_run_command ($imap_stream, "FETCH $passed_id BODY[]", true, $response, $message); array_shift($data); $wholemessage = implode('', $data); - $ret = "---------------\n$wholemessage"; - + $ret = $wholemessage; } return( $ret ); } @@ -456,8 +467,12 @@ function mime_print_body_lines ($imap_stream, $id, $ent_id, $encoding) { $sid = sqimap_session_id(); // Don't kill the connection if the browser is over a dialup // and it would take over 30 seconds to download it. - set_time_limit(0); - + + // donĀ“t call set_time_limit in safe mode. + if (!ini_get("safe_mode")) { + set_time_limit(0); + } + fputs ($imap_stream, "$sid FETCH $id BODY[$ent_id]\r\n"); $cnt = 0; $continue = true; @@ -538,6 +553,7 @@ function findDisplayEntity ($message, $textOnly = 1) { if ($message) { if ( $message->header->type0 == 'multipart' && ( $message->header->type1 == 'alternative' || + $message->header->type1 == 'mixed' || $message->header->type1 == 'related' ) && $show_html_default && ! $textOnly ) { $entity = findDisplayEntityHTML($message); @@ -589,24 +605,26 @@ function formatBody($imap_stream, $message, $color, $wrap_at) { // this if statement checks for the entity to show as the // primary message. To add more of them, just put them in the // order that is their priority. - global $startMessage, $username, $key, $imapServerAddress, $imapPort, - $show_html_default; - + global $startMessage, $username, $key, $imapServerAddress, $imapPort, $body, + $show_html_default, $has_unsafe_images, $view_unsafe_images, $sort; + + $has_unsafe_images = 0; + $id = $message->header->id; $urlmailbox = urlencode($message->header->mailbox); - + // Get the right entity and redefine message to be this entity // Pass the 0 to mean that we want the 'best' viewable one $ent_num = findDisplayEntity ($message, 0); $body_message = getEntity($message, $ent_num); if (($body_message->header->type0 == 'text') || ($body_message->header->type0 == 'rfc822')) { - + $body = mime_fetch_body ($imap_stream, $id, $ent_num); $body = decodeBody($body, $body_message->header->encoding); $hookResults = do_hook("message_body", $body); $body = $hookResults[1]; - + // If there are other types that shouldn't be formatted, add // them here if ($body_message->header->type1 == 'html') { @@ -619,15 +637,20 @@ function formatBody($imap_stream, $message, $color, $wrap_at) { } else { translateText($body, $wrap_at, $body_message->header->charset); } - - $body .= "
". _("Download this as a file") ."

"; - + + $body .= "
". _("Download this as a file") ."

"; + if ($has_unsafe_images) { + if ($view_unsafe_images) { + $body .= "
". _("Hide Unsafe Images") ."

\n"; + } else { + $body .= "
". _("View Unsafe Images") ."

\n"; + } + } + /** Display the ATTACHMENTS: message if there's more than one part **/ - $body .= ""; if (isset($message->entities[0])) { $body .= formatAttachments ($message, $ent_num, $message->header->mailbox, $id); } - $body .= ""; } else { $body = formatAttachments ($message, -1, $message->header->mailbox, $id); } @@ -638,100 +661,109 @@ function formatBody($imap_stream, $message, $color, $wrap_at) { * A recursive function that returns a list of attachments with links * to where to download these attachments */ -function formatAttachments ($message, $ent_id, $mailbox, $id) { - global $where, $what; - global $startMessage, $color; - static $ShownHTML = 0; +function formatAttachments($message, $ent_id, $mailbox, $id) { + global $where, $what; + global $startMessage, $color; + static $ShownHTML = 0; - $body = ""; - if ($ShownHTML == 0) { - $ShownHTML = 1; + $body = ''; + if ($ShownHTML == 0) { + $ShownHTML = 1; $body .= "\n" . - "
\n" . - _("Attachments") . ':' . - "
\n" . - "\n" . - formatAttachments ($message, $ent_id, $mailbox, $id) . - "
"; - - return( $body ); - } + "\n" . + _("Attachments") . ':' . + "\n" . + "\n" . + formatAttachments($message, $ent_id, $mailbox, $id) . + "
"; + + } else if ($message) { + + if (!$message->entities) { + + $type0 = strtolower($message->header->type0); + $type1 = strtolower($message->header->type1); + $name = decodeHeader($message->header->name); + + if ($message->header->entity_id != $ent_id) { + $filename = decodeHeader($message->header->filename); + if (trim($filename) == '') { + if (trim($name) == '') { + if ( trim( $message->header->id ) == '' ) + $display_filename = 'untitled-[' . $message->header->entity_id . ']' ; + else + $display_filename = 'cid: ' . $message->header->id; + // $display_filename = 'untitled-[' . $message->header->entity_id . ']' ; + } else { + $display_filename = $name; + $filename = $name; + } + } else { + $display_filename = $filename; + } - if ($message) { - if (!$message->entities) { - $type0 = strtolower($message->header->type0); - $type1 = strtolower($message->header->type1); - $name = decodeHeader($message->header->name); - - if ($message->header->entity_id != $ent_id) { - $filename = decodeHeader($message->header->filename); - if (trim($filename) == '') { - if (trim($name) == '') { - if ( trim( $message->header->id ) == '' ) - $display_filename = 'untitled-[' . $message->header->entity_id . ']' ; - else - $display_filename = 'cid: ' . $message->header->id; - // $display_filename = 'untitled-[' . $message->header->entity_id . ']' ; - } else { - $display_filename = $name; - $filename = $name; - } - } else { - $display_filename = $filename; - } + $urlMailbox = urlencode($mailbox); + $ent = urlencode($message->header->entity_id); - $urlMailbox = urlencode($mailbox); - $ent = urlencode($message->header->entity_id); - - $DefaultLink = - "../src/download.php?startMessage=$startMessage&passed_id=$id&mailbox=$urlMailbox&passed_ent_id=$ent"; - if ($where && $what) - $DefaultLink .= '&where=' . urlencode($where) . '&what=' . urlencode($what); - $Links['download link']['text'] = _("download"); - $Links['download link']['href'] = - "../src/download.php?absolute_dl=true&passed_id=$id&mailbox=$urlMailbox&passed_ent_id=$ent"; - $ImageURL = ''; - - $HookResults = do_hook("attachment $type0/$type1", $Links, - $startMessage, $id, $urlMailbox, $ent, $DefaultLink, - $display_filename, $where, $what); - - $Links = $HookResults[1]; - $DefaultLink = $HookResults[6]; - - $body .= '  ' . - "$display_filename " . - '' . show_readable_size($message->header->size) . - '  ' . - "[ $type0/$type1 ] " . - ''; - if ($message->header->description) - $body .= '' . htmlspecialchars($message->header->description) . ''; - $body .= ' '; - - - $SkipSpaces = 1; - foreach ($Links as $Val) { - if ($SkipSpaces) { - $SkipSpaces = 0; - } else { - $body .= '  |  '; - } - $body .= '' . $Val['text'] . ''; - } + $DefaultLink = + "../src/download.php?startMessage=$startMessage&passed_id=$id&mailbox=$urlMailbox&passed_ent_id=$ent"; + if ($where && $what) { + $DefaultLink .= '&where=' . urlencode($where) . '&what=' . urlencode($what); + } + $Links['download link']['text'] = _("download"); + $Links['download link']['href'] = + "../src/download.php?absolute_dl=true&passed_id=$id&mailbox=$urlMailbox&passed_ent_id=$ent"; + $ImageURL = ''; + + /* this executes the attachment hook with a specific MIME-type. + * if that doens't have results, it tries if there's a rule + * for a more generic type. */ + $HookResults = do_hook("attachment $type0/$type1", $Links, + $startMessage, $id, $urlMailbox, $ent, $DefaultLink, + $display_filename, $where, $what); + if(count($HookResults[1]) <= 1) { + $HookResults = do_hook("attachment $type0/*", $Links, + $startMessage, $id, $urlMailbox, $ent, $DefaultLink, + $display_filename, $where, $what); + } - unset($Links); + $Links = $HookResults[1]; + $DefaultLink = $HookResults[6]; + + $body .= '  ' . + "$display_filename " . + '' . show_readable_size($message->header->size) . + '  ' . + "[ $type0/$type1 ] " . + ''; + if ($message->header->description) { + $body .= '' . htmlspecialchars(_($message->header->description)) . ''; + } + $body .= ' '; - $body .= "\n"; - } - } else { - for ($i = 0; $i < count($message->entities); $i++) { - $body .= formatAttachments ($message->entities[$i], $ent_id, $mailbox, $id); + + $SkipSpaces = 1; + foreach ($Links as $Val) { + if ($SkipSpaces) { + $SkipSpaces = 0; + } else { + $body .= '  |  '; + } + $body .= '' . $Val['text'] . ''; + } + + unset($Links); + + $body .= "\n"; + } + } else { + for ($i = 0; $i < count($message->entities); $i++) { + $body .= formatAttachments($message->entities[$i], $ent_id, $mailbox, $id); + } } - } - return( $body ); - } + } + return( $body ); } @@ -762,33 +794,40 @@ function decodeBody($body, $encoding) { * RFC1522 (MIME Part Two: Message Header Extensions for Non-ASCII Text). */ function decodeHeader ($string, $utfencode=true) { - if (eregi('=\\?([^?]+)\\?(q|b)\\?([^?]+)\\?=', + +if ( is_array( $string ) ) { + $string = implode("\n", $string ); +} + +if (eregi('=\\?([^?]+)\\?(q|b)\\?([^?]+)\\?=', $string, $res)) { - if (ucfirst($res[2]) == "B") { + if (ucfirst($res[2]) == 'B') { $replace = base64_decode($res[3]); - } else { - $replace = ereg_replace("_", " ", $res[3]); - // Convert lowercase Quoted Printable to uppercase for - // quoted_printable_decode to understand it. - while (ereg("(=(([0-9][abcdef])|([abcdef][0-9])|([abcdef][abcdef])))", $replace, $res)) { - $replace = str_replace($res[1], strtoupper($res[1]), $replace); - } + } else { + $replace = str_replace('_', ' ', $res[3]); + // Convert lowercase Quoted Printable to uppercase for + // quoted_printable_decode to understand it. + while (ereg("(=(([0-9][abcdef])|([abcdef][0-9])|([abcdef][abcdef])))", + $replace, $res)) { + $replace = str_replace($res[1], strtoupper($res[1]), $replace); + } $replace = quoted_printable_decode($replace); - } - /* Only encode into entities by default. Some places + } + /* Only encode into entities by default. Some places don't need the encoding, like the compose form. */ - if ($utfencode){ - $replace = charset_decode ($res[1], $replace); - } + if ($utfencode){ + $replace = charset_decode ($res[1], $replace); + } + + // Remove the name of the character set. + $string = eregi_replace ('=\\?([^?]+)\\?(q|b)\\?([^?]+)\\?=', + $replace, $string); - // Remove the name of the character set. - $string = eregi_replace ('=\\?([^?]+)\\?(q|b)\\?([^?]+)\\?=', - $replace, $string); + // In case there should be more encoding in the string: recurse + $string = decodeHeader($string); +} - // In case there should be more encoding in the string: recurse - return (decodeHeader($string)); - } else - return ($string); +return ($string); } /* @@ -798,7 +837,7 @@ function decodeHeader ($string, $utfencode=true) { */ function encodeHeader ($string) { global $default_charset; - + // Encode only if the string contains 8-bit characters or =? $j = strlen( $string ); $l = strstr($string, '=?'); // Must be encoded ? @@ -826,11 +865,11 @@ function encodeHeader ($string) { $ret .= $string{$i}; } } - + if ( $l ) { $string = "=?$default_charset?Q?$ret?="; } - + return( $string ); } @@ -839,8 +878,11 @@ function encodeHeader ($string) { */ function MagicHTML( $body, $id ) { - global $message, $PHP_SELF, $HTTP_SERVER_VARS; + global $message, $HTTP_SERVER_VARS, + $attachment_common_show_images; + $attachment_common_show_images = + FALSE; // Don't display attached images in HTML mode $j = strlen( $body ); // Legnth of the HTML $ret = ''; // Returned string $bgcolor = '#ffffff'; // Background style color (defaults to white) @@ -854,18 +896,27 @@ function MagicHTML( $body, $id ) { $pos = $i + 1; $tag = ''; while ($body{$pos} == ' ' || $body{$pos} == "\t" || - $body{$pos} == "\n") { + $body{$pos} == "\n" ) { $pos ++; } while (strlen($tag) < 4 && $body{$pos} != ' ' && - $body{$pos} != "\t" && $body{$pos} != "\n") { + $body{$pos} != "\t" && $body{$pos} != "\n" && + $pos < $j ) { $tag .= $body{$pos}; $pos ++; } + /* + A comment in HTML is only three characters and isn't + guaranteed to have a space after it. This fudges so + it will be caught by the switch statement. + */ + if (ereg("!--", $tag)) { + $tag = "!-- "; + } switch( strtoupper( $tag ) ) { // Strips the entire tag and contents case 'APPL': - case 'EMBB': + case 'EMBE': case 'FRAM': case 'SCRI': case 'OBJE': @@ -897,8 +948,8 @@ function MagicHTML( $body, $id ) { case '/HEA': case '!DOC': case 'META': - case 'DIV ': - case '/DIV': + //case 'DIV ': + //case '/DIV': case '!-- ': $i += 4; while ( $body{$i} <> '>' && @@ -980,8 +1031,21 @@ function MagicHTML( $body, $id ) { $ret .= ''; break; case 'BASE': - $i += 5; + $i += 4; $base = ''; + if ( strncasecmp($body{$i}, 'font', 4) ) { + $i += 5; + while ( !isNoSep( $body{$i} ) && $i < $j ) { + $i++; + } + while ( $body{$i} <> '>' && $i < $j ) { + $base .= $body{$i}; + $i++; + } + $ret .= "\n"; + break; + } + $i++; while ( !isNoSep( $body{$i} ) && $i < $j ) { $i++; @@ -1026,9 +1090,12 @@ function MagicHTML( $body, $id ) { return( "\n\n\n" . $ret . + /* Base is illegal within HTML "\n\n\n" ); + */ + "\n\n\n" ); } function isNoSep( $char ) { @@ -1095,7 +1162,7 @@ change on with no (onload -> noload) function stripEvent( &$i, $j, &$body, $id, $base ) { - global $message, $base_uri; + global $message, $base_uri, $has_unsafe_images, $view_unsafe_images; $ret = ''; @@ -1122,22 +1189,27 @@ function stripEvent( &$i, $j, &$body, $id, $base ) { $src .= $body{$k}; $k++; } + $k++; while( !isNoSep( $body{$k} ) && $k < $j ) { $k++; } + $k++; if ( strtolower( substr( $src, 0, 4 ) ) == 'cid:' ) { $src = substr( $src, 4 ); - $src = "../src/download.php?absolute_dl=true&passed_id=$id&mailbox=" . + $src = "../src/download.php?absolute_dl=true&passed_id=$id&mailbox=" . urlencode( $message->header->mailbox ) . - "&passed_ent_id=" . find_ent_id( $src, $message ); - } else if ( strtolower( substr( $src, 0, 4 ) ) <> 'http' || + "&passed_ent_id=" . find_ent_id( $src, $message ); + } else if ( strtolower( substr( $src, 0, 4 ) ) <> 'http' || stristr( $src, $base_uri ) ) { /* Javascript and local urls goes out */ - $src = '../images/' . _("sec_remove_eng.png"); + if (!$view_unsafe_images) { + $src = '../images/' . _("sec_remove_eng.png"); + } + $has_unsafe_images = 1; } $ret .= 'src="' . $src . '" '; - $i = $k-1; + $i = $k - 2; } else { $ret .= 'src'; $i = $i + 3; @@ -1163,9 +1235,9 @@ function stripEvent( &$i, $j, &$body, $id, $base ) { $name .= $body{$i++}; } if ( $name <> '' ) { - $ret .= "../src/download.php?absolute_dl=true&passed_id=$id&mailbox=" . + $ret .= "../src/download.php?absolute_dl=true&passed_id=$id&mailbox=" . urlencode( $message->header->mailbox ) . - "&passed_ent_id=" . find_ent_id( $name, $message ); + "&passed_ent_id=" . find_ent_id( $name, $message ); if ( $body{$k} == '"' ) $ret .= '" '; else @@ -1218,4 +1290,4 @@ function find_ent_id( $id, $message ) { return( $ret ); } -?> \ No newline at end of file +?>