Skip to content

Commit

Permalink
Updated mimeDecode pear package to version 337165
Browse files Browse the repository at this point in the history
  • Loading branch information
SL-Gundam committed Sep 4, 2016
1 parent 2384b19 commit bc3474d
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 61 deletions.
197 changes: 136 additions & 61 deletions core_pear/Mail/mimeDecode.php
Expand Up @@ -52,7 +52,7 @@
* @author Sean Coates <sean@php.net>
* @copyright 2003-2006 PEAR <pear-group@php.net>
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @version CVS: $Id: mimeDecode.php 305875 2010-12-01 07:17:10Z alan_k $
* @version CVS: $Id: mimeDecode.php 337165 2015-07-15 09:42:08Z alan_k $
* @link http://pear.php.net/package/Mail_mime
*/

Expand Down Expand Up @@ -141,11 +141,12 @@ class Mail_mimeDecode extends PEAR

/**
* Flag to determine whether to decode headers
*
* @var boolean
* (set to UTF8 to iconv convert headers)
* @var mixed
* @access private
*/
var $_decode_headers;


/**
* Flag to determine whether to include attached messages
Expand All @@ -165,7 +166,7 @@ class Mail_mimeDecode extends PEAR
* @param string The input to decode
* @access public
*/
function Mail_mimeDecode($input)
function __construct($input)
{
list($header, $body) = $this->_splitBodyHeader($input);

Expand All @@ -176,6 +177,12 @@ function Mail_mimeDecode($input)
$this->_include_bodies = true;
$this->_rfc822_bodies = false;
}
// BC
function Mail_mimeDecode($input)
{
$this->__construct($input);
}


