mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-08 00:47:04 +03:00
Bugfix sending OpenPGP.js signed messages
Cleanup and revamp MailSo/Mime for better multipart handling
This commit is contained in:
parent
8428838a8b
commit
ff8e76631b
11 changed files with 422 additions and 588 deletions
|
|
@ -50,7 +50,6 @@ class Header
|
||||||
function __construct(string $sName, string $sValue = '', string $sEncodedValueForReparse = '', string $sParentCharset = '')
|
function __construct(string $sName, string $sValue = '', string $sEncodedValueForReparse = '', string $sParentCharset = '')
|
||||||
{
|
{
|
||||||
$this->sParentCharset = $sParentCharset;
|
$this->sParentCharset = $sParentCharset;
|
||||||
|
|
||||||
$this->initInputData($sName, $sValue, $sEncodedValueForReparse);
|
$this->initInputData($sName, $sValue, $sEncodedValueForReparse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,7 +59,6 @@ class Header
|
||||||
$this->sFullValue = \trim($sValue);
|
$this->sFullValue = \trim($sValue);
|
||||||
$this->sEncodedValueForReparse = '';
|
$this->sEncodedValueForReparse = '';
|
||||||
|
|
||||||
$this->oParameters = null;
|
|
||||||
if (\strlen($sEncodedValueForReparse) && $this->IsReparsed())
|
if (\strlen($sEncodedValueForReparse) && $this->IsReparsed())
|
||||||
{
|
{
|
||||||
$this->sEncodedValueForReparse = \trim($sEncodedValueForReparse);
|
$this->sEncodedValueForReparse = \trim($sEncodedValueForReparse);
|
||||||
|
|
@ -83,6 +81,10 @@ class Header
|
||||||
{
|
{
|
||||||
$this->sValue = $this->sFullValue;
|
$this->sValue = $this->sFullValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$this->oParameters) {
|
||||||
|
$this->oParameters = new ParameterCollection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function NewInstanceFromEncodedString(string $sEncodedLines, string $sIncomingCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1) : Header
|
public static function NewInstanceFromEncodedString(string $sEncodedLines, string $sIncomingCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1) : Header
|
||||||
|
|
@ -147,6 +149,11 @@ class Header
|
||||||
return $this->oParameters;
|
return $this->oParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setParameter(string $sName, string $sValue) : void
|
||||||
|
{
|
||||||
|
$this->oParameters->setParameter($sName, $sValue);
|
||||||
|
}
|
||||||
|
|
||||||
private function wordWrapHelper(string $sValue, string $sGlue = "\r\n ") : string
|
private function wordWrapHelper(string $sValue, string $sGlue = "\r\n ") : string
|
||||||
{
|
{
|
||||||
return \trim(substr(wordwrap($this->NameWithDelimitrom().$sValue,
|
return \trim(substr(wordwrap($this->NameWithDelimitrom().$sValue,
|
||||||
|
|
@ -175,7 +182,7 @@ class Header
|
||||||
return \iconv_mime_encode($this->Name(), $sResult, $aPreferences);
|
return \iconv_mime_encode($this->Name(), $sResult, $aPreferences);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ($this->IsParameterized() && $this->oParameters && 0 < $this->oParameters->Count())
|
else if ($this->IsParameterized() && 0 < $this->oParameters->Count())
|
||||||
{
|
{
|
||||||
$sResult = $this->sValue.'; '.$this->oParameters->ToString(true);
|
$sResult = $this->sValue.'; '.$this->oParameters->ToString(true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,6 @@ namespace MailSo\Mime;
|
||||||
*/
|
*/
|
||||||
class Message extends Part
|
class Message extends Part
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
public static $DefaultCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1;
|
|
||||||
public static $ForceCharset = '';
|
|
||||||
public $Headers;
|
|
||||||
public $Body = null;
|
|
||||||
public $SubParts;
|
|
||||||
private $sBoundary = '';
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
|
|
@ -318,12 +309,6 @@ class Message extends Part
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateNewBoundary() : string
|
|
||||||
{
|
|
||||||
return '--='.\MailSo\Config::$BoundaryPrefix.
|
|
||||||
\rand(100, 999).'_'.\rand(100000000, 999999999).'.'.\time();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function generateNewMessageId(string $sHostName = '') : string
|
private function generateNewMessageId(string $sHostName = '') : string
|
||||||
{
|
{
|
||||||
if (0 === \strlen($sHostName))
|
if (0 === \strlen($sHostName))
|
||||||
|
|
@ -403,13 +388,9 @@ class Message extends Part
|
||||||
if ($oAttachment->IsLinked()) {
|
if ($oAttachment->IsLinked()) {
|
||||||
$oRelatedPart = new Part;
|
$oRelatedPart = new Part;
|
||||||
$oRelatedPart->Headers->append(
|
$oRelatedPart->Headers->append(
|
||||||
new Header(Enumerations\Header::CONTENT_TYPE,
|
new Header(
|
||||||
Enumerations\MimeType::MULTIPART_RELATED.'; '.
|
Enumerations\Header::CONTENT_TYPE,
|
||||||
(new ParameterCollection)->Add(
|
Enumerations\MimeType::MULTIPART_RELATED
|
||||||
new Parameter(
|
|
||||||
Enumerations\Parameter::BOUNDARY,
|
|
||||||
$this->generateNewBoundary())
|
|
||||||
)->ToString()
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$oRelatedPart->SubParts->append($oRootPart);
|
$oRelatedPart->SubParts->append($oRootPart);
|
||||||
|
|
@ -419,13 +400,9 @@ class Message extends Part
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$oRootPart = new Part;
|
$oRootPart = new Part;
|
||||||
$oRootPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE,
|
$oRootPart->Headers->AddByName(
|
||||||
Enumerations\MimeType::MULTIPART_MIXED.'; '.
|
Enumerations\Header::CONTENT_TYPE,
|
||||||
(new ParameterCollection)->Add(
|
Enumerations\MimeType::MULTIPART_MIXED
|
||||||
new Parameter(
|
|
||||||
Enumerations\Parameter::BOUNDARY,
|
|
||||||
$this->generateNewBoundary())
|
|
||||||
)->ToString()
|
|
||||||
);
|
);
|
||||||
$oRootPart->SubParts = $this->SubParts;
|
$oRootPart->SubParts = $this->SubParts;
|
||||||
}
|
}
|
||||||
|
|
@ -437,13 +414,9 @@ class Message extends Part
|
||||||
} else {
|
} else {
|
||||||
if (!$oMixedPart) {
|
if (!$oMixedPart) {
|
||||||
$oMixedPart = new Part;
|
$oMixedPart = new Part;
|
||||||
$oMixedPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE,
|
$oMixedPart->Headers->AddByName(
|
||||||
Enumerations\MimeType::MULTIPART_MIXED.'; '.
|
Enumerations\Header::CONTENT_TYPE,
|
||||||
(new ParameterCollection)->Add(
|
Enumerations\MimeType::MULTIPART_MIXED
|
||||||
new Parameter(
|
|
||||||
Enumerations\Parameter::BOUNDARY,
|
|
||||||
$this->generateNewBoundary())
|
|
||||||
)->ToString()
|
|
||||||
);
|
);
|
||||||
$oMixedPart->SubParts->append($oRootPart);
|
$oMixedPart->SubParts->append($oRootPart);
|
||||||
$oRootPart = $oMixedPart;
|
$oRootPart = $oMixedPart;
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,11 @@ class Parameter
|
||||||
return $this->sValue;
|
return $this->sValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setValue(string $sValue) : void
|
||||||
|
{
|
||||||
|
$this->sValue = $sValue;
|
||||||
|
}
|
||||||
|
|
||||||
public function Parse(string $sRawParam, string $sSeparator = '=') : self
|
public function Parse(string $sRawParam, string $sSeparator = '=') : self
|
||||||
{
|
{
|
||||||
$this->Reset();
|
$this->Reset();
|
||||||
|
|
|
||||||
|
|
@ -35,17 +35,29 @@ class ParameterCollection extends \MailSo\Base\Collection
|
||||||
|
|
||||||
public function ParameterValueByName(string $sName) : string
|
public function ParameterValueByName(string $sName) : string
|
||||||
{
|
{
|
||||||
$sName = \strtolower(\trim($sName));
|
$oParam = $this->getParameter($sName);
|
||||||
|
return $oParam ? $oParam->Value() : '';
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($this as $oParam)
|
public function getParameter(string $sName) : ?Parameter
|
||||||
{
|
{
|
||||||
if ($sName === \strtolower($oParam->Name()))
|
$sName = \strtolower(\trim($sName));
|
||||||
{
|
foreach ($this as $oParam) {
|
||||||
return $oParam->Value();
|
if ($sName === \strtolower($oParam->Name())) {
|
||||||
|
return $oParam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return '';
|
public function setParameter(string $sName, string $sValue) : void
|
||||||
|
{
|
||||||
|
$oParam = $this->getParameter($sName);
|
||||||
|
if ($oParam) {
|
||||||
|
$oParam->setValue($sValue);
|
||||||
|
} else {
|
||||||
|
parent::append(new Parameter(\trim($sName), $sValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Parse(string $sRawParams) : self
|
public function Parse(string $sRawParams) : self
|
||||||
|
|
|
||||||
318
snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parser.php
Normal file
318
snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parser.php
Normal file
|
|
@ -0,0 +1,318 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of MailSo.
|
||||||
|
*
|
||||||
|
* (c) 2014 Usenko Timur
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MailSo\Mime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @category MailSo
|
||||||
|
* @package Mime
|
||||||
|
*/
|
||||||
|
abstract class Parser
|
||||||
|
{
|
||||||
|
const
|
||||||
|
POS_HEADERS = 1,
|
||||||
|
POS_BODY = 2,
|
||||||
|
POS_SUBPARTS = 3,
|
||||||
|
POS_CLOSE_BOUNDARY = 4;
|
||||||
|
|
||||||
|
private static $LineParts = [];
|
||||||
|
|
||||||
|
protected static function writeBody(Part $oPart, string $sBuffer) : void
|
||||||
|
{
|
||||||
|
if (null === $oPart->Body) {
|
||||||
|
$oPart->Body = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
|
||||||
|
}
|
||||||
|
if (\is_resource($oPart->Body)) {
|
||||||
|
\fwrite($oPart->Body, $sBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param resource $rStreamHandle
|
||||||
|
*/
|
||||||
|
public static function parseStream($rStreamHandle) : ?Part
|
||||||
|
{
|
||||||
|
if (!\is_resource($rStreamHandle)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$oPart = new Part;
|
||||||
|
|
||||||
|
$bIsOef = false;
|
||||||
|
$iOffset = 0;
|
||||||
|
$sBuffer = '';
|
||||||
|
$sPrevBuffer = '';
|
||||||
|
$aBoundaryStack = array();
|
||||||
|
|
||||||
|
static::$LineParts = [$oPart];
|
||||||
|
|
||||||
|
static::parseStreamRecursive($oPart, $rStreamHandle, $iOffset,
|
||||||
|
$sPrevBuffer, $sBuffer, $aBoundaryStack, $bIsOef);
|
||||||
|
|
||||||
|
$oMimePart = null;
|
||||||
|
$sFirstNotNullCharset = null;
|
||||||
|
foreach (static::$LineParts as /* @var $oMimePart Part */ $oMimePart)
|
||||||
|
{
|
||||||
|
$sCharset = $oMimePart->HeaderCharset();
|
||||||
|
if (\strlen($sCharset))
|
||||||
|
{
|
||||||
|
$sFirstNotNullCharset = $sCharset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sFirstNotNullCharset = (null !== $sFirstNotNullCharset)
|
||||||
|
? $sFirstNotNullCharset : Part::$DefaultCharset;
|
||||||
|
|
||||||
|
foreach (static::$LineParts as /* @var $oMimePart Part */ $oMimePart)
|
||||||
|
{
|
||||||
|
$sHeaderCharset = $oMimePart->HeaderCharset();
|
||||||
|
$oMimePart->Headers->SetParentCharset($sHeaderCharset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$LineParts = [];
|
||||||
|
return $oPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param resource $rStreamHandle
|
||||||
|
*/
|
||||||
|
public static function parseStreamRecursive(Part $oPart, $rStreamHandle, int &$iOffset,
|
||||||
|
string &$sPrevBuffer, string &$sBuffer, array &$aBoundaryStack, bool &$bIsOef, bool $bNotFirstRead = false) : void
|
||||||
|
{
|
||||||
|
$iPos = 0;
|
||||||
|
$iParsePosition = self::POS_HEADERS;
|
||||||
|
$sCurrentBoundary = '';
|
||||||
|
$bIsBoundaryCheck = false;
|
||||||
|
$aHeadersLines = array();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (!$bNotFirstRead)
|
||||||
|
{
|
||||||
|
$sPrevBuffer = $sBuffer;
|
||||||
|
$sBuffer = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$bIsOef && !\feof($rStreamHandle))
|
||||||
|
{
|
||||||
|
if (!$bNotFirstRead)
|
||||||
|
{
|
||||||
|
$sBuffer = \fread($rStreamHandle, 8192);
|
||||||
|
if (false === $sBuffer)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$bNotFirstRead = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($bIsOef && !\strlen($sBuffer))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$bIsOef = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
$sCurrentLine = $sPrevBuffer.$sBuffer;
|
||||||
|
if (self::POS_HEADERS === $iParsePosition)
|
||||||
|
{
|
||||||
|
$iEndLen = 4;
|
||||||
|
$iPos = \strpos($sCurrentLine, "\r\n\r\n", $iOffset);
|
||||||
|
if (false === $iPos)
|
||||||
|
{
|
||||||
|
$iEndLen = 2;
|
||||||
|
$iPos = \strpos($sCurrentLine, "\n\n", $iOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== $iPos)
|
||||||
|
{
|
||||||
|
$aHeadersLines[] = \substr($sCurrentLine, $iOffset, $iPos + $iEndLen - $iOffset);
|
||||||
|
|
||||||
|
$oPart->Headers->Parse(\implode($aHeadersLines))->SetParentCharset($oPart->HeaderCharset());
|
||||||
|
$aHeadersLines = array();
|
||||||
|
|
||||||
|
$sBoundary = $oPart->HeaderBoundary();
|
||||||
|
if (\strlen($sBoundary))
|
||||||
|
{
|
||||||
|
$sBoundary = '--'.$sBoundary;
|
||||||
|
$sCurrentBoundary = $sBoundary;
|
||||||
|
\array_unshift($aBoundaryStack, $sBoundary);
|
||||||
|
}
|
||||||
|
|
||||||
|
$iOffset = $iPos + $iEndLen;
|
||||||
|
$iParsePosition = self::POS_BODY;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$iBufferLen = \strlen($sPrevBuffer);
|
||||||
|
if ($iBufferLen > $iOffset)
|
||||||
|
{
|
||||||
|
$aHeadersLines[] = \substr($sPrevBuffer, $iOffset);
|
||||||
|
$iOffset = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$iOffset -= $iBufferLen;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (self::POS_BODY === $iParsePosition)
|
||||||
|
{
|
||||||
|
$iPos = false;
|
||||||
|
$sBoundaryLen = 0;
|
||||||
|
$bIsBoundaryEnd = false;
|
||||||
|
$bCurrentPartBody = false;
|
||||||
|
$bIsBoundaryCheck = \count($aBoundaryStack);
|
||||||
|
|
||||||
|
foreach ($aBoundaryStack as $sKey => $sBoundary)
|
||||||
|
{
|
||||||
|
if (false !== ($iPos = \strpos($sCurrentLine, $sBoundary, $iOffset)))
|
||||||
|
{
|
||||||
|
if ($sCurrentBoundary === $sBoundary)
|
||||||
|
{
|
||||||
|
$bCurrentPartBody = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sBoundaryLen = \strlen($sBoundary);
|
||||||
|
if ('--' === \substr($sCurrentLine, $iPos + $sBoundaryLen, 2))
|
||||||
|
{
|
||||||
|
$sBoundaryLen += 2;
|
||||||
|
$bIsBoundaryEnd = true;
|
||||||
|
unset($aBoundaryStack[$sKey]);
|
||||||
|
$sCurrentBoundary = (isset($aBoundaryStack[$sKey + 1]))
|
||||||
|
? $aBoundaryStack[$sKey + 1] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== $iPos)
|
||||||
|
{
|
||||||
|
static::writeBody($oPart, \substr($sCurrentLine, $iOffset, $iPos - $iOffset));
|
||||||
|
$iOffset = $iPos;
|
||||||
|
|
||||||
|
if ($bCurrentPartBody)
|
||||||
|
{
|
||||||
|
$iParsePosition = self::POS_SUBPARTS;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$iBufferLen = \strlen($sPrevBuffer);
|
||||||
|
if ($iBufferLen > $iOffset)
|
||||||
|
{
|
||||||
|
static::writeBody($oPart, \substr($sPrevBuffer, $iOffset));
|
||||||
|
$iOffset = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$iOffset -= $iBufferLen;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (self::POS_SUBPARTS === $iParsePosition)
|
||||||
|
{
|
||||||
|
$iPos = false;
|
||||||
|
$iBoundaryLen = 0;
|
||||||
|
$bIsBoundaryEnd = false;
|
||||||
|
$bCurrentPartBody = false;
|
||||||
|
$bIsBoundaryCheck = \count($aBoundaryStack);
|
||||||
|
|
||||||
|
foreach ($aBoundaryStack as $sKey => $sBoundary)
|
||||||
|
{
|
||||||
|
if (false !== ($iPos = \strpos($sCurrentLine, $sBoundary, $iOffset)))
|
||||||
|
{
|
||||||
|
if ($sCurrentBoundary === $sBoundary)
|
||||||
|
{
|
||||||
|
$bCurrentPartBody = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$iBoundaryLen = \strlen($sBoundary);
|
||||||
|
if ('--' === \substr($sCurrentLine, $iPos + $iBoundaryLen, 2))
|
||||||
|
{
|
||||||
|
$iBoundaryLen += 2;
|
||||||
|
$bIsBoundaryEnd = true;
|
||||||
|
unset($aBoundaryStack[$sKey]);
|
||||||
|
$sCurrentBoundary = (isset($aBoundaryStack[$sKey + 1]))
|
||||||
|
? $aBoundaryStack[$sKey + 1] : '';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== $iPos && $bCurrentPartBody)
|
||||||
|
{
|
||||||
|
$iOffset = $iPos + $iBoundaryLen;
|
||||||
|
|
||||||
|
$oSubPart = new Part;
|
||||||
|
|
||||||
|
$oSubPart->parseStreamRecursive($rStreamHandle,
|
||||||
|
$iOffset, $sPrevBuffer, $sBuffer, $aBoundaryStack, $bIsOef, true);
|
||||||
|
|
||||||
|
$oPart->SubParts->append($oSubPart);
|
||||||
|
static::$LineParts[] = $oSubPart;
|
||||||
|
//$iParsePosition = self::POS_HEADERS;
|
||||||
|
unset($oSubPart);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\strlen($sPrevBuffer))
|
||||||
|
{
|
||||||
|
if (self::POS_HEADERS === $iParsePosition)
|
||||||
|
{
|
||||||
|
$aHeadersLines[] = ($iOffset < \strlen($sPrevBuffer))
|
||||||
|
? \substr($sPrevBuffer, $iOffset)
|
||||||
|
: $sPrevBuffer;
|
||||||
|
|
||||||
|
$oPart->Headers->Parse(\implode($aHeadersLines))->SetParentCharset($oPart->HeaderCharset());
|
||||||
|
$aHeadersLines = array();
|
||||||
|
}
|
||||||
|
else if (self::POS_BODY === $iParsePosition)
|
||||||
|
{
|
||||||
|
if (!$bIsBoundaryCheck)
|
||||||
|
{
|
||||||
|
static::writeBody($oPart, ($iOffset < \strlen($sPrevBuffer))
|
||||||
|
? \substr($sPrevBuffer, $iOffset) : $sPrevBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (self::POS_HEADERS === $iParsePosition && \count($aHeadersLines))
|
||||||
|
{
|
||||||
|
$oPart->Headers->Parse(\implode($aHeadersLines))->SetParentCharset($oPart->HeaderCharset());
|
||||||
|
$aHeadersLines = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of MailSo.
|
|
||||||
*
|
|
||||||
* (c) 2014 Usenko Timur
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MailSo\Mime\Parser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @category MailSo
|
|
||||||
* @package Mime
|
|
||||||
* @subpackage Parser
|
|
||||||
*/
|
|
||||||
class ParserEmpty implements ParserInterface
|
|
||||||
{
|
|
||||||
public function StartParse(\MailSo\Mime\Part $oPart) : void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function EndParse(\MailSo\Mime\Part $oPart) : void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function StartParseMimePart(\MailSo\Mime\Part $oPart) : void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function EndParseMimePart(\MailSo\Mime\Part $oPart) : void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function InitMimePartHeader() : void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function ReadBuffer(string $sBuffer) : void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function WriteBody(string $sBuffer) : void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of MailSo.
|
|
||||||
*
|
|
||||||
* (c) 2014 Usenko Timur
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MailSo\Mime\Parser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @category MailSo
|
|
||||||
* @package Mime
|
|
||||||
* @subpackage Parser
|
|
||||||
*/
|
|
||||||
interface ParserInterface
|
|
||||||
{
|
|
||||||
public function StartParse(\MailSo\Mime\Part $oPart) : void;
|
|
||||||
|
|
||||||
public function EndParse(\MailSo\Mime\Part $oPart) : void;
|
|
||||||
|
|
||||||
public function StartParseMimePart(\MailSo\Mime\Part $oPart) : void;
|
|
||||||
|
|
||||||
public function EndParseMimePart(\MailSo\Mime\Part $oPart) : void;
|
|
||||||
|
|
||||||
public function InitMimePartHeader() : void;
|
|
||||||
|
|
||||||
public function ReadBuffer(string $sBuffer) : void;
|
|
||||||
|
|
||||||
public function WriteBody(string $sBuffer) : void;
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of MailSo.
|
|
||||||
*
|
|
||||||
* (c) 2014 Usenko Timur
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MailSo\Mime\Parser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @category MailSo
|
|
||||||
* @package Mime
|
|
||||||
* @subpackage Parser
|
|
||||||
*/
|
|
||||||
class ParserMemory extends ParserEmpty implements ParserInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var \MailSo\Mime\Part
|
|
||||||
*/
|
|
||||||
protected $oCurrentMime = null;
|
|
||||||
|
|
||||||
public function StartParseMimePart(\MailSo\Mime\Part $oPart) : void
|
|
||||||
{
|
|
||||||
$this->oCurrentMime = $oPart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function WriteBody(string $sBuffer) : void
|
|
||||||
{
|
|
||||||
if (null === $this->oCurrentMime->Body)
|
|
||||||
{
|
|
||||||
$this->oCurrentMime->Body = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\is_resource($this->oCurrentMime->Body))
|
|
||||||
{
|
|
||||||
\fwrite($this->oCurrentMime->Body, $sBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -17,21 +17,11 @@ namespace MailSo\Mime;
|
||||||
*/
|
*/
|
||||||
class Part
|
class Part
|
||||||
{
|
{
|
||||||
const POS_HEADERS = 1;
|
|
||||||
const POS_BODY = 2;
|
|
||||||
const POS_SUBPARTS = 3;
|
|
||||||
const POS_CLOSE_BOUNDARY = 4;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public static $DefaultCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1;
|
public static $DefaultCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public static $ForceCharset = '';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var HeaderCollection
|
* @var HeaderCollection
|
||||||
*/
|
*/
|
||||||
|
|
@ -47,77 +37,35 @@ class Part
|
||||||
*/
|
*/
|
||||||
public $SubParts;
|
public $SubParts;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sBoundary = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1;
|
|
||||||
|
|
||||||
function __construct()
|
function __construct()
|
||||||
{
|
{
|
||||||
$this->Headers = new HeaderCollection;
|
$this->Headers = new HeaderCollection;
|
||||||
$this->SubParts = new PartCollection;
|
$this->SubParts = new PartCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Boundary() : string
|
|
||||||
{
|
|
||||||
return $this->sBoundary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function ParentCharset() : string
|
|
||||||
{
|
|
||||||
return (\strlen($this->sCharset)) ? $this->sParentCharset : self::$DefaultCharset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function SetParentCharset(string $sParentCharset) : self
|
|
||||||
{
|
|
||||||
$this->sParentCharset = $sParentCharset;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function SetBoundary(string $sBoundary) : self
|
|
||||||
{
|
|
||||||
$this->sBoundary = $sBoundary;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function HeaderCharset() : string
|
public function HeaderCharset() : string
|
||||||
{
|
{
|
||||||
return ($this->Headers) ? \trim(\strtolower($this->Headers->ParameterValue(
|
return \trim(\strtolower($this->Headers->ParameterValue(Enumerations\Header::CONTENT_TYPE, Enumerations\Parameter::CHARSET)));
|
||||||
Enumerations\Header::CONTENT_TYPE,
|
|
||||||
Enumerations\Parameter::CHARSET))) : '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function HeaderBoundary() : string
|
public function HeaderBoundary() : string
|
||||||
{
|
{
|
||||||
return ($this->Headers) ? \trim($this->Headers->ParameterValue(
|
return \trim($this->Headers->ParameterValue(Enumerations\Header::CONTENT_TYPE, Enumerations\Parameter::BOUNDARY));
|
||||||
Enumerations\Header::CONTENT_TYPE,
|
|
||||||
Enumerations\Parameter::BOUNDARY)) : '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ContentType() : string
|
public function ContentType() : string
|
||||||
{
|
{
|
||||||
return ($this->Headers) ?
|
return \trim(\strtolower($this->Headers->ValueByName(Enumerations\Header::CONTENT_TYPE)));
|
||||||
\trim(\strtolower($this->Headers->ValueByName(
|
|
||||||
Enumerations\Header::CONTENT_TYPE))) : '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ContentID() : string
|
public function ContentID() : string
|
||||||
{
|
{
|
||||||
return ($this->Headers) ? \trim($this->Headers->ValueByName(
|
return \trim($this->Headers->ValueByName(Enumerations\Header::CONTENT_ID));
|
||||||
Enumerations\Header::CONTENT_ID)) : '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ContentLocation() : string
|
public function ContentLocation() : string
|
||||||
{
|
{
|
||||||
return ($this->Headers) ? \trim($this->Headers->ValueByName(
|
return \trim($this->Headers->ValueByName(Enumerations\Header::CONTENT_LOCATION));
|
||||||
Enumerations\Header::CONTENT_LOCATION)) : '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function IsFlowedFormat() : bool
|
public function IsFlowedFormat() : bool
|
||||||
|
|
@ -179,7 +127,7 @@ class Part
|
||||||
$rStreamHandle = \file_exists($sFileName) ? \fopen($sFileName, 'rb') : false;
|
$rStreamHandle = \file_exists($sFileName) ? \fopen($sFileName, 'rb') : false;
|
||||||
if ($rStreamHandle) {
|
if ($rStreamHandle) {
|
||||||
try {
|
try {
|
||||||
return static::FromStream($rStreamHandle);
|
return Parser::parseStream($rStreamHandle);
|
||||||
} finally {
|
} finally {
|
||||||
\fclose($rStreamHandle);
|
\fclose($rStreamHandle);
|
||||||
}
|
}
|
||||||
|
|
@ -197,7 +145,7 @@ class Part
|
||||||
\fseek($rStreamHandle, 0);
|
\fseek($rStreamHandle, 0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return static::FromStream($rStreamHandle);
|
return Parser::parseStream($rStreamHandle);
|
||||||
} finally {
|
} finally {
|
||||||
\MailSo\Base\ResourceRegistry::CloseMemoryResource($rStreamHandle);
|
\MailSo\Base\ResourceRegistry::CloseMemoryResource($rStreamHandle);
|
||||||
}
|
}
|
||||||
|
|
@ -208,315 +156,9 @@ class Part
|
||||||
/**
|
/**
|
||||||
* @param resource $rStreamHandle
|
* @param resource $rStreamHandle
|
||||||
*/
|
*/
|
||||||
public $LineParts = [];
|
public static function FromStream($rStreamHandle) : ?Part
|
||||||
public static function FromStream($rStreamHandle) : ?self
|
|
||||||
{
|
{
|
||||||
if (!\is_resource($rStreamHandle)) {
|
return Parser::parseStream($rStreamHandle);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$self = new self;
|
|
||||||
|
|
||||||
$oParserClass = new Parser\ParserMemory;
|
|
||||||
|
|
||||||
$oMimePart = null;
|
|
||||||
$bIsOef = false;
|
|
||||||
$iOffset = 0;
|
|
||||||
$sBuffer = '';
|
|
||||||
$sPrevBuffer = '';
|
|
||||||
$aBoundaryStack = array();
|
|
||||||
|
|
||||||
|
|
||||||
$oParserClass->StartParse($self);
|
|
||||||
|
|
||||||
$self->LineParts[] =& $self;
|
|
||||||
$self->ParseFromStreamRecursion($rStreamHandle, $oParserClass, $iOffset,
|
|
||||||
$sPrevBuffer, $sBuffer, $aBoundaryStack, $bIsOef);
|
|
||||||
|
|
||||||
$sFirstNotNullCharset = null;
|
|
||||||
foreach ($self->LineParts as /* @var $oMimePart Part */ $oMimePart)
|
|
||||||
{
|
|
||||||
$sCharset = $oMimePart->HeaderCharset();
|
|
||||||
if (\strlen($sCharset))
|
|
||||||
{
|
|
||||||
$sFirstNotNullCharset = $sCharset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$sForceCharset = self::$ForceCharset;
|
|
||||||
if (\strlen($sForceCharset))
|
|
||||||
{
|
|
||||||
foreach ($self->LineParts as /* @var $oMimePart Part */ $oMimePart)
|
|
||||||
{
|
|
||||||
$oMimePart->SetParentCharset($sForceCharset);
|
|
||||||
$oMimePart->Headers->SetParentCharset($sForceCharset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sFirstNotNullCharset = (null !== $sFirstNotNullCharset)
|
|
||||||
? $sFirstNotNullCharset : self::$DefaultCharset;
|
|
||||||
|
|
||||||
foreach ($self->LineParts as /* @var $oMimePart Part */ $oMimePart)
|
|
||||||
{
|
|
||||||
$sHeaderCharset = $oMimePart->HeaderCharset();
|
|
||||||
$oMimePart->SetParentCharset((\strlen($sHeaderCharset)) ? $sHeaderCharset : $sFirstNotNullCharset);
|
|
||||||
$oMimePart->Headers->SetParentCharset($sHeaderCharset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$oParserClass->EndParse($self);
|
|
||||||
|
|
||||||
$self->LineParts = [];
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param resource $rStreamHandle
|
|
||||||
*/
|
|
||||||
protected function ParseFromStreamRecursion($rStreamHandle, $oCallbackClass, int &$iOffset,
|
|
||||||
string &$sPrevBuffer, string &$sBuffer, array &$aBoundaryStack, bool &$bIsOef, bool $bNotFirstRead = false) : self
|
|
||||||
{
|
|
||||||
$oCallbackClass->StartParseMimePart($this);
|
|
||||||
|
|
||||||
$iPos = 0;
|
|
||||||
$iParsePosition = self::POS_HEADERS;
|
|
||||||
$sCurrentBoundary = '';
|
|
||||||
$bIsBoundaryCheck = false;
|
|
||||||
$aHeadersLines = array();
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (!$bNotFirstRead)
|
|
||||||
{
|
|
||||||
$sPrevBuffer = $sBuffer;
|
|
||||||
$sBuffer = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$bIsOef && !\feof($rStreamHandle))
|
|
||||||
{
|
|
||||||
if (!$bNotFirstRead)
|
|
||||||
{
|
|
||||||
$sBuffer = \fread($rStreamHandle, 8192);
|
|
||||||
if (false === $sBuffer)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oCallbackClass->ReadBuffer($sBuffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$bNotFirstRead = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ($bIsOef && !\strlen($sBuffer))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$bIsOef = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
$sCurrentLine = $sPrevBuffer.$sBuffer;
|
|
||||||
if (self::POS_HEADERS === $iParsePosition)
|
|
||||||
{
|
|
||||||
$iEndLen = 4;
|
|
||||||
$iPos = \strpos($sCurrentLine, "\r\n\r\n", $iOffset);
|
|
||||||
if (false === $iPos)
|
|
||||||
{
|
|
||||||
$iEndLen = 2;
|
|
||||||
$iPos = \strpos($sCurrentLine, "\n\n", $iOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false !== $iPos)
|
|
||||||
{
|
|
||||||
$aHeadersLines[] = \substr($sCurrentLine, $iOffset, $iPos + $iEndLen - $iOffset);
|
|
||||||
|
|
||||||
$this->Headers->Parse(\implode($aHeadersLines))->SetParentCharset($this->HeaderCharset());
|
|
||||||
$aHeadersLines = array();
|
|
||||||
|
|
||||||
$oCallbackClass->InitMimePartHeader();
|
|
||||||
|
|
||||||
$sBoundary = $this->HeaderBoundary();
|
|
||||||
if (\strlen($sBoundary))
|
|
||||||
{
|
|
||||||
$sBoundary = '--'.$sBoundary;
|
|
||||||
$sCurrentBoundary = $sBoundary;
|
|
||||||
\array_unshift($aBoundaryStack, $sBoundary);
|
|
||||||
}
|
|
||||||
|
|
||||||
$iOffset = $iPos + $iEndLen;
|
|
||||||
$iParsePosition = self::POS_BODY;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$iBufferLen = \strlen($sPrevBuffer);
|
|
||||||
if ($iBufferLen > $iOffset)
|
|
||||||
{
|
|
||||||
$aHeadersLines[] = \substr($sPrevBuffer, $iOffset);
|
|
||||||
$iOffset = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$iOffset -= $iBufferLen;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (self::POS_BODY === $iParsePosition)
|
|
||||||
{
|
|
||||||
$iPos = false;
|
|
||||||
$sBoundaryLen = 0;
|
|
||||||
$bIsBoundaryEnd = false;
|
|
||||||
$bCurrentPartBody = false;
|
|
||||||
$bIsBoundaryCheck = \count($aBoundaryStack);
|
|
||||||
|
|
||||||
foreach ($aBoundaryStack as $sKey => $sBoundary)
|
|
||||||
{
|
|
||||||
if (false !== ($iPos = \strpos($sCurrentLine, $sBoundary, $iOffset)))
|
|
||||||
{
|
|
||||||
if ($sCurrentBoundary === $sBoundary)
|
|
||||||
{
|
|
||||||
$bCurrentPartBody = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sBoundaryLen = \strlen($sBoundary);
|
|
||||||
if ('--' === \substr($sCurrentLine, $iPos + $sBoundaryLen, 2))
|
|
||||||
{
|
|
||||||
$sBoundaryLen += 2;
|
|
||||||
$bIsBoundaryEnd = true;
|
|
||||||
unset($aBoundaryStack[$sKey]);
|
|
||||||
$sCurrentBoundary = (isset($aBoundaryStack[$sKey + 1]))
|
|
||||||
? $aBoundaryStack[$sKey + 1] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false !== $iPos)
|
|
||||||
{
|
|
||||||
$oCallbackClass->WriteBody(\substr($sCurrentLine, $iOffset, $iPos - $iOffset));
|
|
||||||
$iOffset = $iPos;
|
|
||||||
|
|
||||||
if ($bCurrentPartBody)
|
|
||||||
{
|
|
||||||
$iParsePosition = self::POS_SUBPARTS;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oCallbackClass->EndParseMimePart($this);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$iBufferLen = \strlen($sPrevBuffer);
|
|
||||||
if ($iBufferLen > $iOffset)
|
|
||||||
{
|
|
||||||
$oCallbackClass->WriteBody(\substr($sPrevBuffer, $iOffset));
|
|
||||||
$iOffset = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$iOffset -= $iBufferLen;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (self::POS_SUBPARTS === $iParsePosition)
|
|
||||||
{
|
|
||||||
$iPos = false;
|
|
||||||
$iBoundaryLen = 0;
|
|
||||||
$bIsBoundaryEnd = false;
|
|
||||||
$bCurrentPartBody = false;
|
|
||||||
$bIsBoundaryCheck = \count($aBoundaryStack);
|
|
||||||
|
|
||||||
foreach ($aBoundaryStack as $sKey => $sBoundary)
|
|
||||||
{
|
|
||||||
if (false !== ($iPos = \strpos($sCurrentLine, $sBoundary, $iOffset)))
|
|
||||||
{
|
|
||||||
if ($sCurrentBoundary === $sBoundary)
|
|
||||||
{
|
|
||||||
$bCurrentPartBody = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$iBoundaryLen = \strlen($sBoundary);
|
|
||||||
if ('--' === \substr($sCurrentLine, $iPos + $iBoundaryLen, 2))
|
|
||||||
{
|
|
||||||
$iBoundaryLen += 2;
|
|
||||||
$bIsBoundaryEnd = true;
|
|
||||||
unset($aBoundaryStack[$sKey]);
|
|
||||||
$sCurrentBoundary = (isset($aBoundaryStack[$sKey + 1]))
|
|
||||||
? $aBoundaryStack[$sKey + 1] : '';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false !== $iPos && $bCurrentPartBody)
|
|
||||||
{
|
|
||||||
$iOffset = $iPos + $iBoundaryLen;
|
|
||||||
|
|
||||||
$oSubPart = new self;
|
|
||||||
|
|
||||||
$oSubPart->ParseFromStreamRecursion($rStreamHandle, $oCallbackClass,
|
|
||||||
$iOffset, $sPrevBuffer, $sBuffer, $aBoundaryStack, $bIsOef, true);
|
|
||||||
|
|
||||||
$this->SubParts->append($oSubPart);
|
|
||||||
$this->LineParts[] =& $oSubPart;
|
|
||||||
//$iParsePosition = self::POS_HEADERS;
|
|
||||||
unset($oSubPart);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$oCallbackClass->EndParseMimePart($this);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\strlen($sPrevBuffer))
|
|
||||||
{
|
|
||||||
if (self::POS_HEADERS === $iParsePosition)
|
|
||||||
{
|
|
||||||
$aHeadersLines[] = ($iOffset < \strlen($sPrevBuffer))
|
|
||||||
? \substr($sPrevBuffer, $iOffset)
|
|
||||||
: $sPrevBuffer;
|
|
||||||
|
|
||||||
$this->Headers->Parse(\implode($aHeadersLines))->SetParentCharset($this->HeaderCharset());
|
|
||||||
$aHeadersLines = array();
|
|
||||||
|
|
||||||
$oCallbackClass->InitMimePartHeader();
|
|
||||||
}
|
|
||||||
else if (self::POS_BODY === $iParsePosition)
|
|
||||||
{
|
|
||||||
if (!$bIsBoundaryCheck)
|
|
||||||
{
|
|
||||||
$oCallbackClass->WriteBody(($iOffset < \strlen($sPrevBuffer))
|
|
||||||
? \substr($sPrevBuffer, $iOffset) : $sPrevBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (self::POS_HEADERS === $iParsePosition && \count($aHeadersLines))
|
|
||||||
{
|
|
||||||
$this->Headers->Parse(\implode($aHeadersLines))->SetParentCharset($this->HeaderCharset());
|
|
||||||
$aHeadersLines = array();
|
|
||||||
|
|
||||||
$oCallbackClass->InitMimePartHeader();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$oCallbackClass->EndParseMimePart($this);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -524,38 +166,36 @@ class Part
|
||||||
*/
|
*/
|
||||||
public function ToStream()
|
public function ToStream()
|
||||||
{
|
{
|
||||||
if ($this->Body && \is_resource($this->Body))
|
if ($this->SubParts->count()) {
|
||||||
{
|
$sBoundary = $this->HeaderBoundary();
|
||||||
$aMeta = \stream_get_meta_data($this->Body);
|
if (!\strlen($sBoundary)) {
|
||||||
if (!empty($aMeta['seekable']))
|
$this->Headers->GetByName(Enumerations\Header::CONTENT_TYPE)->setParameter(
|
||||||
{
|
Enumerations\Parameter::BOUNDARY,
|
||||||
\rewind($this->Body);
|
$this->SubParts->Boundary()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->SubParts->SetBoundary($sBoundary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$aSubStreams = array(
|
$aSubStreams = array(
|
||||||
|
$this->Headers . "\r\n\r\n"
|
||||||
$this->Headers . "\r\n\r\n",
|
|
||||||
|
|
||||||
null === $this->Body ? '' : $this->Body,
|
|
||||||
|
|
||||||
"\r\n"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($this->SubParts->Count())
|
if ($this->Body) {
|
||||||
{
|
if (\is_resource($this->Body)) {
|
||||||
$sBoundary = $this->HeaderBoundary();
|
$aMeta = \stream_get_meta_data($this->Body);
|
||||||
if (\strlen($sBoundary))
|
if (!empty($aMeta['seekable'])) {
|
||||||
{
|
\rewind($this->Body);
|
||||||
$aSubStreams[] = "--{$sBoundary}\r\n";
|
|
||||||
|
|
||||||
$rSubPartsStream = $this->SubParts->ToStream($sBoundary);
|
|
||||||
if (\is_resource($rSubPartsStream))
|
|
||||||
{
|
|
||||||
$aSubStreams[] = $rSubPartsStream;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
$aSubStreams[] = $this->Body;
|
||||||
|
}
|
||||||
|
|
||||||
$aSubStreams[] = "\r\n--{$sBoundary}--\r\n";
|
if ($this->SubParts->count()) {
|
||||||
|
$rSubPartsStream = $this->SubParts->ToStream();
|
||||||
|
if (\is_resource($rSubPartsStream)) {
|
||||||
|
$aSubStreams[] = $rSubPartsStream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,34 +17,46 @@ namespace MailSo\Mime;
|
||||||
*/
|
*/
|
||||||
class PartCollection extends \MailSo\Base\Collection
|
class PartCollection extends \MailSo\Base\Collection
|
||||||
{
|
{
|
||||||
|
protected $sBoundary;
|
||||||
|
|
||||||
public function append($oPart, bool $bToTop = false) : void
|
public function append($oPart, bool $bToTop = false) : void
|
||||||
{
|
{
|
||||||
assert($oPart instanceof Part);
|
assert($oPart instanceof Part);
|
||||||
parent::append($oPart, $bToTop);
|
parent::append($oPart, $bToTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static $increment = 0;
|
||||||
|
public function Boundary() : string
|
||||||
|
{
|
||||||
|
if (!$this->sBoundary) {
|
||||||
|
$this->sBoundary =
|
||||||
|
\MailSo\Config::$BoundaryPrefix
|
||||||
|
. \SnappyMail\UUID::generate()
|
||||||
|
. '-' . ++static::$increment;
|
||||||
|
|
||||||
|
}
|
||||||
|
return $this->sBoundary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function SetBoundary(string $sBoundary) : void
|
||||||
|
{
|
||||||
|
$this->sBoundary = $sBoundary;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return resource|bool|null
|
* @return resource|bool|null
|
||||||
*/
|
*/
|
||||||
public function ToStream(string $sBoundary)
|
public function ToStream()
|
||||||
{
|
{
|
||||||
if (\strlen($sBoundary))
|
if ($this->count() && $this->sBoundary) {
|
||||||
{
|
|
||||||
$aResult = array();
|
$aResult = array();
|
||||||
|
foreach ($this as $oPart) {
|
||||||
foreach ($this as $oPart)
|
$aResult[] = "\r\n--{$this->sBoundary}\r\n";
|
||||||
{
|
|
||||||
if (\count($aResult))
|
|
||||||
{
|
|
||||||
$aResult[] = "\r\n--{$sBoundary}\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
$aResult[] = $oPart->ToStream();
|
$aResult[] = $oPart->ToStream();
|
||||||
}
|
}
|
||||||
|
$aResult[] = "\r\n--{$this->sBoundary}--\r\n";
|
||||||
return \MailSo\Base\StreamWrappers\SubStreams::CreateStream($aResult);
|
return \MailSo\Base\StreamWrappers\SubStreams::CreateStream($aResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1111,9 +1111,6 @@ trait Messages
|
||||||
$oPart->Headers->AddByName(
|
$oPart->Headers->AddByName(
|
||||||
\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
|
\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
|
||||||
\MailSo\Mime\Enumerations\MimeType::MULTIPART_ALTERNATIVE
|
\MailSo\Mime\Enumerations\MimeType::MULTIPART_ALTERNATIVE
|
||||||
. '; ' . (new \MailSo\Mime\ParameterCollection)->Add(
|
|
||||||
new \MailSo\Mime\Parameter(\MailSo\Mime\Enumerations\Parameter::BOUNDARY, $oMessage->generateNewBoundary())
|
|
||||||
)->ToString()
|
|
||||||
);
|
);
|
||||||
$oMessage->SubParts->append($oPart);
|
$oMessage->SubParts->append($oPart);
|
||||||
|
|
||||||
|
|
@ -1150,12 +1147,11 @@ trait Messages
|
||||||
$oPart = new MimePart;
|
$oPart = new MimePart;
|
||||||
$oPart->Headers->AddByName(
|
$oPart->Headers->AddByName(
|
||||||
\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
|
\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
|
||||||
'multipart/signed; ' . (new \MailSo\Mime\ParameterCollection)->Add(
|
'multipart/signed; micalg="pgp-sha256"; protocol="application/pgp-signature"; boundary="'.$sBoundary.'"'
|
||||||
new \MailSo\Mime\Parameter(\MailSo\Mime\Enumerations\Parameter::BOUNDARY, $sBoundary)
|
|
||||||
)->ToString() . '; protocol="application/pgp-signature"'
|
|
||||||
);
|
);
|
||||||
$oPart->Body = \str_replace("--{$sBoundary}--", '', $aSigned[1]);
|
$oPart->Body = $aSigned[1];
|
||||||
$oMessage->SubParts->append($oPart);
|
$oMessage->SubParts->append($oPart);
|
||||||
|
$oMessage->SubParts->SetBoundary($sBoundary);
|
||||||
|
|
||||||
unset($oAlternativePart);
|
unset($oAlternativePart);
|
||||||
unset($sSigned);
|
unset($sSigned);
|
||||||
|
|
@ -1164,9 +1160,7 @@ trait Messages
|
||||||
$oPart = new MimePart;
|
$oPart = new MimePart;
|
||||||
$oPart->Headers->AddByName(
|
$oPart->Headers->AddByName(
|
||||||
\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
|
\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
|
||||||
'multipart/encrypted; ' . (new \MailSo\Mime\ParameterCollection)->Add(
|
'multipart/encrypted; protocol="application/pgp-encrypted"'
|
||||||
new \MailSo\Mime\Parameter(\MailSo\Mime\Enumerations\Parameter::BOUNDARY, $oMessage->generateNewBoundary())
|
|
||||||
)->ToString() . '; protocol="application/pgp-encrypted"'
|
|
||||||
);
|
);
|
||||||
$oMessage->SubParts->append($oPart);
|
$oMessage->SubParts->append($oPart);
|
||||||
|
|
||||||
|
|
@ -1193,9 +1187,7 @@ trait Messages
|
||||||
$oPart = new MimePart;
|
$oPart = new MimePart;
|
||||||
$oPart->Headers->AddByName(
|
$oPart->Headers->AddByName(
|
||||||
\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
|
\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
|
||||||
'multipart/signed; ' . (new ParameterCollection)->Add(
|
'multipart/signed; micalg="pgp-sha256"; protocol="application/pgp-signature"'
|
||||||
new \MailSo\Mime\Parameter(\MailSo\Mime\Enumerations\Parameter::BOUNDARY, $oMessage->generateNewBoundary())
|
|
||||||
)->ToString() . '; micalg="pgp-sha256"; protocol="application/pgp-signature"'
|
|
||||||
);
|
);
|
||||||
$oMessage->SubParts->append($oPart);
|
$oMessage->SubParts->append($oPart);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue