* This contains the functions necessary to detect and decode MIME
* messages.
*
- * @copyright © 1999-2007 The SquirrelMail Project Team
+ * @copyright © 1999-2009 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id$
* @package squirrelmail
if (strtolower($flag) == '\\flagged') {
$msg->is_flagged = true;
}
+ else if (strtolower($flag) == '$forwarded') {
+ $msg->is_forwarded = true;
+ }
break;
case 'M':
if (strtolower($flag) == '$mdnsent') {
return $ret;
}
-function mime_print_body_lines ($imap_stream, $id, $ent_id=1, $encoding, $rStream='php://stdout') {
+function mime_print_body_lines ($imap_stream, $id, $ent_id=1, $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.
} else {
$body = mime_fetch_body ($imap_stream, $id, $ent_id);
if (is_resource($rStream)) {
- fputs($rStream,decodeBody($body,$encoding));
+ fputs($rStream,decodeBody($body, $encoding, $force_crlf));
} else {
- echo decodeBody($body, $encoding);
+ echo decodeBody($body, $encoding, $force_crlf);
}
}
$body_ary = explode("\n", $body);
for ($i=0; $i < count($body_ary); $i++) {
- $line = $body_ary[$i];
+ $line = rtrim($body_ary[$i],"\r");
+
if (strlen($line) - 2 >= $wrap_at) {
sqWordWrap($line, $wrap_at, $charset);
}
* @param string $ent_num (since 1.3.0) message part id
* @param integer $id (since 1.3.0) message id
* @param string $mailbox (since 1.3.0) imap folder name
- * @param boolean $clean (since 1.5.1) Do not output stuff that's irrelevant for the printable version.
* @return string html formated message text
*/
-function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $mailbox='INBOX', $clean=FALSE) {
+function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $mailbox='INBOX') {
/* 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.
$body = trim($body);
translateText($body, $wrap_at,
$body_message->header->getParameter('charset'));
- } elseif ($use_iframe && ! $clean) {
- // $clean is used to remove iframe in printable view.
-
+ } elseif ($use_iframe) {
/**
* If we don't add html message between iframe tags,
* we must detect unsafe images and modify $has_unsafe_images.
$body_message->header->getParameter('charset'));
}
- // if this is the clean display (i.e. printer friendly), stop here.
- if ( $clean ) {
- return $body;
- }
-
/*
* Previously the links for downloading and unsafe images were printed
* under the mail. By putting the links in a global variable we can
}
/**
- * Generate attachments array for passing to templates. Separated from
- * formatAttachments() below so that the same array can be given to the
- * print-friendly version.
+ * Generate attachments array for passing to templates.
*
* @since 1.5.2
* @param object $message SquirrelMail message object
}
/**
- * Decodes encoded message body
+ * Decodes encoded string (usually message body)
+ *
+ * This function decodes a string (usually the message body)
+ * depending on the encoding type. Currently quoted-printable
+ * and base64 encodings are supported.
+ *
+ * The decode_body hook was added to this function in 1.4.2/1.5.0.
+ * The $force_crlf parameter was added in 1.5.2.
+ *
+ * @param string $string The encoded string
+ * @param string $encoding used encoding
+ * @param string $force_crlf Whether or not to force CRLF or LF
+ * line endings (or to leave as is).
+ * If given as "LF", line endings will
+ * all be converted to LF; if "CRLF",
+ * line endings will all be converted
+ * to CRLF. If given as an empty value,
+ * the global $force_crlf_default will
+ * be consulted (it can be specified in
+ * config/config_local.php). Otherwise,
+ * any other value will cause the string
+ * to be left alone. Note that this will
+ * be overridden to "LF" if not using at
+ * least PHP version 4.3.0. (OPTIONAL;
+ * default is empty - consult global
+ * default value)
+ *
+ * @return string The decoded string
*
- * This function decodes the body depending on the encoding type.
- * Currently quoted-printable and base64 encodings are supported.
- * decode_body hook was added to this function in 1.4.2/1.5.0
- * @param string $body encoded message body
- * @param string $encoding used encoding
- * @return string decoded string
* @since 1.0
+ *
*/
-function decodeBody($body, $encoding) {
+function decodeBody($string, $encoding, $force_crlf='') {
+
+ global $force_crlf_default;
+ if (empty($force_crlf)) $force_crlf = $force_crlf_default;
+ $force_crlf = strtoupper($force_crlf);
+
+ // must force line endings to LF due to broken
+ // quoted_printable_decode() in PHP versions
+ // before 4.3.0 (see below)
+ //
+ if (!check_php_version(4, 3, 0) || $force_crlf == 'LF')
+ $string = str_replace("\r\n", "\n", $string);
+ else if ($force_crlf == 'CRLF')
+ $string = str_replace("\n", "\r\n", $string);
- $body = str_replace("\r\n", "\n", $body);
$encoding = strtolower($encoding);
$encoding_handler = do_hook('decode_body', $encoding);
- // plugins get first shot at decoding the body
+ // plugins get first shot at decoding the string
//
if (!empty($encoding_handler) && function_exists($encoding_handler)) {
- $body = $encoding_handler('decode', $body);
+ $string = $encoding_handler('decode', $string);
} elseif ($encoding == 'quoted-printable' ||
$encoding == 'quoted_printable') {
- /**
- * quoted_printable_decode() function is broken in older
- * php versions. Text with \r\n decoding was fixed only
- * in php 4.3.0. Minimal code requirement 4.0.4 +
- * str_replace("\r\n", "\n", $body); call.
- */
- $body = quoted_printable_decode($body);
+
+ // quoted_printable_decode() function is broken in older
+ // php versions. Text with \r\n decoding was fixed only
+ // in php 4.3.0. Minimal code requirement is PHP 4.0.4+
+ // and the above call to: str_replace("\r\n", "\n", $string);
+ //
+ $string = quoted_printable_decode($string);
+
} elseif ($encoding == 'base64') {
- $body = base64_decode($body);
+ $string = base64_decode($string);
}
// All other encodings are returned raw.
- return $body;
+ return $string;
}
/**
$attvalue = $sQuote . $secremoveimg . $sQuote;
} else {
if (isset($aUrl['path'])) {
+
+ // No one has been able to show that image URIs
+ // can be exploited, so for now, no restrictions
+ // are made at all. If this proves to be a problem,
+ // the commented-out code below can be of help.
+ // (One consideration is that I see nothing in this
+ // function that specifically says that we will
+ // only ever arrive here when inspecting an image
+ // tag, although that does seem to be the end
+ // result - e.g., <script src="..."> where malicious
+ // image URIs are in fact a problem are already
+ // filtered out elsewhere.
+ /* ---------------------------------
// validate image extension.
$ext = strtolower(substr($aUrl['path'],strrpos($aUrl['path'],'.')));
if (!in_array($ext,array('.jpeg','.jpg','xjpeg','.gif','.bmp','.jpe','.png','.xbm'))) {
- $attvalue = $sQuote . SM_PATH . 'images/blank.png'. $sQuote;
+ // If URI is to something other than
+ // a regular image file, get the contents
+ // and try to see if it is an image.
+ // Don't use Fileinfo (finfo_file()) because
+ // we'd need to make the admin configure the
+ // location of the magic.mime file (FIXME: add finfo_file() support later?)
+ //
+ $mime_type = '';
+ if (function_exists('mime_content_type')
+ && ($FILE = @fopen($attvalue, 'rb', FALSE))) {
+
+ // fetch file
+ //
+ $file_contents = '';
+ while (!feof($FILE)) {
+ $file_contents .= fread($FILE, 8192);
+ }
+ fclose($FILE);
+
+ // store file locally
+ //
+ global $attachment_dir, $username;
+ $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
+ $localfilename = GenerateRandomString(32, '', 7);
+ $full_localfilename = "$hashed_attachment_dir/$localfilename";
+ while (file_exists($full_localfilename)) {
+ $localfilename = GenerateRandomString(32, '', 7);
+ $full_localfilename = "$hashed_attachment_dir/$localfilename";
+ }
+ $FILE = fopen("$hashed_attachment_dir/$localfilename", 'wb');
+ fwrite($FILE, $file_contents);
+ fclose($FILE);
+
+ // get mime type and remove file
+ //
+ $mime_type = mime_content_type("$hashed_attachment_dir/$localfilename");
+ unlink("$hashed_attachment_dir/$localfilename");
+ }
+ // debug: echo "$attvalue FILE TYPE IS $mime_type<HR>";
+ if (substr(strtolower($mime_type), 0, 5) != 'image') {
+ $attvalue = $sQuote . SM_PATH . 'images/blank.png'. $sQuote;
+ }
}
+ --------------------------------- */
} else {
$attvalue = $sQuote . SM_PATH . 'images/blank.png'. $sQuote;
}
}
+ } else {
+ $attvalue = $sQuote . $attvalue . $sQuote;
}
break;
case 'outbind':
* One day MS might actually make it match something useful, for now, falling
* back to using cid2http, so we can grab the blank.png.
*/
- $attvalue = sq_cid2http($message, $id, $attvalue, $mailbox);
+ $attvalue = $sQuote . sq_cid2http($message, $id, $attvalue, $mailbox) . $sQuote;
break;
case 'cid':
/**
* Turn cid: urls into http-friendly ones.
*/
- $attvalue = sq_cid2http($message, $id, $attvalue, $mailbox);
+ $attvalue = $sQuote . sq_cid2http($message, $id, $attvalue, $mailbox) . $sQuote;
break;
default:
$attvalue = $sQuote . SM_PATH . 'images/blank.png' . $sQuote;
}
if (!empty($linkurl)) {
- $httpurl = $quotchar . SM_PATH . 'src/download.php?absolute_dl=true&' .
+ $httpurl = $quotchar . sqm_baseuri() . 'src/download.php?absolute_dl=true&' .
"passed_id=$id&mailbox=" . urlencode($mailbox) .
'&ent_id=' . $linkurl . $quotchar;
} else {