X-Git-Url: https://vcs.fsf.org/?p=squirrelmail.git;a=blobdiff_plain;f=functions%2Fmime.php;h=d19d6e0dcf0344ab13a8880d0552f2ab8787ad7d;hp=5ce51925c6ed94b8b24967ddf059ebbcc956057d;hb=34c905749d736b54b8786cca0f5501e5cf87fea3;hpb=89863d1d001dc91764e61c4970909f598a1744c6 diff --git a/functions/mime.php b/functions/mime.php index 5ce51925..d19d6e0d 100644 --- a/functions/mime.php +++ b/functions/mime.php @@ -33,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; } @@ -51,7 +50,6 @@ class message { */ function mime_structure ($imap_stream, $header) { - sqimap_messages_flag ($imap_stream, $header->id, $header->id, 'Seen'); $ssid = sqimap_session_id(); $lsid = strlen( $ssid ); $id = $header->id; @@ -59,15 +57,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)); @@ -77,10 +75,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 ); } @@ -120,15 +118,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; } @@ -142,13 +140,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) { @@ -253,11 +251,11 @@ function mime_get_element (&$structure, $msg, $ent_id) { $text = ""; } // loop through the additional properties and put those in the various headers - if ($msg->header->type0 != 'message') { +// if ($msg->header->type0 != 'message') { for ($i=0; $i < count($properties); $i++) { $msg->header->{$properties[$i]['name']} = $properties[$i]['value']; } - } +// } return $msg; } @@ -370,17 +368,25 @@ 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; - $data = sqimap_run_command ($imap_stream, "FETCH $id BODY[$ent_id]", 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 = trim(array_shift( $data )); + } while( $topline && $topline[0] == '*' && !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 @@ -388,57 +394,65 @@ function mime_fetch_body ($imap_stream, $id, $ent_id ) { */ if ( $ret{0} == '<' ) { $data = sqimap_run_command ($imap_stream, "FETCH $id BODY[$ent_id.MIME]", 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; + /* 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
"; + "
" . + _("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 ); } @@ -457,7 +471,7 @@ function mime_print_body_lines ($imap_stream, $id, $ent_id, $encoding) { if (!ini_get("safe_mode")) { set_time_limit(0); } - + fputs ($imap_stream, "$sid FETCH $id BODY[$ent_id]\r\n"); $cnt = 0; $continue = true; @@ -496,7 +510,7 @@ function decodeMime ($imap_stream, &$header) { // This is here for debugging purposese. It will print out a list // of all the entity IDs that are in the $message object. -/* + function listEntities ($message) { if ($message) { if ($message->header->entity_id) @@ -508,7 +522,7 @@ if ($message) { } } } -*/ + /* returns a $message object for a particular entity id */ function getEntity ($message, $ent_id) { @@ -538,11 +552,12 @@ 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); } - + // Show text/plain or text/html -- the first one we find. if ( $entity == 0 && $message->header->type0 == 'text' && @@ -571,6 +586,11 @@ function findDisplayEntityHTML ($message) { return $message->header->entity_id; } for ($i = 0; isset($message->entities[$i]); $i ++) { + if ( $message->header->type0 == 'message' && + $message->header->type1 == 'rfc822' && + isset($message->header->entity_id)) { + return 0; + } $entity = findDisplayEntityHTML($message->entities[$i]); if ($entity != 0) { return $entity; @@ -589,24 +609,27 @@ 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 +642,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,108 +666,182 @@ 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 ); - } - - 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 ) == '' ) + "\n" . + _("Attachments") . ':' . + "\n" . + "\n" . + formatAttachments($message, $ent_id, $mailbox, $id) . + "
"; + + } else if ($message) { + $header = $message->header; + $type0 = strtolower($header->type0); + $type1 = strtolower($header->type1); + $name = decodeHeader($header->name); + + if ($type0 =='message' && $type1 = 'rfc822') { + + $filename = decodeHeader($message->header->filename); + if (trim($filename) == '') { + if (trim($name) == '') { $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; - } + } else { + $display_filename = $name; + $filename = $name; + } + } else { + $display_filename = $filename; + } - $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 = ''; - - /* 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); - } + $urlMailbox = urlencode($mailbox); + $ent = urlencode($message->header->entity_id); - $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"; + + return( $body ); + + } elseif (!$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); + + $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); + } + + $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'] . ''; + } + + 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 ); } @@ -813,7 +915,7 @@ return ($string); */ 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 ? @@ -841,11 +943,11 @@ function encodeHeader ($string) { $ret .= $string{$i}; } } - + if ( $l ) { $string = "=?$default_charset?Q?$ret?="; } - + return( $string ); } @@ -854,7 +956,7 @@ function encodeHeader ($string) { */ function MagicHTML( $body, $id ) { - global $message, $HTTP_SERVER_VARS, + global $message, $HTTP_SERVER_VARS, $attachment_common_show_images; $attachment_common_show_images = @@ -872,18 +974,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': @@ -998,8 +1109,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++; @@ -1044,9 +1168,12 @@ function MagicHTML( $body, $id ) { return( "\n\n\n" . $ret . + /* Base is illegal within HTML "\n\n\n" ); + */ + "\n\n\n" ); } function isNoSep( $char ) { @@ -1113,7 +1240,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 = ''; @@ -1140,19 +1267,24 @@ 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 - 2; @@ -1181,9 +1313,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