+ while (ereg("=\n", $body))
+ $body = ereg_replace ("=\n", "", $body);
+
+ } else if ($encoding == 'base64') {
+ $body = base64_decode($body);
+ }
+
+ // All other encodings are returned raw.
+ return $body;
+}
+
+/*
+ * This functions decode strings that is encoded according to
+ * RFC1522 (MIME Part Two: Message Header Extensions for Non-ASCII Text).
+ */
+function decodeHeader ($string, $utfencode=true) {
+
+if ( is_array( $string ) ) {
+ $string = implode("\n", $string );
+}
+
+if (eregi('=\\?([^?]+)\\?(q|b)\\?([^?]+)\\?=',
+ $string, $res)) {
+ if (ucfirst($res[2]) == 'B') {
+ $replace = base64_decode($res[3]);
+ } 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
+ don't need the encoding, like the compose form. */
+ if ($utfencode){
+ $replace = charset_decode ($res[1], $replace);
+ }
+
+ // 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);
+}
+
+return ($string);
+}
+
+/*
+ * 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 encodeHeader ($string) {
+ global $default_charset;
+
+ // Encode only if the string contains 8-bit characters or =?
+ $j = strlen( $string );
+ $l = strstr($string, '=?'); // Must be encoded ?
+ $ret = '';
+ 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;
+ } else
+ $ret .= $string{$i};
+ }
+ }
+
+ if ( $l ) {
+ $string = "=?$default_charset?Q?$ret?=";
+ }
+
+ return( $string );
+}
+
+/*
+ Strips dangerous tags from html messages.
+*/
+function MagicHTML( $body, $id ) {
+
+ 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)
+ $textcolor = '#000000'; // Foreground style color (defaults to black)
+ $leftmargin = ''; // Left margin style
+ $title = ''; // HTML title if any
+
+ $i = 0;
+ while ( $i < $j ) {
+ if ( $body{$i} == '<' ) {
+ $pos = $i + 1;
+ $tag = '';
+ while ($body{$pos} == ' ' || $body{$pos} == "\t" ||
+ $body{$pos} == "\n" ) {
+ $pos ++;
+ }
+ while (strlen($tag) < 4 && $body{$pos} != ' ' &&
+ $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 'EMBE':
+ case 'FRAM':
+ case 'SCRI':
+ case 'OBJE':
+ $etg = '/' . $tag;
+ while ( $body{$i+1}.$body{$i+2}.$body{$i+3}.$body{$i+4}.$body{$i+5} <> $etg &&
+ $i < $j ) $i++;
+ while ( $i < $j && $body{++$i} <> '>' );
+ // $ret .= "<!-- $tag removed -->";
+ break;
+ // Substitute Title
+ case 'TITL':
+ $i += 5;
+ while ( $body{$i} <> '>' && // </title>
+ $i < $j )
+ $i++;
+ $i++;
+ $title = '';
+ while ( $body{$i} <> '<' && // </title>
+ $i < $j ) {
+ $title .= $body{$i};
+ $i++;
+ }
+ $i += 7;
+ break;
+ // Destroy these tags
+ case 'HTML':
+ case 'HEAD':
+ case '/HTM':
+ case '/HEA':
+ case '!DOC':
+ case 'META':
+ //case 'DIV ':
+ //case '/DIV':
+ case '!-- ':
+ $i += 4;
+ while ( $body{$i} <> '>' &&
+ $i < $j )
+ $i++;
+ // $i++;
+ break;
+ case 'STYL':
+ $i += 5;
+ while ( $body{$i} <> '>' && // </title>
+ $i < $j )
+ $i++;
+ $i++;
+ // We parse the style to look for interesting stuff
+ $styleblk = '';
+ while ( $body{$i} <> '>' &&
+ $i < $j ) {
+ // First we get the name of the style
+ $style = '';
+ while ( $body{$i} <> '>' &&
+ $body{$i} <> '<' &&
+ $body{$i} <> '{' &&
+ $i < $j ) {
+ if ( isnoSep( $body{$i} ) )
+ $style .= $body{$i};
+ $i++;
+ }
+ stripComments( $i, $j, $body );
+ $style = strtoupper( trim( $style ) );
+ if ( $style == 'BODY' ) {
+ // Next we look into the definitions of the body style
+ while ( $body{$i} <> '>' &&
+ $body{$i} <> '}' &&
+ $i < $j ) {
+ // We look for the background color if any.
+ if ( substr( $body, $i, 17 ) == 'BACKGROUND-COLOR:' ) {
+ $i += 17;
+ $bgcolor = getStyleData( $i, $j, $body );
+ } elseif ( substr( $body, $i, 12 ) == 'MARGIN-LEFT:' ) {
+ $i += 12;
+ $leftmargin = getStyleData( $i, $j, $body );
+ }
+ $i++;
+ }
+ } else {
+ // Other style are mantained
+ $styleblk .= "$style ";
+ while ( $body{$i} <> '>' &&
+ $body{$i} <> '<' &&
+ $body{$i} <> '}' &&
+ $i < $j ) {
+ $styleblk .= $body{$i};
+ $i++;
+ }
+ $styleblk .= $body{$i};
+ }
+ stripComments( $i, $j, $body );
+ if ( $body{$i} <> '>' )
+ $i++;
+ }
+ if ( $styleblk <> '' )
+ $ret .= "<style>$styleblk";
+ break;
+ case 'BODY':
+ if ( $title <> '' )
+ $ret .= '<b>' . _("Title:") . " </b>$title<br>\n";
+ $ret .= "<TABLE";
+ $i += 5;
+ if (! isset($base)) {
+ $base = '';
+ }
+ $ret .= stripEvent( $i, $j, $body, $id, $base );
+ $ret .= " bgcolor=$bgcolor width=\"100%\"><tr>";
+ if ( $leftmargin <> '' )
+ $ret .= "<td width=$leftmargin> </td>";
+ $ret .= '<td>';
+ if (strtolower($bgcolor) == 'ffffff' ||
+ strtolower($bgcolor) == '#ffffff')
+ $ret .= '<font color=#000000>';
+ break;
+ case 'BASE':
+ $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 .= "<BASEFONT $base>\n";
+ break;
+ }
+ $i++;
+ while ( !isNoSep( $body{$i} ) &&
+ $i < $j ) {
+ $i++;
+ }
+ if ( strcasecmp( substr( $base, 0, 4 ), 'href' ) ) {
+ $i += 5;
+ while ( !isNoSep( $body{$i} ) &&
+ $i < $j ) {
+ $i++;
+ }
+ while ( $body{$i} <> '>' &&
+ $i < $j ) {
+ if ( $body{$i} <> '"' ) {
+ $base .= $body{$i};
+ }
+ $i++;
+ }
+ // Debuging $ret .= "<!-- base == $base -->";
+ if ( strcasecmp( substr( $base, 0, 4 ), 'file' ) <> 0 ) {
+ $ret .= "\n<BASE HREF=\"$base\">\n";
+ }
+ }
+ break;
+ case '/BOD':
+ $ret .= '</font></td></tr></TABLE>';
+ $i += 6;
+ break;
+ default:
+ // Following tags can contain some event handler, lets search it
+ stripComments( $i, $j, $body );
+ if (! isset($base)) {
+ $base = '';
+ }
+ $ret .= stripEvent( $i, $j, $body, $id, $base ) . '>';
+ // $ret .= "<!-- $tag detected -->";
+ }
+ } else {
+ $ret .= $body{$i};
+ }
+ $i++;
+ }
+
+return( "\n\n<!-- HTML Output ahead -->\n" .
+ $ret .
+ /* Base is illegal within HTML
+ "\n<!-- END of HTML Output --><base href=\"".
+ get_location() . '/'.
+ "\">\n\n" );
+ */
+ "\n<!-- END of HTML Output -->\n\n" );
+}
+
+function isNoSep( $char ) {
+
+ switch( $char ) {
+ case ' ':
+ case "\n":
+ case "\t":
+ case "\r":
+ case '>':
+ case '"':
+ return( FALSE );
+ break;
+ default:
+ return( TRUE );
+ }
+
+}
+
+/*
+ The following function is usefull to remove extra data that can cause
+ html not to display properly. Especialy with MS stuff.
+*/
+
+function stripComments( &$i, $j, &$body ) {
+
+ while ( $body{$i}.$body{$i+1}.$body{$i+2}.$body{$i+3} == '<!--' &&
+ $i < $j ) {
+ $i += 5;
+ while ( $body{$i-2}.$body{$i-1}.$body{$i} <> '-->' &&
+ $i < $j )
+ $i++;
+ $i++;
+ }
+
+ return;
+
+}
+
+/* Gets the style data of a specific style */
+
+function getStyleData( &$i, $j, &$body ) {
+
+ // We skip spaces
+ while ( $body{$i} <> '>' && !isNoSep( $body{$i} ) &&
+ $i < $j ) {
+ $i++;
+ }
+ // And get the color
+ $ret = '';
+ while ( isNoSep( $body{$i} ) &&
+ $i < $j ) {
+ $ret .= $body{$i};
+ $i++;
+ }
+
+ return( $ret );
+}
+
+/*
+Private function for strip_dangerous_tag. Look for event based coded and "remove" it
+change on with no (onload -> noload)
+*/
+
+function stripEvent( &$i, $j, &$body, $id, $base ) {
+
+ global $message, $base_uri, $has_unsafe_images, $view_unsafe_images;
+
+ $ret = '';
+
+ while ( $body{$i} <> '>' &&
+ $i < $j ) {
+ $etg = strtolower($body{$i}.$body{$i+1}.$body{$i+2});
+ switch( $etg ) {
+ case 'src':
+ // This is probably a src specification
+ $k = $i + 3;
+ while( !isNoSep( $body{$k} )) {
+ $k++;
+ }
+ if ( $body{$k} == '=' ) {
+ /* It is indeed */
+ $k++;
+ while( !isNoSep( $body{$k} ) &&
+ $k < $j ) {
+ $k++;
+ }
+ $src = '';
+ while ( $body{$k} <> '>' && isNoSep( $body{$k} ) &&
+ $k < $j ) {
+ $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=" .
+ urlencode( $message->header->mailbox ) .
+ "&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 */
+ if (!$view_unsafe_images) {
+ $src = '../images/' . _("sec_remove_eng.png");
+ }
+ $has_unsafe_images = 1;
+ }
+ $ret .= 'src="' . $src . '" ';
+ $i = $k - 2;
+ } else {
+ $ret .= 'src';
+ $i = $i + 3;
+ }
+
+ break;
+ case '../':
+ // Retrolinks are not allowed without a base because they mess with SM security
+ if ( $base == '' ) {
+ $i += 2;
+ } else {
+ $ret .= '.';
+ }
+ break;
+ case 'cid':
+ // Internal link
+ $k = $i-1;
+ if ( $body{$i+3} == ':') {
+ $i +=4;
+ $name = '';
+ while ( isNoSep( $body{$i} ) &&
+ $i < $j ) {
+ $name .= $body{$i++};
+ }
+ if ( $name <> '' ) {
+ $ret .= "../src/download.php?absolute_dl=true&passed_id=$id&mailbox=" .
+ urlencode( $message->header->mailbox ) .
+ "&passed_ent_id=" . find_ent_id( $name, $message );
+ if ( $body{$k} == '"' )
+ $ret .= '" ';
+ else
+ $ret .= ' ';
+ }
+ if ( $body{$i} == '>' )
+ $i -= 1;
+ }
+ break;
+ case ' on':
+ case "\non":
+ case "\ron":
+ case "\ton":
+ $ret .= ' no';
+ $i += 2;
+ break;
+ case 'pt:':
+ if ( strcasecmp( $body{$i-4}.$body{$i-3}.$body{$i-2}.$body{$i-1}.$body{$i}.$body{$i+1}.$body{$i+2}, 'script:') == 0 ) {
+ $ret .= '_no/';
+ } else {
+ $ret .= $etg;
+ }
+ $i += 2;
+ break;
+ default:
+ $ret .= $body{$i};
+ }
+ $i++;
+ }
+ return( $ret );
+}
+
+
+/* This function trys to locate the entity_id of a specific mime element */
+
+function find_ent_id( $id, $message ) {
+
+ $ret = '';
+ for ($i=0; $ret == '' && $i < count($message->entities); $i++) {
+
+ if ( $message->entities[$i]->header->entity_id == '' ) {
+ $ret = find_ent_id( $id, $message->entities[$i] );
+ } else {
+ if ( strcasecmp( $message->entities[$i]->header->id, $id ) == 0 )
+ $ret = $message->entities[$i]->header->entity_id;
+ }
+
+ }
+
+ return( $ret );