diff --git a/include/class.mailparse.php b/include/class.mailparse.php index 5b1a0271037fe473f760db7535e9c2f2277220de..dad841ffb1a5067c5e37ef4a42df5ff622ab0fc1 100644 --- a/include/class.mailparse.php +++ b/include/class.mailparse.php @@ -32,9 +32,9 @@ class Mail_Parse { var $tnef = false; // TNEF encoded mail - function Mail_parse($mimeMessage, $charset=null){ + function Mail_parse(&$mimeMessage, $charset=null){ - $this->mime_message = $mimeMessage; + $this->mime_message = &$mimeMessage; if($charset) $this->charset = $charset; @@ -54,18 +54,18 @@ class Mail_Parse { $params = array('crlf' => "\r\n", 'charset' => $this->charset, - 'input' => $this->mime_message, 'include_bodies'=> $this->include_bodies, 'decode_headers'=> $this->decode_headers, 'decode_bodies' => $this->decode_bodies); - $this->struct=Mail_mimeDecode::decode($params); + $this->splitBodyHeader(); + + $decoder = new Mail_mimeDecode($this->mime_message); + $this->struct = $decoder->decode($params); if (PEAR::isError($this->struct)) return false; - $this->splitBodyHeader(); - // Handle wrapped emails when forwarded if ($this->struct && $this->struct->parts) { $outer = $this->struct; @@ -119,7 +119,7 @@ class Mail_Parse { function splitBodyHeader() { $match = array(); - if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", + if (preg_match("/^(.*?)\r?\n\r?\n./s", $this->mime_message, $match)) { $this->header=$match[1]; diff --git a/include/pear/Mail/mimeDecode.php b/include/pear/Mail/mimeDecode.php index b300195824c30528f7ff44987679fd11875889e3..bc524f0cc2cbc8abd75d4c26dcb06201cbd1b98e 100644 --- a/include/pear/Mail/mimeDecode.php +++ b/include/pear/Mail/mimeDecode.php @@ -91,14 +91,6 @@ require_once 'PEAR.php'; */ class Mail_mimeDecode extends PEAR { - /** - * The raw email to decode - * - * @var string - * @access private - */ - var $_input; - /** * The header part of the input * @@ -157,13 +149,13 @@ class Mail_mimeDecode extends PEAR * @param string The input to decode * @access public */ - function Mail_mimeDecode($input) + function Mail_mimeDecode(&$input) { list($header, $body) = $this->_splitBodyHeader($input); - $this->_input = $input; - $this->_header = $header; - $this->_body = $body; + $this->_input = &$input; + $this->_header = &$header; + $this->_body = &$body; $this->_decode_bodies = false; $this->_include_bodies = true; } @@ -241,7 +233,7 @@ class Mail_mimeDecode extends PEAR * @return object Results of decoding process * @access private */ - function _decode($headers, $body, $default_ctype = 'text/plain') + function _decode(&$headers, &$body, $default_ctype = 'text/plain') { $return = new stdClass; $return->headers = array(); @@ -324,8 +316,9 @@ class Mail_mimeDecode extends PEAR $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain'; $parts = $this->_boundarySplit($body, $content_type['other']['boundary']); - for ($i = 0; $i < count($parts); $i++) { - list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]); + while (count($parts)) { + $part = array_shift($parts); + list($part_header, $part_body) = $this->_splitBodyHeader($part); $part = $this->_decode($part_header, $part_body, $default_ctype); if($part === false) $part = $this->raiseError($this->_error); @@ -409,10 +402,18 @@ class Mail_mimeDecode extends PEAR * @return array Contains header and body section * @access private */ - function _splitBodyHeader($input) + function _splitBodyHeader(&$input) { - if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) { - return array($match[1], $match[2]); + if ($input instanceof StringView) + $check = $input->substr(0, 64<<10); + else + $check = &$input; + if (preg_match("/^.*?(\r?\n\r?\n)(.)/s", $check, $match, PREG_OFFSET_CAPTURE)) { + $headers = ($input instanceof StringView) + ? (string) $input->substr(0, $match[1][1]) : substr($input, 0, $match[1][1]); + $body = ($input instanceof StringView) + ? $input->substr($match[2][1]) : new StringView($input, $match[2][1]); + return array($headers, $body); } $this->_error = 'Could not split header and body'; return false; @@ -524,6 +525,12 @@ class Mail_mimeDecode extends PEAR $boundary = $bs_possible; } + if ($input instanceof StringView) { + $parts = $input->split('--' . $boundary); + array_shift($parts); + return $parts; + } + $tmp = explode('--' . $boundary, $input); for ($i = 1; $i < count($tmp) - 1; $i++) { @@ -871,3 +878,51 @@ class Mail_mimeDecode extends PEAR } } // End of class + +class StringView { + var $string; + var $start; + var $end; + + function __construct(&$string, $start=0, $end=false) { + $this->string = &$string; + $this->start = $start; + $this->end = $end; + } + + function __toString() { + return $this->end + ? substr($this->string, $this->start, $this->end - $this->start) + : substr($this->string, $this->start); + } + + function substr($start, $end=false) { + return new StringView($this->string, $this->start + $start, + $end ? min($this->start + $end, $this->end ?: PHP_INT_MAX) : $this->end); + } + + function split($token) { + $ltoken = strlen($token); + $windows = array(); + $offset = $this->start; + for ($i = 0;; $i++) { + $windows[$i] = array('start' => $offset); + $offset = strpos($this->string, $token, $offset); + if (!$offset || ($this->end && $offset >= $this->end)) + break; + + // Enforce local window + $windows[$i]['stop'] = min($this->end ?: $offset, $offset); + $offset += $ltoken; + if ($this->end && $offset > $this->end) + break; + } + + $parts = array(); + foreach ($windows as $w) { + $parts[] = new static($this->string, $w['start'], @$w['stop'] ?: false); + } + return $parts; + + } +}