Commit 59c3ea8d authored by mku's avatar mku

ZP-322 #comment Merge contribution - Mail_mimeDecode rebase to 1.5.5 #time 20m

git-svn-id: https://z-push.org/svn/z-push/trunk@1576 b7dd7b3b-3a3c-0410-9da9-bee62a6cc5b5
parent 7de261a0
......@@ -28,8 +28,8 @@
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of the authors, nor the names of its contributors
* may be used to endorse or promote products derived from this
* - Neither the name of the authors, nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
......@@ -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 288500 2009-09-21 05:32:32Z alan_k $
* @version CVS: $Id: mimeDecode.php 305875 2010-12-01 07:17:10Z alan_k $
* @link http://pear.php.net/package/Mail_mime
*/
......@@ -61,11 +61,10 @@
* Z-Push changes
*
* removed PEAR dependency by implementing own raiseError()
* removed deprecated referencing: $obj = &new Mail_mimeDecode($body); in _decode()
* implemented automated decoding of strings from mail charset
*
* Reference implementation used:
* http://download.pear.php.net/package/Mail_mimeDecode-1.5.1.tgz
* http://download.pear.php.net/package/Mail_mimeDecode-1.5.5.tgz
*
*/
......@@ -209,10 +208,10 @@ class Mail_mimeDecode
function decode($params = null)
{
// determine if this method has been called statically
$isStatic = !(isset($this) && get_class($this) == __CLASS__);
$isStatic = empty($this) || !is_a($this, __CLASS__);
// Have we been called statically?
// If so, create an object and pass details to that.
// If so, create an object and pass details to that.
if ($isStatic AND isset($params['input'])) {
$obj = new Mail_mimeDecode($params['input']);
......@@ -225,13 +224,13 @@ class Mail_mimeDecode
// Called via an object
} else {
$this->_include_bodies = isset($params['include_bodies']) ?
$params['include_bodies'] : false;
$params['include_bodies'] : false;
$this->_decode_bodies = isset($params['decode_bodies']) ?
$params['decode_bodies'] : false;
$params['decode_bodies'] : false;
$this->_decode_headers = isset($params['decode_headers']) ?
$params['decode_headers'] : false;
$params['decode_headers'] : false;
$this->_rfc822_bodies = isset($params['rfc_822bodies']) ?
$params['rfc_822bodies'] : false;
$params['rfc_822bodies'] : false;
$this->_charset = isset($params['charset']) ?
strtolower($params['charset']) : 'utf-8';
......@@ -261,6 +260,7 @@ class Mail_mimeDecode
$headers = $this->_parseHeaders($headers);
foreach ($headers as $value) {
$value['value'] = $this->_decode_headers ? $this->_decodeHeader($value['value']) : $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'];
......@@ -273,8 +273,8 @@ class Mail_mimeDecode
}
}
reset($headers);
while (list($key, $value) = each($headers)) {
foreach ($headers as $key => $value) {
$headers[$key]['name'] = strtolower($headers[$key]['name']);
switch ($headers[$key]['name']) {
......@@ -287,7 +287,7 @@ class Mail_mimeDecode
}
if (isset($content_type['other'])) {
while (list($p_name, $p_value) = each($content_type['other'])) {
foreach($content_type['other'] as $p_name => $p_value) {
$return->ctype_parameters[$p_name] = $p_value;
}
}
......@@ -297,7 +297,7 @@ class Mail_mimeDecode
$content_disposition = $this->_parseHeaderValue($headers[$key]['value']);
$return->disposition = $content_disposition['value'];
if (isset($content_disposition['other'])) {
while (list($p_name, $p_value) = each($content_disposition['other'])) {
foreach($content_disposition['other'] as $p_name => $p_value) {
$return->d_parameters[$p_name] = $p_value;
}
}
......@@ -331,6 +331,7 @@ class Mail_mimeDecode
case 'multipart/alternative':
case 'multipart/related':
case 'multipart/mixed':
case 'application/vnd.wap.multipart.related':
if(!isset($content_type['other']['boundary'])){
$this->_error = 'No boundary found for ' . $content_type['value'] . ' part';
return false;
......@@ -437,6 +438,11 @@ class Mail_mimeDecode
if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
return array($match[1], $match[2]);
}
// bug #17325 - empty bodies are allowed. - we just check that at least one line
// of headers exist..
if (count(explode("\n",$input))) {
return array($input, '');
}
$this->_error = 'Could not split header and body';
return false;
}
......@@ -455,7 +461,12 @@ class Mail_mimeDecode
if ($input !== '') {
// Unfold the input
$input = preg_replace("/\r?\n/", "\r\n", $input);
//#7065 - wrapping.. with encoded stuff.. - probably not needed,
// wrapping space should only get removed if the trailing item on previous line is a
// encoded character
$input = preg_replace("/=\r\n(\t| )+/", '=', $input);
$input = preg_replace("/\r\n(\t| )+/", ' ', $input);
$headers = explode("\r\n", trim($input));
foreach ($headers as $value) {
......@@ -466,7 +477,7 @@ class Mail_mimeDecode
$return[] = array(
'name' => $hdr_name,
'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value
'value' => $hdr_value
);
}
} else {
......@@ -490,44 +501,161 @@ class Mail_mimeDecode
function _parseHeaderValue($input)
{
if (($pos = strpos($input, ';')) !== false) {
if (($pos = strpos($input, ';')) === false) {
$input = $this->_decode_headers ? $this->_decodeHeader($input) : $input;
$return['value'] = trim($input);
return $return;
}
$return['value'] = trim(substr($input, 0, $pos));
$input = trim(substr($input, $pos+1));
if (strlen($input) > 0) {
// This splits on a semi-colon, if there's no preceeding backslash
// Now works with quoted values; had to glue the \; breaks in PHP
// the regex is already bordering on incomprehensible
//$splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/';
// simplyfied RegEx - Nokia Mail2 sends boundaries containing ' which break the above regex
$splitRegex = '/([^;\'"]*[\'"]([^\'"]*)[\'"][^;\'"]*|([^;]+))(;|$)/';
preg_match_all($splitRegex, $input, $matches);
$value = substr($input, 0, $pos);
$value = $this->_decode_headers ? $this->_decodeHeader($value) : $value;
$return['value'] = trim($value);
$input = trim(substr($input, $pos+1));
$parameters = array();
for ($i=0; $i<count($matches[0]); $i++) {
$param = $matches[0][$i];
while (substr($param, -2) == '\;') {
$param .= $matches[0][++$i];
if (!strlen($input) > 0) {
return $return;
}
// at this point input contains xxxx=".....";zzzz="...."
// since we are dealing with quoted strings, we need to handle this properly..
$i = 0;
$l = strlen($input);
$key = '';
$val = false; // our string - including quotes..
$q = false; // in quote..
$lq = ''; // last quote..
while ($i < $l) {
$c = $input[$i];
//var_dump(array('i'=>$i,'c'=>$c,'q'=>$q, 'lq'=>$lq, 'key'=>$key, 'val' =>$val));
$escaped = false;
if ($c == '\\') {
$i++;
if ($i == $l-1) { // end of string.
break;
}
$escaped = true;
$c = $input[$i];
}
// state - in key..
if ($val === false) {
if (!$escaped && $c == '=') {
$val = '';
$key = trim($key);
$i++;
continue;
}
if (!$escaped && $c == ';') {
if ($key) { // a key without a value..
$key= trim($key);
$return['other'][$key] = '';
$return['other'][strtolower($key)] = '';
}
$key = '';
}
$key .= $c;
$i++;
continue;
}
// state - in value.. (as $val is set..)
if ($q === false) {
// not in quote yet.
if ((!strlen($val) || $lq !== false) && $c == ' ' || $c == "\t") {
$i++;
continue; // skip leading spaces after '=' or after '"'
}
if (!$escaped && ($c == '"' || $c == "'")) {
// start quoted area..
$q = $c;
// in theory should not happen raw text in value part..
// but we will handle it as a merged part of the string..
$val = !strlen(trim($val)) ? '' : trim($val);
$i++;
continue;
}
// 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..
}
$parameters[] = $param;
if (!$added) {
$return['other'][$key] = $val;
$return['other'][strtolower($key)] = $val;
}
$val = false;
$key = '';
$lq = false;
$i++;
continue;
}
for ($i = 0; $i < count($parameters); $i++) {
$param_name = trim(substr($parameters[$i], 0, $pos = strpos($parameters[$i], '=')), "'\";\t\\ ");
$param_value = trim(str_replace('\;', ';', substr($parameters[$i], $pos + 1)), "'\";\t\\ ");
if (!empty($param_value[0]) && $param_value[0] == '"') {
$param_value = substr($param_value, 1, -1);
$val .= $c;
$i++;
continue;
}
// state - in quote..
if (!$escaped && $c == $q) { // potential exit state..
// end of quoted string..
$lq = $q;
$q = false;
$i++;
continue;
}
// normal char inside of quoted string..
$val.= $c;
$i++;
}
// do we have anything left..
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;
}
$return['other'][$param_name] = $param_value;
$return['other'][strtolower($param_name)] = $param_value;
$added = true;
}
// continue and use standard setters..
}
if (!$added) {
$return['other'][$key] = $val;
$return['other'][strtolower($key)] = $val;
}
} else {
$return['value'] = trim($input);
}
// decode values.
foreach($return['other'] as $key =>$val) {
$return['other'][$key] = $this->_decode_headers ? $this->_decodeHeader($val) : $val;
}
//print_r($return);
return $return;
}
......@@ -549,13 +677,19 @@ class Mail_mimeDecode
if ($boundary == $bs_check) {
$boundary = $bs_possible;
}
$tmp = preg_split("/--".preg_quote($boundary, '/')."((?=\s)|--)/", $input);
$tmp = explode('--' . $boundary, $input);
for ($i = 1; $i < count($tmp) - 1; $i++) {
$parts[] = $tmp[$i];
$len = count($tmp) -1;
for ($i = 1; $i < $len; $i++) {
if (strlen(trim($tmp[$i]))) {
$parts[] = $tmp[$i];
}
}
// add the last part on if it does not end with the 'closing indicator'
if (!empty($tmp[$len]) && strlen(trim($tmp[$len])) && $tmp[$len][0] != '-') {
$parts[] = $tmp[$len];
}
return $parts;
}
......@@ -648,7 +782,7 @@ class Mail_mimeDecode
$input = preg_replace("/=\r?\n/", '', $input);
// Replace encoded characters
$input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
$input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
return $input;
}
......@@ -730,7 +864,7 @@ class Mail_mimeDecode
/**
* getSendArray() returns the arguments required for Mail::send()
* used to build the arguments for a mail::send() call
* used to build the arguments for a mail::send() call
*
* Usage:
* $mailtext = Full email (for example generated by a template)
......@@ -772,7 +906,7 @@ class Mail_mimeDecode
}
$to = substr($to,1);
return array($to,$header,$this->_body);
}
}
/**
* Returns a xml copy of the output of
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment