diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Header.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Header.php index ddf866a48..5f28dd8a4 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Header.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Header.php @@ -50,7 +50,6 @@ class Header function __construct(string $sName, string $sValue = '', string $sEncodedValueForReparse = '', string $sParentCharset = '') { $this->sParentCharset = $sParentCharset; - $this->initInputData($sName, $sValue, $sEncodedValueForReparse); } @@ -60,7 +59,6 @@ class Header $this->sFullValue = \trim($sValue); $this->sEncodedValueForReparse = ''; - $this->oParameters = null; if (\strlen($sEncodedValueForReparse) && $this->IsReparsed()) { $this->sEncodedValueForReparse = \trim($sEncodedValueForReparse); @@ -83,6 +81,10 @@ class Header { $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 @@ -147,6 +149,11 @@ class Header 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 { return \trim(substr(wordwrap($this->NameWithDelimitrom().$sValue, @@ -175,7 +182,7 @@ class Header 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); } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Message.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Message.php index 5f44d6fc1..900096198 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Message.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Message.php @@ -17,15 +17,6 @@ namespace MailSo\Mime; */ 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 */ @@ -318,12 +309,6 @@ class Message extends Part return $this; } - public function generateNewBoundary() : string - { - return '--='.\MailSo\Config::$BoundaryPrefix. - \rand(100, 999).'_'.\rand(100000000, 999999999).'.'.\time(); - } - private function generateNewMessageId(string $sHostName = '') : string { if (0 === \strlen($sHostName)) @@ -403,13 +388,9 @@ class Message extends Part if ($oAttachment->IsLinked()) { $oRelatedPart = new Part; $oRelatedPart->Headers->append( - new Header(Enumerations\Header::CONTENT_TYPE, - Enumerations\MimeType::MULTIPART_RELATED.'; '. - (new ParameterCollection)->Add( - new Parameter( - Enumerations\Parameter::BOUNDARY, - $this->generateNewBoundary()) - )->ToString() + new Header( + Enumerations\Header::CONTENT_TYPE, + Enumerations\MimeType::MULTIPART_RELATED ) ); $oRelatedPart->SubParts->append($oRootPart); @@ -419,13 +400,9 @@ class Message extends Part } } else { $oRootPart = new Part; - $oRootPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, - Enumerations\MimeType::MULTIPART_MIXED.'; '. - (new ParameterCollection)->Add( - new Parameter( - Enumerations\Parameter::BOUNDARY, - $this->generateNewBoundary()) - )->ToString() + $oRootPart->Headers->AddByName( + Enumerations\Header::CONTENT_TYPE, + Enumerations\MimeType::MULTIPART_MIXED ); $oRootPart->SubParts = $this->SubParts; } @@ -437,13 +414,9 @@ class Message extends Part } else { if (!$oMixedPart) { $oMixedPart = new Part; - $oMixedPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, - Enumerations\MimeType::MULTIPART_MIXED.'; '. - (new ParameterCollection)->Add( - new Parameter( - Enumerations\Parameter::BOUNDARY, - $this->generateNewBoundary()) - )->ToString() + $oMixedPart->Headers->AddByName( + Enumerations\Header::CONTENT_TYPE, + Enumerations\MimeType::MULTIPART_MIXED ); $oMixedPart->SubParts->append($oRootPart); $oRootPart = $oMixedPart; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parameter.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parameter.php index 2b87a6995..cc5c2cd4b 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parameter.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parameter.php @@ -57,6 +57,11 @@ class Parameter return $this->sValue; } + public function setValue(string $sValue) : void + { + $this->sValue = $sValue; + } + public function Parse(string $sRawParam, string $sSeparator = '=') : self { $this->Reset(); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/ParameterCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/ParameterCollection.php index ecd098d95..a556d30b0 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/ParameterCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/ParameterCollection.php @@ -35,17 +35,29 @@ class ParameterCollection extends \MailSo\Base\Collection public function ParameterValueByName(string $sName) : string { - $sName = \strtolower(\trim($sName)); + $oParam = $this->getParameter($sName); + return $oParam ? $oParam->Value() : ''; + } - foreach ($this as $oParam) - { - if ($sName === \strtolower($oParam->Name())) - { - return $oParam->Value(); + public function getParameter(string $sName) : ?Parameter + { + $sName = \strtolower(\trim($sName)); + foreach ($this as $oParam) { + 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 diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parser.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parser.php new file mode 100644 index 000000000..492801e44 --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parser.php @@ -0,0 +1,318 @@ +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; + } + +} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parser/ParserEmpty.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parser/ParserEmpty.php deleted file mode 100644 index 1b9096715..000000000 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Parser/ParserEmpty.php +++ /dev/null @@ -1,48 +0,0 @@ -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); - } - } -} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Part.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Part.php index c94e857e5..50ac0e4ad 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Part.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Part.php @@ -17,21 +17,11 @@ namespace MailSo\Mime; */ class Part { - const POS_HEADERS = 1; - const POS_BODY = 2; - const POS_SUBPARTS = 3; - const POS_CLOSE_BOUNDARY = 4; - /** * @var string */ public static $DefaultCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1; - /** - * @var string - */ - public static $ForceCharset = ''; - /** * @var HeaderCollection */ @@ -47,77 +37,35 @@ class Part */ public $SubParts; - /** - * @var string - */ - private $sBoundary = ''; - - /** - * @var string - */ - private $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1; - function __construct() { $this->Headers = new HeaderCollection; $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 { - return ($this->Headers) ? \trim(\strtolower($this->Headers->ParameterValue( - Enumerations\Header::CONTENT_TYPE, - Enumerations\Parameter::CHARSET))) : ''; + return \trim(\strtolower($this->Headers->ParameterValue(Enumerations\Header::CONTENT_TYPE, Enumerations\Parameter::CHARSET))); } public function HeaderBoundary() : string { - return ($this->Headers) ? \trim($this->Headers->ParameterValue( - Enumerations\Header::CONTENT_TYPE, - Enumerations\Parameter::BOUNDARY)) : ''; + return \trim($this->Headers->ParameterValue(Enumerations\Header::CONTENT_TYPE, Enumerations\Parameter::BOUNDARY)); } public function ContentType() : string { - return ($this->Headers) ? - \trim(\strtolower($this->Headers->ValueByName( - Enumerations\Header::CONTENT_TYPE))) : ''; + return \trim(\strtolower($this->Headers->ValueByName(Enumerations\Header::CONTENT_TYPE))); } public function ContentID() : string { - return ($this->Headers) ? \trim($this->Headers->ValueByName( - Enumerations\Header::CONTENT_ID)) : ''; + return \trim($this->Headers->ValueByName(Enumerations\Header::CONTENT_ID)); } public function ContentLocation() : string { - return ($this->Headers) ? \trim($this->Headers->ValueByName( - Enumerations\Header::CONTENT_LOCATION)) : ''; + return \trim($this->Headers->ValueByName(Enumerations\Header::CONTENT_LOCATION)); } public function IsFlowedFormat() : bool @@ -179,7 +127,7 @@ class Part $rStreamHandle = \file_exists($sFileName) ? \fopen($sFileName, 'rb') : false; if ($rStreamHandle) { try { - return static::FromStream($rStreamHandle); + return Parser::parseStream($rStreamHandle); } finally { \fclose($rStreamHandle); } @@ -197,7 +145,7 @@ class Part \fseek($rStreamHandle, 0); try { - return static::FromStream($rStreamHandle); + return Parser::parseStream($rStreamHandle); } finally { \MailSo\Base\ResourceRegistry::CloseMemoryResource($rStreamHandle); } @@ -208,315 +156,9 @@ class Part /** * @param resource $rStreamHandle */ - public $LineParts = []; - public static function FromStream($rStreamHandle) : ?self + public static function FromStream($rStreamHandle) : ?Part { - if (!\is_resource($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; + return Parser::parseStream($rStreamHandle); } /** @@ -524,38 +166,36 @@ class Part */ public function ToStream() { - if ($this->Body && \is_resource($this->Body)) - { - $aMeta = \stream_get_meta_data($this->Body); - if (!empty($aMeta['seekable'])) - { - \rewind($this->Body); + if ($this->SubParts->count()) { + $sBoundary = $this->HeaderBoundary(); + if (!\strlen($sBoundary)) { + $this->Headers->GetByName(Enumerations\Header::CONTENT_TYPE)->setParameter( + Enumerations\Parameter::BOUNDARY, + $this->SubParts->Boundary() + ); + } else { + $this->SubParts->SetBoundary($sBoundary); } } $aSubStreams = array( - - $this->Headers . "\r\n\r\n", - - null === $this->Body ? '' : $this->Body, - - "\r\n" + $this->Headers . "\r\n\r\n" ); - if ($this->SubParts->Count()) - { - $sBoundary = $this->HeaderBoundary(); - if (\strlen($sBoundary)) - { - $aSubStreams[] = "--{$sBoundary}\r\n"; - - $rSubPartsStream = $this->SubParts->ToStream($sBoundary); - if (\is_resource($rSubPartsStream)) - { - $aSubStreams[] = $rSubPartsStream; + if ($this->Body) { + if (\is_resource($this->Body)) { + $aMeta = \stream_get_meta_data($this->Body); + if (!empty($aMeta['seekable'])) { + \rewind($this->Body); } + } + $aSubStreams[] = $this->Body; + } - $aSubStreams[] = "\r\n--{$sBoundary}--\r\n"; + if ($this->SubParts->count()) { + $rSubPartsStream = $this->SubParts->ToStream(); + if (\is_resource($rSubPartsStream)) { + $aSubStreams[] = $rSubPartsStream; } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/PartCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/PartCollection.php index 36bafc0e9..e5f7f4395 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/PartCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/PartCollection.php @@ -17,34 +17,46 @@ namespace MailSo\Mime; */ class PartCollection extends \MailSo\Base\Collection { + protected $sBoundary; + public function append($oPart, bool $bToTop = false) : void { assert($oPart instanceof Part); 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 */ - public function ToStream(string $sBoundary) + public function ToStream() { - if (\strlen($sBoundary)) - { + if ($this->count() && $this->sBoundary) { $aResult = array(); - - foreach ($this as $oPart) - { - if (\count($aResult)) - { - $aResult[] = "\r\n--{$sBoundary}\r\n"; - } - + foreach ($this as $oPart) { + $aResult[] = "\r\n--{$this->sBoundary}\r\n"; $aResult[] = $oPart->ToStream(); } - + $aResult[] = "\r\n--{$this->sBoundary}--\r\n"; return \MailSo\Base\StreamWrappers\SubStreams::CreateStream($aResult); } - return null; } } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php index b4627ed56..d7d8d2129 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php @@ -1111,9 +1111,6 @@ trait Messages $oPart->Headers->AddByName( \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, \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); @@ -1150,12 +1147,11 @@ trait Messages $oPart = new MimePart; $oPart->Headers->AddByName( \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - 'multipart/signed; ' . (new \MailSo\Mime\ParameterCollection)->Add( - new \MailSo\Mime\Parameter(\MailSo\Mime\Enumerations\Parameter::BOUNDARY, $sBoundary) - )->ToString() . '; protocol="application/pgp-signature"' + 'multipart/signed; micalg="pgp-sha256"; protocol="application/pgp-signature"; boundary="'.$sBoundary.'"' ); - $oPart->Body = \str_replace("--{$sBoundary}--", '', $aSigned[1]); + $oPart->Body = $aSigned[1]; $oMessage->SubParts->append($oPart); + $oMessage->SubParts->SetBoundary($sBoundary); unset($oAlternativePart); unset($sSigned); @@ -1164,9 +1160,7 @@ trait Messages $oPart = new MimePart; $oPart->Headers->AddByName( \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - 'multipart/encrypted; ' . (new \MailSo\Mime\ParameterCollection)->Add( - new \MailSo\Mime\Parameter(\MailSo\Mime\Enumerations\Parameter::BOUNDARY, $oMessage->generateNewBoundary()) - )->ToString() . '; protocol="application/pgp-encrypted"' + 'multipart/encrypted; protocol="application/pgp-encrypted"' ); $oMessage->SubParts->append($oPart); @@ -1193,9 +1187,7 @@ trait Messages $oPart = new MimePart; $oPart->Headers->AddByName( \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - 'multipart/signed; ' . (new ParameterCollection)->Add( - new \MailSo\Mime\Parameter(\MailSo\Mime\Enumerations\Parameter::BOUNDARY, $oMessage->generateNewBoundary()) - )->ToString() . '; micalg="pgp-sha256"; protocol="application/pgp-signature"' + 'multipart/signed; micalg="pgp-sha256"; protocol="application/pgp-signature"' ); $oMessage->SubParts->append($oPart);