/**
* Begins the decoding process. If called statically
Expand All @@ -188,7 +195,9 @@ function Mail_mimeDecode($input)
* object.
* decode_bodies - Whether to decode the bodies
* of the parts. (Transfer encoding)
* decode_headers - Whether to decode headers
* decode_headers - Whether to decode headers,
* - use "UTF8//IGNORE" to convert charset.
*
* input - If called statically, this will be treated
* as the input
* @return object Decoded results
Expand Down Expand Up @@ -220,13 +229,17 @@ function decode($params = null)
$params['decode_headers'] : false;
$this->_rfc822_bodies = isset($params['rfc_822bodies']) ?
$params['rfc_822bodies'] : false;


if (is_string($this->_decode_headers) && !function_exists('iconv')) {
PEAR::raiseError('header decode conversion requested, however iconv is missing');
}

$structure = $this->_decode($this->_header, $this->_body);
if ($structure === false) {
$structure = $this->raiseError($this->_error);
}
}

return $structure;
}

Expand All @@ -247,7 +260,7 @@ function _decode($headers, $body, $default_ctype = 'text/plain')
$headers = $this->_parseHeaders($headers);

foreach ($headers as $value) {
$value['value'] = $this->_decode_headers ? $this->_decodeHeader($value['value']) : $value['value'];
$value['value'] = $this->_decodeHeader($value['value']);
if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) {
$return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]);
$return->headers[strtolower($value['name'])][] = $value['value'];
Expand Down Expand Up @@ -307,6 +320,14 @@ function _decode($headers, $body, $default_ctype = 'text/plain')
$encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null;
break;

case 'multipart/signed': // PGP
$parts = $this->_boundarySplit($body, $content_type['other']['boundary'], true);
$return->parts['msg_body'] = $parts[0];
list($part_header, $part_body) = $this->_splitBodyHeader($parts[1]);
$return->parts['sig_hdr'] = $part_header;
$return->parts['sig_body'] = $part_body;
break;

case 'multipart/parallel':
case 'multipart/appledouble': // Appledouble mail
Expand All @@ -315,6 +336,7 @@ function _decode($headers, $body, $default_ctype = 'text/plain')
case 'multipart/digest':
case 'multipart/alternative':
case 'multipart/related':
case 'multipart/relative': //#20431 - android
case 'multipart/mixed':
case 'application/vnd.wap.multipart.related':
if(!isset($content_type['other']['boundary'])){
Expand All @@ -335,6 +357,7 @@ function _decode($headers, $body, $default_ctype = 'text/plain')
break;

case 'message/rfc822':
case 'message/delivery-status': // #bug #18693
if ($this->_rfc822_bodies) {
$encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
$return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body);
Expand Down Expand Up @@ -449,14 +472,27 @@ function _parseHeaders($input)
$input = preg_replace("/\r\n(\t| )+/", ' ', $input);

$headers = explode("\r\n", trim($input));

$got_start = false;
foreach ($headers as $value) {
if (!$got_start) {
// munge headers for mbox style from
if ($value[0] == '>') {
$value = substring($value, 1); // remove mbox >
}
if (substr($value,0,5) == 'From ') {
$value = 'Return-Path: ' . substr($value, 5);
} else {
$got_start = true;
}
}

$hdr_name = substr($value, 0, $pos = strpos($value, ':'));
$hdr_value = substr($value, $pos+1);
// ERP-modification: Small fix for notice level error
// if($hdr_value[0] == ' ')
if(isset($hdr_value[0]) && $hdr_value[0] == ' ')
// if($hdr_value[0] == ' ') {
if(isset($hdr_value[0]) && $hdr_value[0] == ' ') {
$hdr_value = substr($hdr_value, 1);
}

$return[] = array(
'name' => $hdr_name,
Expand All @@ -477,23 +513,33 @@ function _parseHeaders($input)
* robust as it could be. Eg. header comments
* in the wrong place will probably break it.
*
* Extra things this can handle
* filename*0=......
* filename*1=......
*
* This is where lines are broken in, and need merging.
*
* filename*0*=ENC'lang'urlencoded data.
* filename*1*=ENC'lang'urlencoded data.
*
*
*
* @param string Header value to parse
* @return array Contains parsed result
* @access private
*/
function _parseHeaderValue($input)
{

if (($pos = strpos($input, ';')) === false) {
$input = $this->_decode_headers ? $this->_decodeHeader($input) : $input;
$input = $this->_decodeHeader($input);
$return['value'] = trim($input);
return $return;
}



$value = substr($input, 0, $pos);
$value = $this->_decode_headers ? $this->_decodeHeader($value) : $value;
$value = $this->_decodeHeader($value);
$return['value'] = trim($value);
$input = trim(substr($input, $pos+1));

Expand Down Expand Up @@ -537,7 +583,6 @@ function _parseHeaderValue($input)
if ($key) { // a key without a value..
$key= trim($key);
$return['other'][$key] = '';
$return['other'][strtolower($key)] = '';
}
$key = '';
}
Expand All @@ -554,7 +599,11 @@ function _parseHeaderValue($input)
$i++;
continue; // skip leading spaces after '=' or after '"'
}
if (!$escaped && ($c == '"' || $c == "'")) {

// do not de-quote 'xxx*= itesm..
$key_is_trans = $key[strlen($key)-1] == '*';

if (!$key_is_trans && !$escaped && ($c == '"' || $c == "'")) {
// start quoted area..
$q = $c;
// in theory should not happen raw text in value part..
Expand All @@ -565,26 +614,8 @@ function _parseHeaderValue($input)
}
// got end....
if (!$escaped && $c == ';') {

$val = trim($val);
$added = false;
if (preg_match('/\*[0-9]+$/', $key)) {
// this is the extended aaa*0=...;aaa*1=.... code
// it assumes the pieces arrive in order, and are valid...
$key = preg_replace('/\*[0-9]+$/', '', $key);
if (isset($return['other'][$key])) {
$return['other'][$key] .= $val;
if (strtolower($key) != $key) {
$return['other'][strtolower($key)] .= $val;
}
$added = true;
}
// continue and use standard setters..
}
if (!$added) {
$return['other'][$key] = $val;
$return['other'][strtolower($key)] = $val;
}

$return['other'][$key] = trim($val);
$val = false;
$key = '';
$lq = false;
Expand All @@ -599,7 +630,7 @@ function _parseHeaderValue($input)

// state - in quote..
if (!$escaped && $c == $q) { // potential exit state..

// end of quoted string..
$lq = $q;
$q = false;
Expand All @@ -616,29 +647,58 @@ function _parseHeaderValue($input)
if (strlen(trim($key)) || $val !== false) {

$val = trim($val);
$added = false;
if ($val !== false && preg_match('/\*[0-9]+$/', $key)) {
// no dupes due to our crazy regexp.
$key = preg_replace('/\*[0-9]+$/', '', $key);
if (isset($return['other'][$key])) {
$return['other'][$key] .= $val;
if (strtolower($key) != $key) {
$return['other'][strtolower($key)] .= $val;
}
$added = true;

$return['other'][$key] = $val;
}


$clean_others = array();
// merge added values. eg. *1[*]
foreach($return['other'] as $key =>$val) {
if (preg_match('/\*[0-9]+\**$/', $key)) {
$key = preg_replace('/(.*)\*[0-9]+(\**)$/', '\1\2', $key);
if (isset($clean_others[$key])) {
$clean_others[$key] .= $val;
continue;
}
// continue and use standard setters..

}
if (!$added) {
$return['other'][$key] = $val;
$return['other'][strtolower($key)] = $val;
$clean_others[$key] = $val;

}

// handle language translation of '*' ending others.
foreach( $clean_others as $key =>$val) {
if ( $key[strlen($key)-1] != '*') {
$clean_others[strtolower($key)] = $val;
continue;
}
unset($clean_others[$key]);
$key = substr($key,0,-1);
//extended-initial-value := [charset] "'" [language] "'"
// extended-other-values
$match = array();
$info = preg_match("/^([^']+)'([^']*)'(.*)$/", $val, $match);

$clean_others[$key] = urldecode($match[3]);
$clean_others[strtolower($key)] = $clean_others[$key];
$clean_others[strtolower($key).'-charset'] = $match[1];
$clean_others[strtolower($key).'-language'] = $match[2];


}


$return['other'] = $clean_others;

// decode values.
foreach($return['other'] as $key =>$val) {
$return['other'][$key] = $this->_decode_headers ? $this->_decodeHeader($val) : $val;
$charset = isset($return['other'][$key . '-charset']) ?
$return['other'][$key . '-charset'] : false;

$return['other'][$key] = $this->_decodeHeader($val, $charset);
}
//print_r($return);
return $return;
}

Expand All @@ -650,7 +710,7 @@ function _parseHeaderValue($input)
* @return array Contains array of resulting mime parts
* @access private
*/
function _boundarySplit($input, $boundary)
function _boundarySplit($input, $boundary, $eatline = false)
{
$parts = array();

Expand All @@ -660,7 +720,10 @@ function _boundarySplit($input, $boundary)
if ($boundary == $bs_check) {
$boundary = $bs_possible;
}
$tmp = preg_split("/--".preg_quote($boundary, '/')."((?=\s)|--)/", $input);
// eatline is used by multipart/signed.
$tmp = $eatline ?
preg_split("/\r?\n--".preg_quote($boundary, '/')."(|--)\n/", $input) :
preg_split("/--".preg_quote($boundary, '/')."((?=\s)|--)/", $input);

$len = count($tmp) -1;
for ($i = 1; $i < $len; $i++) {
Expand All @@ -686,8 +749,11 @@ function _boundarySplit($input, $boundary)
* @return string Decoded header value
* @access private
*/
function _decodeHeader($input)
function _decodeHeader($input, $default_charset=false)
{
if (!$this->_decode_headers) {
return $input;
}
// Remove white space between encoded-words
$input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);

Expand All @@ -711,10 +777,18 @@ function _decodeHeader($input)
$text = str_replace('='.$value, chr(hexdec($value)), $text);
break;
}

if (is_string($this->_decode_headers)) {
$conv = @iconv($charset, $this->_decode_headers, $text);
$text = ($conv === false) ? $text : $conv;
}
$input = str_replace($encoded, $text, $input);
}


if ($default_charset && is_string($this->_decode_headers)) {
$conv = @iconv($charset, $this->_decode_headers, $input);
$input = ($conv === false) ? $input : $conv;
}

return $input;
}

Expand Down Expand Up @@ -761,9 +835,10 @@ function _quotedPrintableDecode($input)
$input = preg_replace("/=\r?\n/", '', $input);

// Replace encoded characters
// ERP-modification: PHP7 deprecated the /e PCRE modifier.
// $input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
$input = preg_replace_callback('/=([a-f0-9]{2})/i', function ($matches) { return chr(hexdec($matches[1])); }, $input);

$cb = create_function('$matches', ' return chr(hexdec($matches[0]));');

$input = preg_replace_callback( '/=([a-f0-9]{2})/i', $cb, $input);

return $input;
}
Expand Down
1 change: 1 addition & 0 deletions doc/CHANGELOG.txt
Expand Up @@ -4,6 +4,7 @@ Jul 2016 - EmailReporting-0.9.3-DEV
- Added error when __construct is not run when it should have
- Added fallback in case of an unknown email priority
- Added helper link for scheduled job setup
- Updated mimeDecode pear package to version 337165

Jul 2016 - EmailReporting-0.9.2
- Fixed collation check issue with MantisBT 1.3.x
Expand Down

0 comments on commit bc3474d

Please sign in to comment.