File: //usr/local/CyberCP/public/snappymail/snappymail/v/2.38.2/app/libraries/MailSo/Mime/Part.php
<?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;
use MailSo\Mime\Enumerations\ContentType;
/**
* @category MailSo
* @package Mime
*/
class Part
{
public HeaderCollection $Headers;
/**
* @var resource
*/
public $Body = null;
/**
* @var resource
*/
public $Raw = null;
public PartCollection $SubParts;
function __construct()
{
$this->Headers = new HeaderCollection;
$this->SubParts = new PartCollection;
}
public function HeaderCharset() : string
{
return \trim(\strtolower($this->Headers->ParameterValue(Enumerations\Header::CONTENT_TYPE, Enumerations\Parameter::CHARSET)));
}
public function HeaderBoundary() : string
{
return \trim($this->Headers->ParameterValue(Enumerations\Header::CONTENT_TYPE, Enumerations\Parameter::BOUNDARY));
}
public function ContentType() : string
{
return \trim(\strtolower($this->Headers->ValueByName(Enumerations\Header::CONTENT_TYPE)));
}
public function IsFlowedFormat() : bool
{
$bResult = 'flowed' === \trim(\strtolower($this->Headers->ParameterValue(
Enumerations\Header::CONTENT_TYPE,
Enumerations\Parameter::FORMAT)));
if ($bResult && \in_array($this->ContentTransferEncoding(), array('base64', 'quoted-printable'))) {
$bResult = false;
}
return $bResult;
}
public function FileName() : string
{
$sResult = \trim($this->Headers->ParameterValue(
Enumerations\Header::CONTENT_DISPOSITION,
Enumerations\Parameter::FILENAME));
if (!\strlen($sResult)) {
$sResult = \trim($this->Headers->ParameterValue(
Enumerations\Header::CONTENT_TYPE,
Enumerations\Parameter::NAME));
}
return $sResult;
}
// https://datatracker.ietf.org/doc/html/rfc3156#section-5
public function isPgpSigned() : bool
{
$header = $this->Headers->GetByName(Enumerations\Header::CONTENT_TYPE);
return $header
&& \preg_match('#multipart/signed.+protocol=["\']?application/pgp-signature#si', $header->FullValue())
// The multipart/signed body MUST consist of exactly two parts.
&& 2 === \count($this->SubParts)
&& 'application/pgp-signature' === $this->SubParts[1]->ContentType();
}
// https://www.rfc-editor.org/rfc/rfc8551.html#section-3.5
public function isSMimeSigned() : bool
{
$header = $this->Headers->GetByName(Enumerations\Header::CONTENT_TYPE);
return ($header
&& \preg_match('#multipart/signed.+protocol=["\']?application/(x-)?pkcs7-signature#si', $header->FullValue())
// The multipart/signed body MUST consist of exactly two parts.
&& 2 === \count($this->SubParts)
&& ContentType::isPkcs7Signature($this->SubParts[1]->ContentType())
) || ($header
&& \preg_match('#application/(x-)?pkcs7-mime.+smime-type=["\']?signed-data#si', $header->FullValue())
);
}
public static function FromFile(string $sFileName) : ?self
{
$rStreamHandle = \file_exists($sFileName) ? \fopen($sFileName, 'rb') : false;
if ($rStreamHandle) {
try {
return Parser::parseStream($rStreamHandle);
} finally {
\fclose($rStreamHandle);
}
}
return null;
}
public static function FromString(string $sRawMessage) : ?self
{
$rStreamHandle = \strlen($sRawMessage) ?
\MailSo\Base\ResourceRegistry::CreateMemoryResource() : false;
if ($rStreamHandle) {
\fwrite($rStreamHandle, $sRawMessage);
unset($sRawMessage);
\fseek($rStreamHandle, 0);
try {
return Parser::parseStream($rStreamHandle);
} finally {
\MailSo\Base\ResourceRegistry::CloseMemoryResource($rStreamHandle);
}
}
return null;
}
/**
* @param resource $rStreamHandle
*/
public static function FromStream($rStreamHandle) : ?Part
{
return Parser::parseStream($rStreamHandle);
}
/**
* @return resource|bool
*/
public function ToStream()
{
if ($this->Raw) {
$aSubStreams = array(
$this->Raw
);
} else {
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"
);
if ($this->Body) {
$aSubStreams[0] .= "\r\n";
if (\is_resource($this->Body)) {
$aMeta = \stream_get_meta_data($this->Body);
if (!empty($aMeta['seekable'])) {
\rewind($this->Body);
}
}
$aSubStreams[] = $this->Body;
}
if ($this->SubParts->count()) {
$rSubPartsStream = $this->SubParts->ToStream();
if (\is_resource($rSubPartsStream)) {
$aSubStreams[] = $rSubPartsStream;
}
}
}
return \MailSo\Base\StreamWrappers\SubStreams::CreateStream($aSubStreams);
}
public function addPgpEncrypted(string $sEncrypted)
{
$oPart = new self;
$oPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, 'multipart/encrypted; protocol="application/pgp-encrypted"');
$this->SubParts->append($oPart);
$oSubPart = new self;
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, 'application/pgp-encrypted');
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_DISPOSITION, 'attachment');
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_TRANSFER_ENCODING, '7Bit');
$oSubPart->Body = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString('Version: 1');
$oPart->SubParts->append($oSubPart);
$oSubPart = new self;
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, 'application/octet-stream');
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_DISPOSITION, 'inline; filename="msg.asc"');
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_TRANSFER_ENCODING, '7Bit');
$oSubPart->Body = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sEncrypted);
$oPart->SubParts->append($oSubPart);
}
public function addPlain(string $sPlain)
{
$oPart = new self;
$oPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, 'text/plain; charset=utf-8');
$oPart->Headers->AddByName(Enumerations\Header::CONTENT_TRANSFER_ENCODING, 'quoted-printable');
$oPart->Body = \MailSo\Base\StreamWrappers\Binary::CreateStream(
\MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString(\preg_replace('/\\r?\\n/su', "\r\n", \trim($sPlain))),
'convert.quoted-printable-encode'
);
$this->SubParts->append($oPart);
}
}