mirror of
https://github.com/itflow-org/itflow
synced 2026-03-13 17:24:51 +00:00
Add new optional beta email parser thats based on ImapEngine instead of Webklex
This commit is contained in:
3
plugins/vendor/zbateson/mail-mime-parser/.github/FUNDING.yml
vendored
Normal file
3
plugins/vendor/zbateson/mail-mime-parser/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: zbateson
|
||||
36
plugins/vendor/zbateson/mail-mime-parser/.github/workflows/tests.yml
vendored
Normal file
36
plugins/vendor/zbateson/mail-mime-parser/.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
php: [8.5, 8.4, 8.3, 8.2, 8.1, 8.0]
|
||||
stability: [prefer-stable]
|
||||
|
||||
name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
|
||||
coverage: none
|
||||
|
||||
- name: Setup problem matchers
|
||||
run: |
|
||||
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
- name: Install dependencies
|
||||
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction
|
||||
|
||||
- name: Execute tests
|
||||
run: ./vendor/bin/phpunit -c tests/phpunit.xml
|
||||
15
plugins/vendor/zbateson/mail-mime-parser/.php-cs-fixer.dist.php
vendored
Normal file
15
plugins/vendor/zbateson/mail-mime-parser/.php-cs-fixer.dist.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*
|
||||
* This document has been generated with
|
||||
* https://mlocati.github.io/php-cs-fixer-configurator/#version:3.0.0-rc.1|configurator
|
||||
* you can change this configuration by importing this file.
|
||||
*
|
||||
*/
|
||||
|
||||
$config = include 'vendor/zbateson/mb-wrapper/PhpCsFixer.php';
|
||||
|
||||
return $config->setFinder(PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->in(__DIR__.'/src')
|
||||
->in(__DIR__.'/tests')
|
||||
);
|
||||
24
plugins/vendor/zbateson/mail-mime-parser/LICENSE
vendored
Normal file
24
plugins/vendor/zbateson/mail-mime-parser/LICENSE
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2014-2015, Zaahid Bateson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
4
plugins/vendor/zbateson/mail-mime-parser/PHPStanConstants.php
vendored
Normal file
4
plugins/vendor/zbateson/mail-mime-parser/PHPStanConstants.php
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
define ('TEST_DATA_DIR', __DIR__ . '/tests/_data');
|
||||
define ('TEST_OUTPUT_DIR', __DIR__ . '/tests/_output');
|
||||
125
plugins/vendor/zbateson/mail-mime-parser/README.md
vendored
Normal file
125
plugins/vendor/zbateson/mail-mime-parser/README.md
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
# zbateson/mail-mime-parser
|
||||
|
||||
Testable and PSR-compliant mail mime parser alternative to PHP's imap* functions and Pear libraries for reading messages in _Internet Message Format_ [RFC 822](http://tools.ietf.org/html/rfc822) (and later revisions [RFC 2822](http://tools.ietf.org/html/rfc2822), [RFC 5322](http://tools.ietf.org/html/rfc5322)).
|
||||
|
||||
[](https://github.com/zbateson/mail-mime-parser/actions/workflows/tests.yml)
|
||||
[](https://scrutinizer-ci.com/g/zbateson/mail-mime-parser/?branch=master)
|
||||
[](https://scrutinizer-ci.com/g/zbateson/mail-mime-parser/?branch=master)
|
||||
[](//packagist.org/packages/zbateson/mail-mime-parser)
|
||||
[](//packagist.org/packages/zbateson/mail-mime-parser)
|
||||
|
||||
The goals of this project are to be:
|
||||
|
||||
* Well written
|
||||
* Standards-compliant but forgiving
|
||||
* Tested where possible
|
||||
|
||||
To include it for use in your project, install it via composer:
|
||||
|
||||
```
|
||||
composer require zbateson/mail-mime-parser
|
||||
```
|
||||
|
||||
## Sponsors
|
||||
|
||||
[](https://secumailer.com)
|
||||
|
||||
A huge thank you to [all my sponsors](https://github.com/sponsors/zbateson). <3
|
||||
|
||||
If this project's helped you, please consider [sponsoring me](https://github.com/sponsors/zbateson).
|
||||
|
||||
## Php 7 Support Dropped
|
||||
|
||||
As of mail-mime-parser 3.0, support for php 7 has been dropped.
|
||||
|
||||
## New in 3.0
|
||||
|
||||
Most changes in 3.0 are 'backend' changes, for example switching to PHP-DI for dependency injection, and basic usage should not be affected.
|
||||
|
||||
The header class method 'getAllParts' includes comment parts in 3.0.
|
||||
|
||||
Error, validation, and logging support has been added.
|
||||
|
||||
For a more complete list of changes, please visit the [3.0 Upgrade Guide](https://mail-mime-parser.org/upgrade-3.0) and the [Usage Guide](https://mail-mime-parser.org/).
|
||||
|
||||
## Requirements
|
||||
|
||||
MailMimeParser requires PHP 8.0 or newer. Tested on PHP 8.0, 8.1, 8.2, 8.3 and 8.4.
|
||||
|
||||
## Usage
|
||||
|
||||
```php
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
use ZBateson\MailMimeParser\Message;
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
|
||||
// use an instance of MailMimeParser as a class dependency
|
||||
$mailParser = new MailMimeParser();
|
||||
|
||||
// parse() accepts a string, resource or Psr7 StreamInterface
|
||||
// pass `true` as the second argument to attach the passed $handle and close
|
||||
// it when the returned IMessage is destroyed.
|
||||
$handle = fopen('file.mime', 'r');
|
||||
$message = $mailParser->parse($handle, false); // returns `IMessage`
|
||||
|
||||
// OR: use this procedurally (Message::from also accepts a string,
|
||||
// resource or Psr7 StreamInterface
|
||||
// true or false as second parameter doesn't matter if passing a string.
|
||||
$string = "Content-Type: text/plain\r\nSubject: Test\r\n\r\nMessage";
|
||||
$message = Message::from($string, false);
|
||||
|
||||
echo $message->getHeaderValue(HeaderConsts::FROM); // user@example.com
|
||||
echo $message
|
||||
->getHeader(HeaderConsts::FROM) // AddressHeader
|
||||
->getPersonName(); // Person Name
|
||||
echo $message->getSubject(); // The email's subject
|
||||
echo $message
|
||||
->getHeader(HeaderConsts::TO) // also AddressHeader
|
||||
->getAddresses()[0] // AddressPart
|
||||
->getPersonName(); // Person Name
|
||||
echo $message
|
||||
->getHeader(HeaderConsts::CC) // also AddressHeader
|
||||
->getAddresses()[0] // AddressPart
|
||||
->getEmail(); // user@example.com
|
||||
|
||||
echo $message->getTextContent(); // or getHtmlContent()
|
||||
|
||||
echo $message->getHeader('X-Foo'); // for custom or undocumented headers
|
||||
|
||||
$att = $message->getAttachmentPart(0); // first attachment
|
||||
echo $att->getHeaderValue(HeaderConsts::CONTENT_TYPE); // e.g. "text/plain"
|
||||
echo $att->getHeaderParameter( // value of "charset" part
|
||||
HeaderConsts::CONTENT_TYPE,
|
||||
'charset'
|
||||
);
|
||||
echo $att->getContent(); // get the attached file's contents
|
||||
$stream = $att->getContentStream(); // the file is decoded automatically
|
||||
$dest = \GuzzleHttp\Psr7\stream_for(
|
||||
fopen('my-file.ext')
|
||||
);
|
||||
\GuzzleHttp\Psr7\copy_to_stream(
|
||||
$stream, $dest
|
||||
);
|
||||
// OR: more simply if saving or copying to another stream
|
||||
$att->saveContent('my-file.ext'); // writes to my-file.ext
|
||||
$att->saveContent($stream); // copies to the stream
|
||||
|
||||
// close only when $message is no longer being used.
|
||||
fclose($handle);
|
||||
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Usage Guide](https://mail-mime-parser.org/)
|
||||
* [API Reference](https://mail-mime-parser.org/api/3.0)
|
||||
|
||||
## Upgrade guides
|
||||
|
||||
* [1.x Upgrade Guide](https://mail-mime-parser.org/upgrade-1.0)
|
||||
* [2.x Upgrade Guide](https://mail-mime-parser.org/upgrade-2.0)
|
||||
* [3.x Upgrade Guide](https://mail-mime-parser.org/upgrade-3.0)
|
||||
|
||||
## License
|
||||
|
||||
BSD licensed - please see [license agreement](https://github.com/zbateson/mail-mime-parser/blob/master/LICENSE).
|
||||
45
plugins/vendor/zbateson/mail-mime-parser/composer.json
vendored
Normal file
45
plugins/vendor/zbateson/mail-mime-parser/composer.json
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "zbateson/mail-mime-parser",
|
||||
"description": "MIME email message parser",
|
||||
"keywords": ["mail", "mime", "parser", "email", "php-imap", "mailparse", "mimeparse", "MimeMailParser"],
|
||||
"homepage": "https://mail-mime-parser.org",
|
||||
"license": "BSD-2-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Zaahid Bateson"
|
||||
},
|
||||
{
|
||||
"name": "Contributors",
|
||||
"homepage": "https://github.com/zbateson/mail-mime-parser/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/zbateson/mail-mime-parser/issues",
|
||||
"source": "https://github.com/zbateson/mail-mime-parser",
|
||||
"docs": "https://mail-mime-parser.org/#usage-guide"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"guzzlehttp/psr7": "^2.5",
|
||||
"zbateson/mb-wrapper": "^2.0",
|
||||
"zbateson/stream-decorators": "^2.1",
|
||||
"php-di/php-di": "^6.0|^7.0",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"friendsofphp/php-cs-fixer": "*",
|
||||
"phpstan/phpstan": "*",
|
||||
"monolog/monolog": "^2|^3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best support/performance",
|
||||
"ext-iconv": "For best support/performance"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {"ZBateson\\MailMimeParser\\": "src/"}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {"ZBateson\\MailMimeParser\\": "tests/MailMimeParser"}
|
||||
}
|
||||
}
|
||||
13
plugins/vendor/zbateson/mail-mime-parser/phpstan.neon
vendored
Normal file
13
plugins/vendor/zbateson/mail-mime-parser/phpstan.neon
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
parameters:
|
||||
level: 6
|
||||
errorFormat: raw
|
||||
editorUrl: '%%file%% %%line%% %%column%%: %%error%%'
|
||||
paths:
|
||||
- src
|
||||
bootstrapFiles:
|
||||
- PHPStanConstants.php
|
||||
ignoreErrors:
|
||||
-
|
||||
message: '#Call to an undefined method ZBateson\\MailMimeParser#'
|
||||
paths:
|
||||
- src/*
|
||||
123
plugins/vendor/zbateson/mail-mime-parser/src/Error.php
vendored
Normal file
123
plugins/vendor/zbateson/mail-mime-parser/src/Error.php
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Log\LogLevel;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Holds information about an error or notice that happened on a specific
|
||||
* object.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class Error
|
||||
{
|
||||
/**
|
||||
* @var string The error message.
|
||||
*/
|
||||
protected string $message;
|
||||
|
||||
/**
|
||||
* @var string The PSR log level for this error.
|
||||
*/
|
||||
protected string $psrLevel;
|
||||
|
||||
/**
|
||||
* @var ErrorBag The object the error/notice occurred on.
|
||||
*/
|
||||
protected ErrorBag $object;
|
||||
|
||||
/**
|
||||
* @var ?Throwable An Exception object if one happened, or null if not
|
||||
*/
|
||||
protected ?Throwable $exception;
|
||||
|
||||
/**
|
||||
* @var array<string, int>
|
||||
*/
|
||||
private array $levelMap = [
|
||||
LogLevel::EMERGENCY => 0,
|
||||
LogLevel::ALERT => 1,
|
||||
LogLevel::CRITICAL => 2,
|
||||
LogLevel::ERROR => 3,
|
||||
LogLevel::WARNING => 4,
|
||||
LogLevel::NOTICE => 5,
|
||||
LogLevel::INFO => 6,
|
||||
LogLevel::DEBUG => 7,
|
||||
];
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws InvalidArgumentException if the passed $psrLogLevelAsErrorLevel
|
||||
* is not a known PSR log level (see \Psr\Log\LogLevel)
|
||||
*/
|
||||
public function __construct(string $message, string $psrLogLevelAsErrorLevel, ErrorBag $object, ?Throwable $exception = null)
|
||||
{
|
||||
if (!isset($this->levelMap[$psrLogLevelAsErrorLevel])) {
|
||||
throw new InvalidArgumentException($psrLogLevelAsErrorLevel . ' is not a known PSR Log Level');
|
||||
}
|
||||
$this->message = $message;
|
||||
$this->psrLevel = $psrLogLevelAsErrorLevel;
|
||||
$this->object = $object;
|
||||
$this->exception = $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error message.
|
||||
*/
|
||||
public function getMessage() : string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PSR string log level for this error message.
|
||||
*/
|
||||
public function getPsrLevel() : string
|
||||
{
|
||||
return $this->psrLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class type the error occurred on.
|
||||
*/
|
||||
public function getClass() : string
|
||||
{
|
||||
return \get_class($this->object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object the error occurred on.
|
||||
*/
|
||||
public function getObject() : ErrorBag
|
||||
{
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exception that occurred, if any, or null.
|
||||
*/
|
||||
public function getException() : ?Throwable
|
||||
{
|
||||
return $this->exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the PSR log level for this error is equal to or greater
|
||||
* than the one passed, e.g. passing LogLevel::ERROR would return true for
|
||||
* LogLevel::ERROR and LogLevel::CRITICAL, ALERT and EMERGENCY.
|
||||
*/
|
||||
public function isPsrLevelGreaterOrEqualTo(string $minLevel) : bool
|
||||
{
|
||||
$minIntLevel = $this->levelMap[$minLevel] ?? 1000;
|
||||
$thisLevel = $this->levelMap[$this->psrLevel];
|
||||
return ($minIntLevel >= $thisLevel);
|
||||
}
|
||||
}
|
||||
124
plugins/vendor/zbateson/mail-mime-parser/src/ErrorBag.php
vendored
Normal file
124
plugins/vendor/zbateson/mail-mime-parser/src/ErrorBag.php
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Provides a top-level abstract implementation of IErrorBag.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class ErrorBag implements IErrorBag
|
||||
{
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
/**
|
||||
* @var Error[] array of Error objects belonging to this object.
|
||||
*/
|
||||
private array $errors = [];
|
||||
|
||||
/**
|
||||
* @var bool true once the object has been validated.
|
||||
*/
|
||||
private bool $validated = false;
|
||||
|
||||
public function __construct(LoggerInterface $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class name. Override to identify objects in logs.
|
||||
*
|
||||
*/
|
||||
public function getErrorLoggingContextName() : string
|
||||
{
|
||||
return static::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any children ErrorBag objects.
|
||||
*
|
||||
* @return IErrorBag[]
|
||||
*/
|
||||
abstract protected function getErrorBagChildren() : array;
|
||||
|
||||
/**
|
||||
* Perform any extra validation and call 'addError'.
|
||||
*
|
||||
* getErrors and getAllErrors call validate() if their $validate parameter
|
||||
* is true. validate() is only called once on an object with getErrors
|
||||
* getAllErrors.
|
||||
*/
|
||||
protected function validate() : void
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public function addError(string $message, string $psrLogLevel, ?Throwable $exception = null) : static
|
||||
{
|
||||
$error = new Error($message, $psrLogLevel, $this, $exception);
|
||||
$this->errors[] = $error;
|
||||
$this->logger->log(
|
||||
$psrLogLevel,
|
||||
'{contextName} {message} {exception}',
|
||||
[
|
||||
'contextName' => $this->getErrorLoggingContextName(),
|
||||
'message' => $message,
|
||||
'exception' => $exception ?? ''
|
||||
]
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getErrors(bool $validate = false, string $minPsrLevel = LogLevel::ERROR) : array
|
||||
{
|
||||
if ($validate && !$this->validated) {
|
||||
$this->validated = true;
|
||||
$this->validate();
|
||||
}
|
||||
return \array_values(\array_filter(
|
||||
$this->errors,
|
||||
function($e) use ($minPsrLevel) {
|
||||
return $e->isPsrLevelGreaterOrEqualTo($minPsrLevel);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
public function hasErrors(bool $validate = false, string $minPsrLevel = LogLevel::ERROR) : bool
|
||||
{
|
||||
return (\count($this->getErrors($validate, $minPsrLevel)) > 0);
|
||||
}
|
||||
|
||||
public function getAllErrors(bool $validate = false, string $minPsrLevel = LogLevel::ERROR) : array
|
||||
{
|
||||
$arr = \array_values(\array_map(
|
||||
function($e) use ($validate, $minPsrLevel) {
|
||||
return $e->getAllErrors($validate, $minPsrLevel);
|
||||
},
|
||||
$this->getErrorBagChildren()
|
||||
));
|
||||
return \array_merge($this->getErrors($validate, $minPsrLevel), ...$arr);
|
||||
}
|
||||
|
||||
public function hasAnyErrors(bool $validate = false, string $minPsrLevel = LogLevel::ERROR) : bool
|
||||
{
|
||||
if ($this->hasErrors($validate, $minPsrLevel)) {
|
||||
return true;
|
||||
}
|
||||
foreach ($this->getErrorBagChildren() as $ch) {
|
||||
if ($ch->hasAnyErrors($validate, $minPsrLevel)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
226
plugins/vendor/zbateson/mail-mime-parser/src/Header/AbstractHeader.php
vendored
Normal file
226
plugins/vendor/zbateson/mail-mime-parser/src/Header/AbstractHeader.php
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\IConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\CommentPart;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* Abstract base class representing a mime email's header.
|
||||
*
|
||||
* The base class sets up the header's consumer for parsing, sets the name of
|
||||
* the header, and calls the consumer to parse the header's value.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class AbstractHeader extends ErrorBag implements IHeader
|
||||
{
|
||||
/**
|
||||
* @var string the name of the header
|
||||
*/
|
||||
protected string $name;
|
||||
|
||||
/**
|
||||
* @var IHeaderPart[] all parts not including CommentParts.
|
||||
*/
|
||||
protected array $parts = [];
|
||||
|
||||
/**
|
||||
* @var IHeaderPart[] the header's parts (as returned from the consumer),
|
||||
* including commentParts
|
||||
*/
|
||||
protected array $allParts = [];
|
||||
|
||||
/**
|
||||
* @var string the raw value
|
||||
*/
|
||||
protected string $rawValue;
|
||||
|
||||
/**
|
||||
* @var string[] array of comments, initialized on demand in getComments()
|
||||
*/
|
||||
private ?array $comments = null;
|
||||
|
||||
/**
|
||||
* Assigns the header's name and raw value, then calls parseHeaderValue to
|
||||
* extract a parsed value.
|
||||
*
|
||||
* @param IConsumerService $consumerService For parsing the value.
|
||||
* @param string $name Name of the header.
|
||||
* @param string $value Value of the header.
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
IConsumerService $consumerService,
|
||||
string $name,
|
||||
string $value
|
||||
) {
|
||||
parent::__construct($logger);
|
||||
$this->name = $name;
|
||||
$this->rawValue = $value;
|
||||
$this->parseHeaderValue($consumerService, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters $this->allParts into the parts required by $this->parts
|
||||
* and assigns it.
|
||||
*
|
||||
* The AbstractHeader::filterAndAssignToParts method filters out CommentParts.
|
||||
*/
|
||||
protected function filterAndAssignToParts() : void
|
||||
{
|
||||
$this->parts = \array_values(\array_filter($this->allParts, function($p) {
|
||||
return !($p instanceof CommentPart);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the consumer and assigns the parsed parts to member variables.
|
||||
*
|
||||
* The default implementation assigns the returned value to $this->allParts
|
||||
* and filters out comments from it, assigning the filtered array to
|
||||
* $this->parts by calling filterAndAssignToParts.
|
||||
*/
|
||||
protected function parseHeaderValue(IConsumerService $consumer, string $value) : void
|
||||
{
|
||||
$this->allParts = $consumer($value);
|
||||
$this->filterAndAssignToParts();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IHeaderPart[]
|
||||
*/
|
||||
public function getParts() : array
|
||||
{
|
||||
return $this->parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IHeaderPart[]
|
||||
*/
|
||||
public function getAllParts() : array
|
||||
{
|
||||
return $this->allParts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getComments() : array
|
||||
{
|
||||
if ($this->comments === null) {
|
||||
$this->comments = \array_map(fn (IHeaderPart $c) => $c->getComment(), \array_merge(...\array_map(
|
||||
fn ($p) => ($p instanceof CommentPart) ? [$p] : $p->getComments(),
|
||||
$this->allParts
|
||||
)));
|
||||
}
|
||||
return $this->comments;
|
||||
}
|
||||
|
||||
public function getValue() : ?string
|
||||
{
|
||||
if (!empty($this->parts)) {
|
||||
return $this->parts[0]->getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRawValue() : string
|
||||
{
|
||||
return $this->rawValue;
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function __toString() : string
|
||||
{
|
||||
return "{$this->name}: {$this->rawValue}";
|
||||
}
|
||||
|
||||
public function getErrorLoggingContextName() : string
|
||||
{
|
||||
return 'Header::' . $this->getName();
|
||||
}
|
||||
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return $this->getAllParts();
|
||||
}
|
||||
|
||||
protected function validate() : void
|
||||
{
|
||||
if (\strlen(\trim($this->name)) === 0) {
|
||||
$this->addError('Header doesn\'t have a name', LogLevel::ERROR);
|
||||
}
|
||||
if (\strlen(\trim($this->rawValue)) === 0) {
|
||||
$this->addError('Header doesn\'t have a value', LogLevel::NOTICE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the passed $value parameter is null, and if so tries to parse
|
||||
* a header line from $nameOrLine splitting on first occurrence of a ':'
|
||||
* character.
|
||||
*
|
||||
* The returned array always contains two elements. The first being the
|
||||
* name (or blank if a ':' char wasn't found and $value is null), and the
|
||||
* second being the value.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected static function getHeaderPartsFrom(string $nameOrLine, ?string $value = null) : array
|
||||
{
|
||||
$namePart = $nameOrLine;
|
||||
$valuePart = $value;
|
||||
if ($value === null) {
|
||||
// full header line
|
||||
$parts = \explode(':', $nameOrLine, 2);
|
||||
$namePart = (\count($parts) > 1) ? $parts[0] : '';
|
||||
$valuePart = \trim((\count($parts) > 1) ? $parts[1] : $parts[0]);
|
||||
}
|
||||
return [$namePart, $valuePart];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the passed parameters into an IHeader object.
|
||||
*
|
||||
* The type of returned IHeader is determined by the name of the header.
|
||||
* See {@see HeaderFactory::newInstance} for more details.
|
||||
*
|
||||
* The required $nameOrLine parameter may contain either the name of a
|
||||
* header to parse, or a full header line, e.g. From: email@example.com. If
|
||||
* passing a full header line, the $value parameter must be set to null (the
|
||||
* default).
|
||||
*
|
||||
* Note that more specific types can be called on directly. For instance an
|
||||
* AddressHeader may be created by calling AddressHeader::from() which will
|
||||
* ignore the name of the header, and always return an AddressHeader, or by
|
||||
* calling `new AddressHeader('name', 'value')` directly.
|
||||
*
|
||||
* @param string $nameOrLine The header's name or full header line.
|
||||
* @param string|null $value The header's value, or null if passing a full
|
||||
* header line to parse.
|
||||
*/
|
||||
public static function from(string $nameOrLine, ?string $value = null) : IHeader
|
||||
{
|
||||
$parts = static::getHeaderPartsFrom($nameOrLine, $value);
|
||||
$container = MailMimeParser::getGlobalContainer();
|
||||
$hf = $container->get(HeaderFactory::class);
|
||||
if (self::class !== static::class) {
|
||||
return $hf->newInstanceOf($parts[0], $parts[1], static::class);
|
||||
}
|
||||
return $hf->newInstance($parts[0], $parts[1]);
|
||||
}
|
||||
}
|
||||
138
plugins/vendor/zbateson/mail-mime-parser/src/Header/AddressHeader.php
vendored
Normal file
138
plugins/vendor/zbateson/mail-mime-parser/src/Header/AddressHeader.php
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\AddressBaseConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\AddressGroupPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\AddressPart;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* A header containing one or more email addresses and/or groups of addresses.
|
||||
*
|
||||
* An address is separated by a comma, and each group separated by a semi-colon.
|
||||
* The AddressHeader provides a complete list of all addresses referenced in a
|
||||
* header including any addresses in groups, in addition to being able to access
|
||||
* the groups separately if needed.
|
||||
*
|
||||
* For full specifications, see {@link https://www.ietf.org/rfc/rfc2822.txt}
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class AddressHeader extends AbstractHeader
|
||||
{
|
||||
/**
|
||||
* @var AddressPart[] array of addresses, included all addresses contained
|
||||
* in groups.
|
||||
*/
|
||||
protected array $addresses = [];
|
||||
|
||||
/**
|
||||
* @var AddressGroupPart[] array of address groups (lists).
|
||||
*/
|
||||
protected array $groups = [];
|
||||
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $value,
|
||||
?LoggerInterface $logger = null,
|
||||
?AddressBaseConsumerService $consumerService = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$consumerService ?? $di->get(AddressBaseConsumerService::class),
|
||||
$name,
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters $this->allParts into the parts required by $this->parts
|
||||
* and assignes it.
|
||||
*
|
||||
* The AbstractHeader::filterAndAssignToParts method filters out CommentParts.
|
||||
*/
|
||||
protected function filterAndAssignToParts() : void
|
||||
{
|
||||
parent::filterAndAssignToParts();
|
||||
foreach ($this->parts as $part) {
|
||||
if ($part instanceof AddressPart) {
|
||||
$this->addresses[] = $part;
|
||||
} elseif ($part instanceof AddressGroupPart) {
|
||||
$this->addresses = \array_merge($this->addresses, $part->getAddresses());
|
||||
$this->groups[] = $part;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all address parts in the header including any addresses that are
|
||||
* in groups (lists).
|
||||
*
|
||||
* @return AddressPart[] The addresses.
|
||||
*/
|
||||
public function getAddresses() : array
|
||||
{
|
||||
return $this->addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all group parts (lists) in the header.
|
||||
*
|
||||
* @return AddressGroupPart[]
|
||||
*/
|
||||
public function getGroups() : array
|
||||
{
|
||||
return $this->groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an address exists with the passed email address.
|
||||
*
|
||||
* Comparison is done case insensitively.
|
||||
*
|
||||
*/
|
||||
public function hasAddress(string $email) : bool
|
||||
{
|
||||
foreach ($this->addresses as $addr) {
|
||||
if (\strcasecmp($addr->getEmail(), $email) === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first email address in the header.
|
||||
*
|
||||
* @return ?string The email address
|
||||
*/
|
||||
public function getEmail() : ?string
|
||||
{
|
||||
if (!empty($this->addresses)) {
|
||||
return $this->addresses[0]->getEmail();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name associated with the first email address to complement
|
||||
* getEmail() if one is set, or null if not.
|
||||
*
|
||||
* @return string|null The person name.
|
||||
*/
|
||||
public function getPersonName() : ?string
|
||||
{
|
||||
if (!empty($this->addresses)) {
|
||||
return $this->addresses[0]->getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
338
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AbstractConsumerService.php
vendored
Normal file
338
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AbstractConsumerService.php
vendored
Normal file
@@ -0,0 +1,338 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use ArrayIterator;
|
||||
use Iterator;
|
||||
use NoRewindIterator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeToken;
|
||||
|
||||
/**
|
||||
* Abstract base class for all header token consumers.
|
||||
*
|
||||
* Defines the base parser that loops over tokens, consuming them and creating
|
||||
* header parts.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class AbstractConsumerService implements IConsumerService
|
||||
{
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
/**
|
||||
* @var HeaderPartFactory used to construct IHeaderPart objects
|
||||
*/
|
||||
protected HeaderPartFactory $partFactory;
|
||||
|
||||
/**
|
||||
* @var AbstractConsumerService[] array of sub-consumers used by this
|
||||
* consumer if any, or an empty array if none exist.
|
||||
*/
|
||||
protected array $subConsumers = [];
|
||||
|
||||
/**
|
||||
* @var ?string the generated token split pattern on first run, so it doesn't
|
||||
* need to be regenerated every time.
|
||||
*/
|
||||
private ?string $tokenSplitPattern = null;
|
||||
|
||||
/**
|
||||
* @param AbstractConsumerService[] $subConsumers
|
||||
*/
|
||||
public function __construct(LoggerInterface $logger, HeaderPartFactory $partFactory, array $subConsumers = [])
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->partFactory = $partFactory;
|
||||
$this->subConsumers = $subConsumers;
|
||||
}
|
||||
|
||||
public function __invoke(string $value) : array
|
||||
{
|
||||
$this->logger->debug('Starting {class} for "{value}"', ['class' => static::class, 'value' => $value]);
|
||||
if ($value !== '') {
|
||||
$parts = $this->parseRawValue($value);
|
||||
$this->logger->debug(
|
||||
'Ending {class} for "{value}": parsed into {cnt} header part objects',
|
||||
['class' => static::class, 'value' => $value, 'cnt' => \count($parts)]
|
||||
);
|
||||
return $parts;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this consumer and all unique sub consumers.
|
||||
*
|
||||
* Loops into the sub-consumers (and their sub-consumers, etc...) finding
|
||||
* all unique consumers, and returns them in an array.
|
||||
*
|
||||
* @return AbstractConsumerService[] Array of unique consumers.
|
||||
*/
|
||||
protected function getAllConsumers() : array
|
||||
{
|
||||
$found = [$this];
|
||||
do {
|
||||
$current = \current($found);
|
||||
$subConsumers = $current->subConsumers;
|
||||
foreach ($subConsumers as $consumer) {
|
||||
if (!\in_array($consumer, $found)) {
|
||||
$found[] = $consumer;
|
||||
}
|
||||
}
|
||||
} while (\next($found) !== false);
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the raw header value into header parts.
|
||||
*
|
||||
* Calls splitTokens to split the value into token part strings, then calls
|
||||
* parseParts to parse the returned array.
|
||||
*
|
||||
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[] the array of parsed
|
||||
* parts
|
||||
*/
|
||||
private function parseRawValue(string $value) : array
|
||||
{
|
||||
$tokens = $this->splitRawValue($value);
|
||||
return $this->parseTokensIntoParts(new NoRewindIterator(new ArrayIterator($tokens)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of regular expression separators specific to this
|
||||
* consumer.
|
||||
*
|
||||
* The returned patterns are used to split the header value into tokens for
|
||||
* the consumer to parse into parts.
|
||||
*
|
||||
* Each array element makes part of a generated regular expression that is
|
||||
* used in a call to preg_split(). RegEx patterns can be used, and care
|
||||
* should be taken to escape special characters.
|
||||
*
|
||||
* @return string[] Array of regex patterns.
|
||||
*/
|
||||
abstract protected function getTokenSeparators() : array;
|
||||
|
||||
/**
|
||||
* Returns a list of regular expression markers for this consumer and all
|
||||
* sub-consumers by calling getTokenSeparators().
|
||||
*
|
||||
* @return string[] Array of regular expression markers.
|
||||
*/
|
||||
protected function getAllTokenSeparators() : array
|
||||
{
|
||||
$markers = $this->getTokenSeparators();
|
||||
$subConsumers = $this->getAllConsumers();
|
||||
foreach ($subConsumers as $consumer) {
|
||||
$markers = \array_merge($consumer->getTokenSeparators(), $markers);
|
||||
}
|
||||
return \array_unique($markers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a regex pattern used to split the input header string.
|
||||
*
|
||||
* The default implementation calls
|
||||
* {@see AbstractConsumerService::getAllTokenSeparators()} and implodes the
|
||||
* returned array with the regex OR '|' character as its glue.
|
||||
*
|
||||
* @return string the regex pattern
|
||||
*/
|
||||
protected function getTokenSplitPattern() : string
|
||||
{
|
||||
$sChars = \implode('|', $this->getAllTokenSeparators());
|
||||
$mimePartPattern = MimeToken::MIME_PART_PATTERN;
|
||||
return '~(' . $mimePartPattern . '|\\\\\r\n|\\\\.|' . $sChars . ')~ms';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of split tokens from the input string.
|
||||
*
|
||||
* The method calls preg_split using
|
||||
* {@see AbstractConsumerService::getTokenSplitPattern()}. The split array
|
||||
* will not contain any empty parts and will contain the markers.
|
||||
*
|
||||
* @param string $rawValue the raw string
|
||||
* @return string[] the array of tokens
|
||||
*/
|
||||
protected function splitRawValue($rawValue) : array
|
||||
{
|
||||
if ($this->tokenSplitPattern === null) {
|
||||
$this->tokenSplitPattern = $this->getTokenSplitPattern();
|
||||
$this->logger->debug(
|
||||
'Configuring {class} with token split pattern: {pattern}',
|
||||
['class' => static::class, 'pattern' => $this->tokenSplitPattern]
|
||||
);
|
||||
}
|
||||
return \preg_split(
|
||||
$this->tokenSplitPattern,
|
||||
$rawValue,
|
||||
-1,
|
||||
PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed string token marks the beginning marker for
|
||||
* the current consumer.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*/
|
||||
abstract protected function isStartToken(string $token) : bool;
|
||||
|
||||
/**
|
||||
* Returns true if the passed string token marks the end marker for the
|
||||
* current consumer.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*/
|
||||
abstract protected function isEndToken(string $token) : bool;
|
||||
|
||||
/**
|
||||
* Constructs and returns an IHeaderPart for the passed string token.
|
||||
*
|
||||
* If the token should be ignored, the function must return null.
|
||||
*
|
||||
* The default created part uses the instance's partFactory->newInstance
|
||||
* method.
|
||||
*
|
||||
* @param string $token the token
|
||||
* @param bool $isLiteral set to true if the token represents a literal -
|
||||
* e.g. an escaped token
|
||||
* @return ?IHeaderPart The constructed header part or null if the token
|
||||
* should be ignored.
|
||||
*/
|
||||
protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
|
||||
{
|
||||
if ($isLiteral) {
|
||||
return $this->partFactory->newToken($token, true);
|
||||
}
|
||||
// can be overridden with custom PartFactory
|
||||
return $this->partFactory->newInstance($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through this consumer's sub-consumers checking if the current
|
||||
* token triggers a sub-consumer's start token and passes control onto that
|
||||
* sub-consumer's parseTokenIntoParts().
|
||||
*
|
||||
* If no sub-consumer is responsible for the current token, calls
|
||||
* {@see AbstractConsumerService::getPartForToken()} and returns it in an
|
||||
* array.
|
||||
*
|
||||
* @param Iterator<string> $tokens
|
||||
* @return IHeaderPart[]
|
||||
*/
|
||||
protected function getConsumerTokenParts(Iterator $tokens) : array
|
||||
{
|
||||
$token = $tokens->current();
|
||||
$subConsumers = $this->subConsumers;
|
||||
foreach ($subConsumers as $consumer) {
|
||||
if ($consumer->isStartToken($token)) {
|
||||
$this->logger->debug(
|
||||
'Token: "{value}" in {class} starting sub-consumer {consumer}',
|
||||
['value' => $token, 'class' => static::class, 'consumer' => \get_class($consumer)]
|
||||
);
|
||||
$this->advanceToNextToken($tokens, true);
|
||||
return $consumer->parseTokensIntoParts($tokens);
|
||||
}
|
||||
}
|
||||
$part = $this->getPartForToken($token, false);
|
||||
return ($part !== null) ? [$part] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of IHeaderPart for the current token on the iterator.
|
||||
*
|
||||
* If the current token is a start token from a sub-consumer, the sub-
|
||||
* consumer's {@see AbstractConsumerService::parseTokensIntoParts()} method
|
||||
* is called.
|
||||
*
|
||||
* @param Iterator<string> $tokens The token iterator.
|
||||
* @return IHeaderPart[]
|
||||
*/
|
||||
protected function getTokenParts(Iterator $tokens) : array
|
||||
{
|
||||
$token = $tokens->current();
|
||||
if ($token === "\\\r\n" || (\strlen($token) === 2 && $token[0] === '\\')) {
|
||||
$part = $this->getPartForToken(\substr($token, 1), true);
|
||||
return ($part !== null) ? [$part] : [];
|
||||
}
|
||||
return $this->getConsumerTokenParts($tokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the iterator should be advanced to the next token after
|
||||
* reading tokens or finding a start token.
|
||||
*
|
||||
* The default implementation will advance for a start token, but not
|
||||
* advance on the end token of the current consumer, allowing the end token
|
||||
* to be passed up to a higher-level consumer.
|
||||
*
|
||||
* @param Iterator $tokens The token iterator.
|
||||
* @param bool $isStartToken true for the start token.
|
||||
*/
|
||||
protected function advanceToNextToken(Iterator $tokens, bool $isStartToken) : static
|
||||
{
|
||||
$checkEndToken = (!$isStartToken && $tokens->valid());
|
||||
$isEndToken = ($checkEndToken && $this->isEndToken($tokens->current()));
|
||||
if (($isStartToken) || ($checkEndToken && !$isEndToken)) {
|
||||
$tokens->next();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the passed token Iterator and returns an array of parsed
|
||||
* IHeaderPart objects.
|
||||
*
|
||||
* The method checks each token to see if the token matches a sub-consumer's
|
||||
* start token, or if it matches the current consumer's end token to stop
|
||||
* processing.
|
||||
*
|
||||
* If a sub-consumer's start token is matched, the sub-consumer is invoked
|
||||
* and its returned parts are merged to the current consumer's header parts.
|
||||
*
|
||||
* After all tokens are read and an array of Header\Parts are constructed,
|
||||
* the array is passed to {@see AbstractConsumerService::processParts} for
|
||||
* any final processing if there are any parts.
|
||||
*
|
||||
* @param Iterator<string> $tokens An iterator over a string of tokens
|
||||
* @return IHeaderPart[] An array of parsed parts
|
||||
*/
|
||||
protected function parseTokensIntoParts(Iterator $tokens) : array
|
||||
{
|
||||
$parts = [];
|
||||
while ($tokens->valid() && !$this->isEndToken($tokens->current())) {
|
||||
$this->logger->debug('Parsing token: {token} in class: {consumer}', ['token' => $tokens->current(), 'consumer' => static::class]);
|
||||
$parts = \array_merge($parts, $this->getTokenParts($tokens));
|
||||
$this->advanceToNextToken($tokens, false);
|
||||
}
|
||||
return (empty($parts)) ? [] : $this->processParts($parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs any final processing on the array of parsed parts before
|
||||
* returning it to the consumer client. The passed $parts array is
|
||||
* guaranteed to not be empty.
|
||||
*
|
||||
* The default implementation simply returns the passed array after
|
||||
* filtering out null/empty parts.
|
||||
*
|
||||
* @param IHeaderPart[] $parts The parsed parts.
|
||||
* @return IHeaderPart[] Array of resulting final parts.
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
$this->logger->debug('Processing parts array {parts} in {consumer}', ['parts' => $parts, 'consumer' => static::class]);
|
||||
return $parts;
|
||||
}
|
||||
}
|
||||
69
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AbstractGenericConsumerService.php
vendored
Normal file
69
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AbstractGenericConsumerService.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
/**
|
||||
* A minimal implementation of AbstractConsumerService splitting tokens by
|
||||
* whitespace.
|
||||
*
|
||||
* Although the class doesn't have any abstract methods, it's defined as
|
||||
* abstract because it doesn't define specific sub-consumers as constructor
|
||||
* dependencies, and so is defined as abstract to avoid its direct use (use
|
||||
* the concrete GenericConsumerService or GenericConsumerMimeLiteralPartService
|
||||
* classes instead).
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class AbstractGenericConsumerService extends AbstractConsumerService
|
||||
{
|
||||
/**
|
||||
* Returns the regex '\s+' (whitespace) pattern matcher as a token marker so
|
||||
* the header value is split along whitespace characters.
|
||||
*
|
||||
* @return string[] an array of regex pattern matchers
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return ['\s+'];
|
||||
}
|
||||
|
||||
/**
|
||||
* AbstractGenericConsumerService doesn't have start/end tokens, and so
|
||||
* always returns false.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* AbstractGenericConsumerService doesn't have start/end tokens, and so
|
||||
* always returns false.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to combine all part values into a single string and return it
|
||||
* as an array with a single element.
|
||||
*
|
||||
* The returned IHeaderPart array consists of a single ContainerPart created
|
||||
* out of all passed IHeaderParts.
|
||||
*
|
||||
* @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts
|
||||
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[]
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
return [$this->partFactory->newContainerPart($parts)];
|
||||
}
|
||||
}
|
||||
104
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AddressBaseConsumerService.php
vendored
Normal file
104
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AddressBaseConsumerService.php
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Iterator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
|
||||
|
||||
/**
|
||||
* Serves as a base-consumer for recipient/sender email address headers (like
|
||||
* From and To).
|
||||
*
|
||||
* AddressBaseConsumerService passes on token processing to its sub-consumer, an
|
||||
* AddressConsumerService, and collects Part\AddressPart objects processed and
|
||||
* returned by AddressConsumerService.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class AddressBaseConsumerService extends AbstractConsumerService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
HeaderPartFactory $partFactory,
|
||||
AddressConsumerService $addressConsumerService
|
||||
) {
|
||||
parent::__construct($logger, $partFactory, [$addressConsumerService]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty array.
|
||||
*
|
||||
* @return string[] an array of regex pattern matchers
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables advancing for start tokens.
|
||||
*
|
||||
* The start token for AddressBaseConsumerService is part of an
|
||||
* {@see AddressPart} (or a sub-consumer) and so must be passed on.
|
||||
*/
|
||||
protected function advanceToNextToken(Iterator $tokens, bool $isStartToken) : static
|
||||
{
|
||||
if ($isStartToken) {
|
||||
return $this;
|
||||
}
|
||||
parent::advanceToNextToken($tokens, $isStartToken);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* AddressBaseConsumerService doesn't have start/end tokens, and so always
|
||||
* returns false.
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* AddressBaseConsumerService doesn't have start/end tokens, and so always
|
||||
* returns false.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return false
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden so tokens aren't handled at this level, and instead are passed
|
||||
* on to AddressConsumerService.
|
||||
*
|
||||
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[]|array
|
||||
*/
|
||||
protected function getTokenParts(Iterator $tokens) : array
|
||||
{
|
||||
return $this->getConsumerTokenParts($tokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* Never reached by AddressBaseConsumerService. Overridden to satisfy
|
||||
* AbstractConsumerService.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
139
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AddressConsumerService.php
vendored
Normal file
139
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AddressConsumerService.php
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Part\AddressGroupPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\AddressPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeToken;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* Parses a single part of an address header.
|
||||
*
|
||||
* Represents a single part of a list of addresses. A part could be one email
|
||||
* address, or one 'group' containing multiple addresses. The consumer ends on
|
||||
* finding either a comma token, representing a separation between addresses, or
|
||||
* a semi-colon token representing the end of a group.
|
||||
*
|
||||
* A single email address may consist of just an email, or a name and an email
|
||||
* address. Both of these are valid examples of a From header:
|
||||
* - From: jonsnow@winterfell.com
|
||||
* - From: Jon Snow <jonsnow@winterfell.com>
|
||||
*
|
||||
* Groups must be named, for example:
|
||||
* - To: Winterfell: jonsnow@winterfell.com, Arya Stark <arya@winterfell.com>;
|
||||
*
|
||||
* Addresses may contain quoted parts and comments, and names may be mime-header
|
||||
* encoded.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class AddressConsumerService extends AbstractConsumerService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MimeTokenPartFactory $partFactory,
|
||||
AddressGroupConsumerService $addressGroupConsumerService,
|
||||
AddressEmailConsumerService $addressEmailConsumerService,
|
||||
CommentConsumerService $commentConsumerService,
|
||||
QuotedStringConsumerService $quotedStringConsumerService
|
||||
) {
|
||||
$addressGroupConsumerService->setAddressConsumerService($this);
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
[
|
||||
$addressGroupConsumerService,
|
||||
$addressEmailConsumerService,
|
||||
$commentConsumerService,
|
||||
$quotedStringConsumerService
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return patterns matching end tokens ("," and ";"), and
|
||||
* whitespace.
|
||||
*
|
||||
* @return string[] the patterns
|
||||
*/
|
||||
public function getTokenSeparators() : array
|
||||
{
|
||||
return [',', ';', '\s+'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true for commas and semi-colons.
|
||||
*
|
||||
* Although the semi-colon is not strictly the end token of an
|
||||
* AddressConsumerService, it could end a parent
|
||||
* {@see AddressGroupConsumerService}.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return ($token === ',' || $token === ';');
|
||||
}
|
||||
|
||||
/**
|
||||
* AddressConsumer is "greedy", so this always returns true.
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs final processing on parsed parts.
|
||||
*
|
||||
* AddressConsumerService's implementation looks for tokens representing the
|
||||
* beginning of an address part, to create a {@see AddressPart} out of a
|
||||
* name/address pair, or assign the name part to a parsed
|
||||
* {@see AddressGroupPart} returned from its AddressGroupConsumerService
|
||||
* sub-consumer.
|
||||
*
|
||||
* The returned array consists of a single element - either an
|
||||
* {@see AddressPart} or an {@see AddressGroupPart}.
|
||||
*
|
||||
* @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts
|
||||
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[]|array
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
$found = null;
|
||||
$revved = \array_reverse($parts, true);
|
||||
foreach ($revved as $key => $part) {
|
||||
if ($part instanceof AddressGroupPart || $part instanceof AddressPart) {
|
||||
$found = $part;
|
||||
// purposefully ignoring anything after
|
||||
\array_splice($parts, $key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found !== null) {
|
||||
if ($found instanceof AddressGroupPart) {
|
||||
return [$this->partFactory->newAddressGroupPart(
|
||||
$parts,
|
||||
[$found]
|
||||
)];
|
||||
}
|
||||
return [$this->partFactory->newAddress(
|
||||
$parts,
|
||||
[$found]
|
||||
)];
|
||||
}
|
||||
|
||||
return [
|
||||
$this->partFactory->newAddress(
|
||||
[],
|
||||
\array_map(fn ($p) => ($p instanceof MimeToken) ? $this->partFactory->newToken($p->getRawValue()) : $p, $parts)
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
78
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AddressEmailConsumerService.php
vendored
Normal file
78
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AddressEmailConsumerService.php
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
|
||||
|
||||
/**
|
||||
* Parses the Address portion of an email address header, for an address part
|
||||
* that contains both a name and an email address, e.g. "name" <email@tld.com>.
|
||||
*
|
||||
* The address portion found within the '<' and '>' chars may contain comments
|
||||
* and quoted portions.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class AddressEmailConsumerService extends AbstractConsumerService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
HeaderPartFactory $partFactory,
|
||||
CommentConsumerService $commentConsumerService,
|
||||
QuotedStringConsumerService $quotedStringConsumerService
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
[$commentConsumerService, $quotedStringConsumerService]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return patterns matching the beginning/end part of an
|
||||
* address in a name/address part ("<" and ">" chars).
|
||||
*
|
||||
* @return string[] the patterns
|
||||
*/
|
||||
public function getTokenSeparators() : array
|
||||
{
|
||||
return ['<', '>'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true for the '>' char.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return ($token === '>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true for the '<' char.
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return ($token === '<');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single {@see ZBateson\MailMimeParser\Header\Part\AddressPart}
|
||||
* with its 'email' portion set, so an {@see AddressConsumerService} can
|
||||
* identify it and create an
|
||||
* {@see ZBateson\MailMimeParser\Header\Part\AddressPart} Address with
|
||||
* both a name and email set.
|
||||
*
|
||||
* @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts
|
||||
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[]|array
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
return [$this->partFactory->newAddress([], $parts)];
|
||||
}
|
||||
}
|
||||
106
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AddressGroupConsumerService.php
vendored
Normal file
106
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/AddressGroupConsumerService.php
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Iterator;
|
||||
use ZBateson\MailMimeParser\Header\Part\AddressGroupPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
|
||||
|
||||
/**
|
||||
* Parses a single group of addresses (as a named-group part of an address
|
||||
* header).
|
||||
*
|
||||
* Finds addresses using its AddressConsumerService sub-consumer separated by
|
||||
* commas, and ends processing once a semi-colon is found.
|
||||
*
|
||||
* Prior to returning to its calling client, AddressGroupConsumerService
|
||||
* constructs a single Part\AddressGroupPart object filling it with all located
|
||||
* addresses, and returns it.
|
||||
*
|
||||
* The AddressGroupConsumerService extends AddressBaseConsumerService to define
|
||||
* start/end tokens, token separators, and construct a Part\AddressGroupPart to
|
||||
* return.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class AddressGroupConsumerService extends AddressBaseConsumerService
|
||||
{
|
||||
public function __construct(LoggerInterface $logger, HeaderPartFactory $partFactory)
|
||||
{
|
||||
AbstractConsumerService::__construct($logger, $partFactory, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Needs to be called in AddressConsumerService's constructor to avoid a
|
||||
* circular dependency.
|
||||
*
|
||||
*/
|
||||
public function setAddressConsumerService(AddressConsumerService $subConsumer) : void
|
||||
{
|
||||
$this->subConsumers = [$subConsumer];
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return patterns matching the beginning and end markers of a
|
||||
* group address: colon and semi-colon (":" and ";") characters.
|
||||
*
|
||||
* @return string[] the patterns
|
||||
*/
|
||||
public function getTokenSeparators() : array
|
||||
{
|
||||
return [':', ';'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed token is a semi-colon.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return ($token === ';');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed token is a colon.
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return ($token === ':');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to always call processParts even for an empty set of
|
||||
* addresses, since a group could be empty.
|
||||
*
|
||||
* @param Iterator $tokens
|
||||
* @return IHeaderPart[]
|
||||
*/
|
||||
protected function parseTokensIntoParts(Iterator $tokens) : array
|
||||
{
|
||||
$ret = parent::parseTokensIntoParts($tokens);
|
||||
if ($ret === []) {
|
||||
return $this->processParts([]);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs post-processing on parsed parts.
|
||||
*
|
||||
* Returns an array with a single
|
||||
* {@see AddressGroupPart} element with all email addresses from this and
|
||||
* any sub-groups.
|
||||
*
|
||||
* @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts
|
||||
* @return AddressGroupPart[]|array
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
return [$this->partFactory->newAddressGroupPart([], $parts)];
|
||||
}
|
||||
}
|
||||
113
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/CommentConsumerService.php
vendored
Normal file
113
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/CommentConsumerService.php
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Iterator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* Consumes all tokens within parentheses as comments.
|
||||
*
|
||||
* Parenthetical comments in mime-headers can be nested within one another. The
|
||||
* outer-level continues after an inner-comment ends. Additionally,
|
||||
* quoted-literals may exist with comments as well meaning a parenthesis inside
|
||||
* a quoted string would not begin or end a comment section.
|
||||
*
|
||||
* In order to satisfy these specifications, CommentConsumerService inherits
|
||||
* from GenericConsumerService which defines CommentConsumerService and
|
||||
* QuotedStringConsumerService as sub-consumers.
|
||||
*
|
||||
* Examples:
|
||||
* X-Mime-Header: Some value (comment)
|
||||
* X-Mime-Header: Some value (comment (nested comment) still in comment)
|
||||
* X-Mime-Header: Some value (comment "and part of original ) comment" -
|
||||
* still a comment)
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class CommentConsumerService extends GenericConsumerService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MimeTokenPartFactory $partFactory,
|
||||
QuotedStringConsumerService $quotedStringConsumerService
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
$this,
|
||||
$quotedStringConsumerService
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns patterns matching open and close parenthesis characters
|
||||
* as separators.
|
||||
*
|
||||
* @return string[] the patterns
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return \array_merge(parent::getTokenSeparators(), ['\(', '\)']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the token is an open parenthesis character, '('.
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return ($token === '(');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the token is a close parenthesis character, ')'.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return ($token === ')');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates and returns Part\Token objects.
|
||||
*
|
||||
* Tokens from this and sub-consumers are combined into a Part\CommentPart
|
||||
* in processParts.
|
||||
*/
|
||||
protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
|
||||
{
|
||||
return $this->partFactory->newInstance($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls $tokens->next() and returns.
|
||||
*
|
||||
* The default implementation checks if the current token is an end token,
|
||||
* and will not advance past it. Because a comment part of a header can be
|
||||
* nested, its implementation must advance past its own 'end' token.
|
||||
*/
|
||||
protected function advanceToNextToken(Iterator $tokens, bool $isStartToken) : static
|
||||
{
|
||||
$tokens->next();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post processing involves creating a single Part\CommentPart out of
|
||||
* generated parts from tokens. The Part\CommentPart is returned in an
|
||||
* array.
|
||||
*
|
||||
* @param IHeaderPart[] $parts
|
||||
* @return IHeaderPart[]
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
return [$this->partFactory->newCommentPart($parts)];
|
||||
}
|
||||
}
|
||||
45
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/DateConsumerService.php
vendored
Normal file
45
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/DateConsumerService.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
|
||||
/**
|
||||
* Parses a date header into a Part\DatePart taking care of comment and quoted
|
||||
* parts as necessary.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class DateConsumerService extends GenericConsumerService
|
||||
{
|
||||
/**
|
||||
* Returns a Part\LiteralPart for the current token
|
||||
*
|
||||
* @param string $token the token
|
||||
* @param bool $isLiteral set to true if the token represents a literal -
|
||||
* e.g. an escaped token
|
||||
*/
|
||||
protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
|
||||
{
|
||||
return $this->partFactory->newToken($token, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a single Part\DatePart of any parsed parts returning it in an
|
||||
* array with a single element.
|
||||
*
|
||||
* @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts The parsed
|
||||
* parts.
|
||||
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[] Array of resulting
|
||||
* final parts.
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
return [$this->partFactory->newDatePart($parts)];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* GenericConsumerMimeLiteralPartService uses a MimeTokenPartFactory instead
|
||||
* of a HeaderPartFactory.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class GenericConsumerMimeLiteralPartService extends GenericConsumerService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MimeTokenPartFactory $partFactory,
|
||||
CommentConsumerService $commentConsumerService,
|
||||
QuotedStringConsumerService $quotedStringConsumerService
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
$commentConsumerService,
|
||||
$quotedStringConsumerService
|
||||
);
|
||||
}
|
||||
}
|
||||
34
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/GenericConsumerService.php
vendored
Normal file
34
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/GenericConsumerService.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
|
||||
|
||||
/**
|
||||
* The base GenericConsumerService is a consumer with CommentConsumerService and
|
||||
* QuotedStringConsumerService as sub-consumers, and splitting tokens by
|
||||
* whitespace.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class GenericConsumerService extends AbstractGenericConsumerService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
HeaderPartFactory $partFactory,
|
||||
CommentConsumerService $commentConsumerService,
|
||||
QuotedStringConsumerService $quotedStringConsumerService
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
[$commentConsumerService, $quotedStringConsumerService]
|
||||
);
|
||||
}
|
||||
}
|
||||
26
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/IConsumerService.php
vendored
Normal file
26
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/IConsumerService.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
/**
|
||||
* Interface defining a consumer service class.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IConsumerService
|
||||
{
|
||||
/**
|
||||
* Invokes parsing of a header's value into header parts.
|
||||
*
|
||||
* @param string $value the raw header value
|
||||
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[] the array of parsed
|
||||
* parts
|
||||
*/
|
||||
public function __invoke(string $value) : array;
|
||||
}
|
||||
90
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/IdBaseConsumerService.php
vendored
Normal file
90
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/IdBaseConsumerService.php
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
|
||||
|
||||
/**
|
||||
* Serves as a base-consumer for ID headers (like Message-ID and Content-ID).
|
||||
*
|
||||
* IdBaseConsumerService handles invalidly-formatted IDs not within '<' and '>'
|
||||
* characters. Processing for validly-formatted IDs are passed on to its
|
||||
* sub-consumer, IdConsumer.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class IdBaseConsumerService extends AbstractConsumerService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
HeaderPartFactory $partFactory,
|
||||
CommentConsumerService $commentConsumerService,
|
||||
QuotedStringConsumerService $quotedStringConsumerService,
|
||||
IdConsumerService $idConsumerService
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
[
|
||||
$commentConsumerService,
|
||||
$quotedStringConsumerService,
|
||||
$idConsumerService
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns '\s+' as a whitespace separator.
|
||||
*
|
||||
* @return string[] an array of regex pattern matchers.
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return ['\s+'];
|
||||
}
|
||||
|
||||
/**
|
||||
* IdBaseConsumerService doesn't have start/end tokens, and so always
|
||||
* returns false.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* IdBaseConsumerService doesn't have start/end tokens, and so always
|
||||
* returns false.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null for whitespace, and
|
||||
* {@see ZBateson\MailMimeParser\Header\Part\Token} for anything else.
|
||||
*
|
||||
* @param string $token the token
|
||||
* @param bool $isLiteral set to true if the token represents a literal -
|
||||
* e.g. an escaped token
|
||||
* @return ?IHeaderPart The constructed header part or null if the token
|
||||
* should be ignored
|
||||
*/
|
||||
protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
|
||||
{
|
||||
if (\preg_match('/^\s+$/', $token)) {
|
||||
return null;
|
||||
}
|
||||
return $this->partFactory->newToken($token, true);
|
||||
}
|
||||
}
|
||||
57
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/IdConsumerService.php
vendored
Normal file
57
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/IdConsumerService.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
|
||||
/**
|
||||
* Parses a single ID from an ID header. Begins consuming on a '<' char, and
|
||||
* ends on a '>' char.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class IdConsumerService extends GenericConsumerService
|
||||
{
|
||||
/**
|
||||
* Overridden to return patterns matching the beginning part of an ID ('<'
|
||||
* and '>' chars).
|
||||
*
|
||||
* @return string[] the patterns
|
||||
*/
|
||||
public function getTokenSeparators() : array
|
||||
{
|
||||
return \array_merge(parent::getTokenSeparators(), ['<', '>']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true for '>'.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return ($token === '>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true for '<'.
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return ($token === '<');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null for whitespace, and Token for anything else.
|
||||
*/
|
||||
protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
|
||||
{
|
||||
if (\preg_match('/^\s+$/', $token)) {
|
||||
return null;
|
||||
}
|
||||
return $this->partFactory->newToken($token, true);
|
||||
}
|
||||
}
|
||||
96
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/ParameterConsumerService.php
vendored
Normal file
96
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/ParameterConsumerService.php
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Iterator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
|
||||
use ZBateson\MailMimeParser\Header\Part\ParameterPart;
|
||||
|
||||
/**
|
||||
* Reads headers separated into parameters consisting of an optional main value,
|
||||
* and subsequent name/value pairs - for example text/html; charset=utf-8.
|
||||
*
|
||||
* A ParameterConsumerService's parts are separated by a semi-colon. Its
|
||||
* name/value pairs are separated with an '=' character.
|
||||
*
|
||||
* Parts may be mime-encoded entities, or RFC-2231 split/encoded parts.
|
||||
* Additionally, a value can be quoted and comments may exist.
|
||||
*
|
||||
* Actual processing of parameters is done in ParameterNameValueConsumerService,
|
||||
* with ParameterConsumerService processing all collected parts into split
|
||||
* parameter parts as necessary.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ParameterConsumerService extends AbstractGenericConsumerService
|
||||
{
|
||||
use QuotedStringMimeLiteralPartTokenSplitPatternTrait;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
HeaderPartFactory $partFactory,
|
||||
ParameterNameValueConsumerService $parameterNameValueConsumerService,
|
||||
CommentConsumerService $commentConsumerService,
|
||||
QuotedStringConsumerService $quotedStringConsumerService
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
[$parameterNameValueConsumerService, $commentConsumerService, $quotedStringConsumerService]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables advancing for start tokens.
|
||||
*/
|
||||
protected function advanceToNextToken(Iterator $tokens, bool $isStartToken) : static
|
||||
{
|
||||
if ($isStartToken) {
|
||||
return $this;
|
||||
}
|
||||
parent::advanceToNextToken($tokens, $isStartToken);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post processing involves looking for split parameter parts with matching
|
||||
* names and combining them into a SplitParameterPart, and otherwise
|
||||
* returning ParameterParts from ParameterNameValueConsumer as-is.
|
||||
*
|
||||
* @param IHeaderPart[] $parts The parsed parts.
|
||||
* @return IHeaderPart[] Array of resulting final parts.
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
$factory = $this->partFactory;
|
||||
return \array_values(\array_map(
|
||||
function($partsArray) use ($factory) {
|
||||
if (\count($partsArray) > 1) {
|
||||
return $factory->newSplitParameterPart($partsArray);
|
||||
}
|
||||
return $partsArray[0];
|
||||
},
|
||||
\array_merge_recursive(...\array_map(
|
||||
function($p) {
|
||||
// if $p->getIndex is non-null, it's a split-parameter part
|
||||
// and an array of one element consisting of name => ParameterPart
|
||||
// is returned, which is then merged into name => array-of-parameter-parts
|
||||
// or ';' object_id . ';' for non-split parts with a value of a single
|
||||
// element array of [ParameterPart]
|
||||
if ($p instanceof ParameterPart && $p->getIndex() !== null) {
|
||||
return [\strtolower($p->getName()) => [$p]];
|
||||
}
|
||||
return [';' . \spl_object_id($p) . ';' => [$p]];
|
||||
},
|
||||
$parts
|
||||
))
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\ContainerPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* Parses an individual part of a parameter header.
|
||||
*
|
||||
* 'isStartToken' always returns true, so control is taken from
|
||||
* ParameterConsumerService always, and returned when a ';' is encountered (and
|
||||
* so processes a single part and returns it, then gets control back).0
|
||||
*
|
||||
* If an '=' is encountered, the ParameterValueConsumerService sub-consumer
|
||||
* takes control and parses the value of a parameter.
|
||||
*
|
||||
* If no '=' is encountered, it's assumed to be a single value element, which
|
||||
* should be the first part of a parameter header, e.g. 'text/html' in
|
||||
* Content-Type: text/html; charset=utf-8
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ParameterNameValueConsumerService extends AbstractGenericConsumerService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MimeTokenPartFactory $partFactory,
|
||||
ParameterValueConsumerService $parameterValueConsumerService,
|
||||
CommentConsumerService $commentConsumerService,
|
||||
QuotedStringConsumerService $quotedStringConsumerService
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
[$parameterValueConsumerService, $commentConsumerService, $quotedStringConsumerService]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns semi-colon as a token separator, in addition to parent token
|
||||
* separators.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return \array_merge(parent::getTokenSeparators(), [';']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns true to grab control from its parent
|
||||
* ParameterConsumerService.
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the token is a ';' char.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return ($token === ';');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates either a ContainerPart if an '=' wasn't encountered, indicating
|
||||
* this to be the main 'value' part of a header (or a malformed part of a
|
||||
* parameter header), or a ParameterPart if the last IHeaderPart in the
|
||||
* passed $parts array is already a ContainerPart (indicating it was parsed
|
||||
* in ParameterValueConsumerService.)
|
||||
*
|
||||
* @param IHeaderPart[] $parts The parsed parts.
|
||||
* @return IHeaderPart[] Array of resulting final parts.
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
$nameOnly = $parts;
|
||||
$valuePart = \array_pop($nameOnly);
|
||||
if (!($valuePart instanceof ContainerPart)) {
|
||||
return [$this->partFactory->newContainerPart($parts)];
|
||||
}
|
||||
return [$this->partFactory->newParameterPart(
|
||||
$nameOnly,
|
||||
$valuePart
|
||||
)];
|
||||
}
|
||||
}
|
||||
64
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/ParameterValueConsumerService.php
vendored
Normal file
64
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/ParameterValueConsumerService.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* Starts processing tokens after a '=' character is found, indicating the
|
||||
* 'value' portion of a name/value pair in a parameter header.
|
||||
*
|
||||
* The value portion will consist of all tokens, quoted parts, and comment parts
|
||||
* parsed up to a semi-colon token indicating control should be returned to the
|
||||
* parent ParameterNameValueConsumerService.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ParameterValueConsumerService extends GenericConsumerMimeLiteralPartService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MimeTokenPartFactory $partFactory,
|
||||
CommentConsumerService $commentConsumerService,
|
||||
QuotedStringMimeLiteralPartConsumerService $quotedStringConsumerService
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
$commentConsumerService,
|
||||
$quotedStringConsumerService
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns semi-colon and equals char as token separators.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return \array_merge(parent::getTokenSeparators(), ['=', ';']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the token is an '=' character.
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return ($token === '=');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the token is a ';' character.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return ($token === ';');
|
||||
}
|
||||
}
|
||||
79
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/QuotedStringConsumerService.php
vendored
Normal file
79
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/QuotedStringConsumerService.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
|
||||
/**
|
||||
* Represents a quoted part of a header value starting at a double quote, and
|
||||
* ending at the next double quote.
|
||||
*
|
||||
* A quoted-pair part in a header is a literal. There are no sub-consumers for
|
||||
* it and a Part\LiteralPart is returned.
|
||||
*
|
||||
* Newline characters (CR and LF) are stripped entirely from the quoted part.
|
||||
* This is based on the example at:
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc822#section-3.1.1
|
||||
*
|
||||
* And https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html in section 7.2.1
|
||||
* splitting the boundary.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class QuotedStringConsumerService extends AbstractConsumerService
|
||||
{
|
||||
/**
|
||||
* Returns true if the token is a double quote.
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return ($token === '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the token is a double quote.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return ($token === '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single regex pattern for a double quote.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return ['\"'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a LiteralPart and returns it.
|
||||
*/
|
||||
protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
|
||||
{
|
||||
return $this->partFactory->newToken($token, $isLiteral, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to combine all part values into a single string and return it
|
||||
* as an array with a single element.
|
||||
*
|
||||
* The returned IHeaderParts is an array containing a single
|
||||
* QuotedLiteralPart.
|
||||
*
|
||||
* @param IHeaderPart[] $parts
|
||||
* @return IHeaderPart[]
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
return [$this->partFactory->newQuotedLiteralPart($parts)];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeToken;
|
||||
|
||||
/**
|
||||
* Allows for mime-encoded parts inside a quoted part.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class QuotedStringMimeLiteralPartConsumerService extends QuotedStringConsumerService
|
||||
{
|
||||
/**
|
||||
* Constructs a LiteralPart and returns it.
|
||||
*
|
||||
* @param bool $isLiteral not used - everything in a quoted string is a
|
||||
* literal
|
||||
*/
|
||||
protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
|
||||
{
|
||||
if (!$isLiteral && \preg_match('/' . MimeToken::MIME_PART_PATTERN . '/', $token)) {
|
||||
return $this->partFactory->newMimeToken($token);
|
||||
}
|
||||
return $this->partFactory->newToken($token, $isLiteral);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeToken;
|
||||
|
||||
/**
|
||||
* Provides a getTokenSplitPattern for consumers that could have quoted parts
|
||||
* that are mime-header-encoded.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
trait QuotedStringMimeLiteralPartTokenSplitPatternTrait
|
||||
{
|
||||
/**
|
||||
* Overridden to use a specialized regex for finding mime-encoded parts
|
||||
* (RFC 2047).
|
||||
*
|
||||
* Some implementations seem to place mime-encoded parts within quoted
|
||||
* parameters, and split the mime-encoded parts across multiple split
|
||||
* parameters. The specialized regex doesn't allow double quotes inside a
|
||||
* mime encoded part, so it can be "continued" in another parameter.
|
||||
*
|
||||
* @return string the regex pattern
|
||||
*/
|
||||
protected function getTokenSplitPattern() : string
|
||||
{
|
||||
$sChars = \implode('|', $this->getAllTokenSeparators());
|
||||
$mimePartPattern = MimeToken::MIME_PART_PATTERN_NO_QUOTES;
|
||||
return '~(' . $mimePartPattern . '|\\\\\r\n|\\\\.|' . $sChars . ')~ms';
|
||||
}
|
||||
}
|
||||
68
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/Received/DomainConsumerService.php
vendored
Normal file
68
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/Received/DomainConsumerService.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer\Received;
|
||||
|
||||
/**
|
||||
* Parses a so-called "extended-domain" (from and by) part of a Received header.
|
||||
*
|
||||
* Looks for and extracts the following fields from an extended-domain part:
|
||||
* Name, Hostname and Address.
|
||||
*
|
||||
* The Name part is always the portion of the extended-domain part existing on
|
||||
* its own, outside of the parenthesized hostname and address part. This is
|
||||
* true regardless of whether an address is used as the name, as its assumed to
|
||||
* be the string used to identify the server, whatever it may be.
|
||||
*
|
||||
* The parenthesized part normally (but not necessarily) following a name must
|
||||
* "look like" a tcp-info section of an extended domain as defined by RFC5321.
|
||||
* The validation is very purposefully very loose to be accommodating to many
|
||||
* erroneous implementations. The only restriction is the host part must
|
||||
* contain two characters, the first being alphanumeric, followed by any number
|
||||
* of more alphanumeric, '.', and '-' characters. The address part must be
|
||||
* within square brackets, '[]'... although an address outside of square
|
||||
* brackets could be matched by the domain matcher if it exists alone within the
|
||||
* parentheses. The address is any number of '.', numbers, ':' and letters a-f.
|
||||
* This allows it to match ipv6 addresses as well. In addition, the address may
|
||||
* start with the string "ipv6", and may be followed by a port number as some
|
||||
* implementations seem to do.
|
||||
*
|
||||
* Strings in parentheses not matching the aforementioned 'domain/address'
|
||||
* pattern will be considered comments, and will be returned as a separate
|
||||
* CommentPart.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc5321#section-4.4
|
||||
* @see https://github.com/Te-k/pyreceived/blob/master/test.py
|
||||
* @author Zaahid Bateson
|
||||
* @author Mariusz Krzaczkowski
|
||||
*/
|
||||
class DomainConsumerService extends GenericReceivedConsumerService
|
||||
{
|
||||
/**
|
||||
* Overridden to return true if the passed token is a closing parenthesis.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
if ($token === ')') {
|
||||
return true;
|
||||
}
|
||||
return parent::isEndToken($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single ReceivedDomainPart out of matched parts. If an
|
||||
* unmatched parenthesized expression was found, it's returned as a
|
||||
* CommentPart.
|
||||
*
|
||||
* @param \ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
|
||||
* @return \ZBateson\MailMimeParser\Header\Part\ReceivedDomainPart[]|\ZBateson\MailMimeParser\Header\Part\CommentPart[]|\ZBateson\MailMimeParser\Header\Part\HeaderPart[]
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
return [$this->partFactory->newReceivedDomainPart($this->partName, $parts)];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer\Received;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\AbstractGenericConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\CommentConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
|
||||
|
||||
/**
|
||||
* Consumes simple literal strings for parts of a Received header.
|
||||
*
|
||||
* Starts consuming when the initialized $partName string is located, for
|
||||
* instance when initialized with "FROM", will start consuming on " FROM" or
|
||||
* "FROM ".
|
||||
*
|
||||
* The consumer ends when any possible "Received" header part is found, namely
|
||||
* on one of the following tokens: from, by, via, with, id, for, or when the
|
||||
* start token for the date stamp is found, ';'.
|
||||
*
|
||||
* The consumer allows comments in and around the consumer... although the
|
||||
* Received header specification only allows them before a part, for example,
|
||||
* technically speaking this is valid:
|
||||
*
|
||||
* "FROM machine (host) (comment) BY machine"
|
||||
*
|
||||
* However, this is not:
|
||||
*
|
||||
* "FROM machine (host) BY machine WITH (comment) ESMTP"
|
||||
*
|
||||
* The consumer will allow both.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class GenericReceivedConsumerService extends AbstractGenericConsumerService
|
||||
{
|
||||
/**
|
||||
* @var string the current part name being parsed.
|
||||
*
|
||||
* This is always the lower-case name provided to the constructor, not the
|
||||
* actual string that started the consumer, which could be in any case.
|
||||
*/
|
||||
protected $partName;
|
||||
|
||||
/**
|
||||
* Constructor overridden to include $partName parameter.
|
||||
*
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
HeaderPartFactory $partFactory,
|
||||
CommentConsumerService $commentConsumerService,
|
||||
string $partName
|
||||
) {
|
||||
parent::__construct($logger, $partFactory, [$commentConsumerService]);
|
||||
$this->partName = $partName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed token matches (case-insensitively)
|
||||
* $this->getPartName() with optional whitespace surrounding it.
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
$pattern = '/^' . \preg_quote($this->partName, '/') . '$/i';
|
||||
return (\preg_match($pattern, $token) === 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the token matches (case-insensitively) any of the
|
||||
* following, with optional surrounding whitespace:
|
||||
*
|
||||
* o by
|
||||
* o via
|
||||
* o with
|
||||
* o id
|
||||
* o for
|
||||
* o ;
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return (\preg_match('/^(by|via|with|id|for|;)$/i', $token) === 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a whitespace separator (for filtering ignorable whitespace
|
||||
* between parts), and a separator matching the current part name as
|
||||
* set on $this->partName.
|
||||
*
|
||||
* @return string[] an array of regex pattern matchers
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return [
|
||||
'\s+',
|
||||
'(\A\s*|\s+)(?i)' . \preg_quote($this->partName, '/') . '(?-i)(?=\s+)'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts
|
||||
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[]
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
return [$this->partFactory->newReceivedPart($this->partName, $parts)];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer\Received;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\Consumer\DateConsumerService;
|
||||
|
||||
/**
|
||||
* Parses the date portion of a Received header into a DatePart.
|
||||
*
|
||||
* The only difference between DateConsumerService and
|
||||
* ReceivedDateConsumerService is the addition of a start token, ';', and a
|
||||
* token separator (also ';').
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ReceivedDateConsumerService extends DateConsumerService
|
||||
{
|
||||
/**
|
||||
* Returns true if the token is a ';'
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return ($token === ';');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing ';'.
|
||||
*
|
||||
* @return string[] an array of regex pattern matchers
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return [';'];
|
||||
}
|
||||
}
|
||||
129
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/ReceivedConsumerService.php
vendored
Normal file
129
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/ReceivedConsumerService.php
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Iterator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\Received\DomainConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\Received\GenericReceivedConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\Received\ReceivedDateConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\HeaderPartFactory;
|
||||
use ZBateson\MailMimeParser\Header\Part\Token;
|
||||
|
||||
/**
|
||||
* Parses a Received header into ReceivedParts, ReceivedDomainParts, a DatePart,
|
||||
* and CommentParts.
|
||||
*
|
||||
* Parts that don't correspond to any of the above are discarded.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ReceivedConsumerService extends AbstractConsumerService
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
HeaderPartFactory $partFactory,
|
||||
DomainConsumerService $fromDomainConsumerService,
|
||||
DomainConsumerService $byDomainConsumerService,
|
||||
GenericReceivedConsumerService $viaGenericReceivedConsumerService,
|
||||
GenericReceivedConsumerService $withGenericReceivedConsumerService,
|
||||
GenericReceivedConsumerService $idGenericReceivedConsumerService,
|
||||
GenericReceivedConsumerService $forGenericReceivedConsumerService,
|
||||
ReceivedDateConsumerService $receivedDateConsumerService,
|
||||
CommentConsumerService $commentConsumerService
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$partFactory,
|
||||
[
|
||||
$fromDomainConsumerService,
|
||||
$byDomainConsumerService,
|
||||
$viaGenericReceivedConsumerService,
|
||||
$withGenericReceivedConsumerService,
|
||||
$idGenericReceivedConsumerService,
|
||||
$forGenericReceivedConsumerService,
|
||||
$receivedDateConsumerService,
|
||||
$commentConsumerService
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* ReceivedConsumerService doesn't have any token separators of its own.
|
||||
* Sub-Consumers will return separators matching 'part' word separators, for
|
||||
* example 'from' and 'by', and ';' for date, etc...
|
||||
*
|
||||
* @return string[] an array of regex pattern matchers
|
||||
*/
|
||||
protected function getTokenSeparators() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* ReceivedConsumerService doesn't have an end token, and so this just
|
||||
* returns false.
|
||||
*/
|
||||
protected function isEndToken(string $token) : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ReceivedConsumerService doesn't start consuming at a specific token, it's
|
||||
* the base handler for the Received header, and so this always returns
|
||||
* false.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function isStartToken(string $token) : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to exclude the MimeLiteralPart pattern that comes by default
|
||||
* in AbstractConsumer.
|
||||
*
|
||||
* @return string the regex pattern
|
||||
*/
|
||||
protected function getTokenSplitPattern() : string
|
||||
{
|
||||
$sChars = \implode('|', $this->getAllTokenSeparators());
|
||||
return '~(' . $sChars . ')~';
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to /not/ advance when the end token matches a start token for
|
||||
* a sub-consumer.
|
||||
*/
|
||||
protected function advanceToNextToken(Iterator $tokens, bool $isStartToken) : static
|
||||
{
|
||||
if ($isStartToken) {
|
||||
$tokens->next();
|
||||
} elseif ($tokens->valid() && !$this->isEndToken($tokens->current())) {
|
||||
foreach ($this->subConsumers as $consumer) {
|
||||
if ($consumer->isStartToken($tokens->current())) {
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
$tokens->next();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ZBateson\MailMimeParser\Header\IHeaderPart[] $parts
|
||||
* @return \ZBateson\MailMimeParser\Header\IHeaderPart[]
|
||||
*/
|
||||
protected function processParts(array $parts) : array
|
||||
{
|
||||
// filtering out tokens (filters out the names, e.g. 'by' or 'with')
|
||||
return \array_values(\array_filter($parts, fn ($p) => !$p instanceof Token));
|
||||
}
|
||||
}
|
||||
62
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/SubjectConsumerService.php
vendored
Normal file
62
plugins/vendor/zbateson/mail-mime-parser/src/Header/Consumer/SubjectConsumerService.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Consumer;
|
||||
|
||||
use Iterator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeToken;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* Extends AbstractGenericConsumerService to use a MimeTokenPartFactory, and
|
||||
* to preserve all whitespace and escape sequences as-is (unlike other headers
|
||||
* subject headers don't have escape chars such as '\\' for a backslash).
|
||||
*
|
||||
* SubjectConsumerService doesn't define any sub-consumers.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class SubjectConsumerService extends AbstractGenericConsumerService
|
||||
{
|
||||
public function __construct(LoggerInterface $logger, MimeTokenPartFactory $partFactory)
|
||||
{
|
||||
parent::__construct($logger, $partFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to preserve whitespace.
|
||||
*
|
||||
* Whitespace between two words is preserved unless the whitespace begins
|
||||
* with a newline (\n or \r\n), in which case the entire string of
|
||||
* whitespace is discarded, and a single space ' ' character is used in its
|
||||
* place.
|
||||
*/
|
||||
protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
|
||||
{
|
||||
if (\preg_match('/' . MimeToken::MIME_PART_PATTERN . '/', $token)) {
|
||||
return $this->partFactory->newMimeToken($token);
|
||||
}
|
||||
return $this->partFactory->newSubjectToken($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of \ZBateson\MailMimeParser\Header\Part\HeaderPart for
|
||||
* the current token on the iterator.
|
||||
*
|
||||
* Overridden from AbstractConsumerService to remove special filtering for
|
||||
* backslash escaping, which also seems to not apply to Subject headers at
|
||||
* least in ThunderBird's implementation.
|
||||
*
|
||||
* @return IHeaderPart[]
|
||||
*/
|
||||
protected function getTokenParts(Iterator $tokens) : array
|
||||
{
|
||||
return $this->getConsumerTokenParts($tokens);
|
||||
}
|
||||
}
|
||||
67
plugins/vendor/zbateson/mail-mime-parser/src/Header/DateHeader.php
vendored
Normal file
67
plugins/vendor/zbateson/mail-mime-parser/src/Header/DateHeader.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\DateConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\DatePart;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* Reads a DatePart value header in either RFC 2822 or RFC 822 format.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class DateHeader extends AbstractHeader
|
||||
{
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $value,
|
||||
?LoggerInterface $logger = null,
|
||||
?DateConsumerService $consumerService = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$consumerService ?? $di->get(DateConsumerService::class),
|
||||
$name,
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method returning the part's DateTime object, or null if the
|
||||
* date could not be parsed.
|
||||
*
|
||||
* @return ?DateTime The parsed DateTime object.
|
||||
*/
|
||||
public function getDateTime() : ?DateTime
|
||||
{
|
||||
if (!empty($this->parts) && $this->parts[0] instanceof DatePart) {
|
||||
return $this->parts[0]->getDateTime();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a DateTimeImmutable for the part's DateTime object, or null if
|
||||
* the date could not be parsed.
|
||||
*
|
||||
* @return ?DateTimeImmutable The parsed DateTimeImmutable object.
|
||||
*/
|
||||
public function getDateTimeImmutable() : ?DateTimeImmutable
|
||||
{
|
||||
$dateTime = $this->getDateTime();
|
||||
if ($dateTime !== null) {
|
||||
return DateTimeImmutable::createFromMutable($dateTime);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
47
plugins/vendor/zbateson/mail-mime-parser/src/Header/GenericHeader.php
vendored
Normal file
47
plugins/vendor/zbateson/mail-mime-parser/src/Header/GenericHeader.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\GenericConsumerMimeLiteralPartService;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* Reads a generic header.
|
||||
*
|
||||
* Header's may contain mime-encoded parts, quoted parts, and comments. The
|
||||
* string value is the combined value of all its parts.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class GenericHeader extends AbstractHeader
|
||||
{
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $value,
|
||||
?LoggerInterface $logger = null,
|
||||
?GenericConsumerMimeLiteralPartService $consumerService = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$consumerService ?? $di->get(DateConsumerService::class),
|
||||
$name,
|
||||
$value
|
||||
);
|
||||
parent::__construct($logger, $consumerService, $name, $value);
|
||||
}
|
||||
|
||||
public function getValue() : ?string
|
||||
{
|
||||
if (!empty($this->parts)) {
|
||||
return \implode('', \array_map(function($p) { return $p->getValue(); }, $this->parts));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
95
plugins/vendor/zbateson/mail-mime-parser/src/Header/HeaderConsts.php
vendored
Normal file
95
plugins/vendor/zbateson/mail-mime-parser/src/Header/HeaderConsts.php
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
/**
|
||||
* List of header name constants.
|
||||
*
|
||||
* @author Thomas Landauer
|
||||
*/
|
||||
abstract class HeaderConsts
|
||||
{
|
||||
// Headers according to the table at https://tools.ietf.org/html/rfc5322#section-3.6
|
||||
public const RETURN_PATH = 'Return-Path';
|
||||
|
||||
public const RECEIVED = 'Received';
|
||||
|
||||
public const RESENT_DATE = 'Resent-Date';
|
||||
|
||||
public const RESENT_FROM = 'Resent-From';
|
||||
|
||||
public const RESENT_SENDER = 'Resent-Sender';
|
||||
|
||||
public const RESENT_TO = 'Resent-To';
|
||||
|
||||
public const RESENT_CC = 'Resent-Cc';
|
||||
|
||||
public const RESENT_BCC = 'Resent-Bcc';
|
||||
|
||||
public const RESENT_MSD_ID = 'Resent-Message-ID';
|
||||
|
||||
public const RESENT_MESSAGE_ID = self::RESENT_MSD_ID;
|
||||
|
||||
public const ORIG_DATE = 'Date';
|
||||
|
||||
public const DATE = self::ORIG_DATE;
|
||||
|
||||
public const FROM = 'From';
|
||||
|
||||
public const SENDER = 'Sender';
|
||||
|
||||
public const REPLY_TO = 'Reply-To';
|
||||
|
||||
public const TO = 'To';
|
||||
|
||||
public const CC = 'Cc';
|
||||
|
||||
public const BCC = 'Bcc';
|
||||
|
||||
public const MESSAGE_ID = 'Message-ID';
|
||||
|
||||
public const IN_REPLY_TO = 'In-Reply-To';
|
||||
|
||||
public const REFERENCES = 'References';
|
||||
|
||||
public const SUBJECT = 'Subject';
|
||||
|
||||
public const COMMENTS = 'Comments';
|
||||
|
||||
public const KEYWORDS = 'Keywords';
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc4021#section-2.2
|
||||
public const MIME_VERSION = 'MIME-Version';
|
||||
|
||||
public const CONTENT_TYPE = 'Content-Type';
|
||||
|
||||
public const CONTENT_TRANSFER_ENCODING = 'Content-Transfer-Encoding';
|
||||
|
||||
public const CONTENT_ID = 'Content-ID';
|
||||
|
||||
public const CONTENT_DESCRIPTION = 'Content-Description';
|
||||
|
||||
public const CONTENT_DISPOSITION = 'Content-Disposition';
|
||||
|
||||
public const CONTENT_LANGUAGE = 'Content-Language';
|
||||
|
||||
public const CONTENT_BASE = 'Content-Base';
|
||||
|
||||
public const CONTENT_LOCATION = 'Content-Location';
|
||||
|
||||
public const CONTENT_FEATURES = 'Content-features';
|
||||
|
||||
public const CONTENT_ALTERNATIVE = 'Content-Alternative';
|
||||
|
||||
public const CONTENT_MD5 = 'Content-MD5';
|
||||
|
||||
public const CONTENT_DURATION = 'Content-Duration';
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc3834
|
||||
public const AUTO_SUBMITTED = 'Auto-Submitted';
|
||||
}
|
||||
213
plugins/vendor/zbateson/mail-mime-parser/src/Header/HeaderFactory.php
vendored
Normal file
213
plugins/vendor/zbateson/mail-mime-parser/src/Header/HeaderFactory.php
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ReflectionClass;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\AddressBaseConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\DateConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\GenericConsumerMimeLiteralPartService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\IConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\IdBaseConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\ParameterConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\ReceivedConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\SubjectConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* Constructs various IHeader types depending on the type of header passed.
|
||||
*
|
||||
* If the passed header resolves to a specific defined header type, it is parsed
|
||||
* as such. Otherwise, a GenericHeader is instantiated and returned. Headers
|
||||
* are mapped as follows:
|
||||
*
|
||||
* - {@see AddressHeader}: From, To, Cc, Bcc, Sender, Reply-To, Resent-From,
|
||||
* Resent-To, Resent-Cc, Resent-Bcc, Resent-Reply-To, Return-Path,
|
||||
* Delivered-To
|
||||
* - {@see DateHeader}: Date, Resent-Date, Delivery-Date, Expires, Expiry-Date,
|
||||
* Reply-By
|
||||
* - {@see ParameterHeader}: Content-Type, Content-Disposition, Received-SPF,
|
||||
* Authentication-Results, DKIM-Signature, Autocrypt
|
||||
* - {@see SubjectHeader}: Subject
|
||||
* - {@see IdHeader}: Message-ID, Content-ID, In-Reply-To, References
|
||||
* - {@see ReceivedHeader}: Received
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class HeaderFactory
|
||||
{
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
/**
|
||||
* @var IConsumerService[] array of available consumer service classes
|
||||
*/
|
||||
protected array $consumerServices;
|
||||
|
||||
/**
|
||||
* @var MimeTokenPartFactory for mime decoding.
|
||||
*/
|
||||
protected MimeTokenPartFactory $mimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* @var string[][] maps IHeader types to headers.
|
||||
*/
|
||||
protected $types = [
|
||||
AddressHeader::class => [
|
||||
'from',
|
||||
'to',
|
||||
'cc',
|
||||
'bcc',
|
||||
'sender',
|
||||
'replyto',
|
||||
'resentfrom',
|
||||
'resentto',
|
||||
'resentcc',
|
||||
'resentbcc',
|
||||
'resentreplyto',
|
||||
'returnpath',
|
||||
'deliveredto',
|
||||
],
|
||||
DateHeader::class => [
|
||||
'date',
|
||||
'resentdate',
|
||||
'deliverydate',
|
||||
'expires',
|
||||
'expirydate',
|
||||
'replyby',
|
||||
],
|
||||
ParameterHeader::class => [
|
||||
'contenttype',
|
||||
'contentdisposition',
|
||||
'receivedspf',
|
||||
'authenticationresults',
|
||||
'dkimsignature',
|
||||
'autocrypt',
|
||||
],
|
||||
SubjectHeader::class => [
|
||||
'subject',
|
||||
],
|
||||
IdHeader::class => [
|
||||
'messageid',
|
||||
'contentid',
|
||||
'inreplyto',
|
||||
'references'
|
||||
],
|
||||
ReceivedHeader::class => [
|
||||
'received'
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string Defines the generic IHeader type to use for headers that
|
||||
* aren't mapped in $types
|
||||
*/
|
||||
protected $genericType = GenericHeader::class;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MimeTokenPartFactory $mimeTokenPartFactory,
|
||||
AddressBaseConsumerService $addressBaseConsumerService,
|
||||
DateConsumerService $dateConsumerService,
|
||||
GenericConsumerMimeLiteralPartService $genericConsumerMimeLiteralPartService,
|
||||
IdBaseConsumerService $idBaseConsumerService,
|
||||
ParameterConsumerService $parameterConsumerService,
|
||||
ReceivedConsumerService $receivedConsumerService,
|
||||
SubjectConsumerService $subjectConsumerService
|
||||
) {
|
||||
$this->logger = $logger;
|
||||
$this->mimeTokenPartFactory = $mimeTokenPartFactory;
|
||||
$this->consumerServices = [
|
||||
AddressBaseConsumerService::class => $addressBaseConsumerService,
|
||||
DateConsumerService::class => $dateConsumerService,
|
||||
GenericConsumerMimeLiteralPartService::class => $genericConsumerMimeLiteralPartService,
|
||||
IdBaseConsumerService::class => $idBaseConsumerService,
|
||||
ParameterConsumerService::class => $parameterConsumerService,
|
||||
ReceivedConsumerService::class => $receivedConsumerService,
|
||||
SubjectConsumerService::class => $subjectConsumerService
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string in lower-case, and with non-alphanumeric characters
|
||||
* stripped out.
|
||||
*
|
||||
* @param string $header The header name
|
||||
* @return string The normalized header name
|
||||
*/
|
||||
public function getNormalizedHeaderName(string $header) : string
|
||||
{
|
||||
return \preg_replace('/[^a-z0-9]/', '', \strtolower($header));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of an IHeader class for the passed header name.
|
||||
*
|
||||
* @param string $name The header name.
|
||||
* @return string The Fully Qualified class name.
|
||||
*/
|
||||
private function getClassFor(string $name) : string
|
||||
{
|
||||
$test = $this->getNormalizedHeaderName($name);
|
||||
foreach ($this->types as $class => $matchers) {
|
||||
foreach ($matchers as $matcher) {
|
||||
if ($test === $matcher) {
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->genericType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IHeader instance for the passed header name and value, and
|
||||
* returns it.
|
||||
*
|
||||
* @param string $name The header name.
|
||||
* @param string $value The header value.
|
||||
* @return IHeader The created header object.
|
||||
*/
|
||||
public function newInstance(string $name, string $value) : IHeader
|
||||
{
|
||||
$class = $this->getClassFor($name);
|
||||
$this->logger->debug(
|
||||
'Creating {class} for header with name "{name}" and value "{value}"',
|
||||
['class' => $class, 'name' => $name, 'value' => $value]
|
||||
);
|
||||
return $this->newInstanceOf($name, $value, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IHeader instance for the passed header name and value using
|
||||
* the passed IHeader class, and returns it.
|
||||
*
|
||||
* @param string $name The header name.
|
||||
* @param string $value The header value.
|
||||
* @param string $iHeaderClass The class to use for header creation
|
||||
* @return IHeader The created header object.
|
||||
*/
|
||||
public function newInstanceOf(string $name, string $value, string $iHeaderClass) : IHeader
|
||||
{
|
||||
$ref = new ReflectionClass($iHeaderClass);
|
||||
$params = $ref->getConstructor()->getParameters();
|
||||
if ($ref->isSubclassOf(MimeEncodedHeader::class)) {
|
||||
return new $iHeaderClass(
|
||||
$name,
|
||||
$value,
|
||||
$this->logger,
|
||||
$this->mimeTokenPartFactory,
|
||||
$this->consumerServices[$params[4]->getType()->getName()]
|
||||
);
|
||||
}
|
||||
return new $iHeaderClass(
|
||||
$name,
|
||||
$value,
|
||||
$this->logger,
|
||||
$this->consumerServices[$params[3]->getType()->getName()]
|
||||
);
|
||||
}
|
||||
}
|
||||
84
plugins/vendor/zbateson/mail-mime-parser/src/Header/IHeader.php
vendored
Normal file
84
plugins/vendor/zbateson/mail-mime-parser/src/Header/IHeader.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use ZBateson\MailMimeParser\IErrorBag;
|
||||
|
||||
/**
|
||||
* A mime email header line consisting of a name and value.
|
||||
*
|
||||
* The header object provides methods to access the header's name, raw value,
|
||||
* and also its parsed value. The parsed value will depend on the type of
|
||||
* header and in some cases may be broken up into other parts (for example email
|
||||
* addresses in an address header, or parameters in a parameter header).
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IHeader extends IErrorBag
|
||||
{
|
||||
/**
|
||||
* Returns an array of IHeaderPart objects the header's value has been
|
||||
* parsed into, excluding any
|
||||
* {@see \ZBateson\MailMimeParser\Header\Part\CommentPart}s.
|
||||
*
|
||||
* To retrieve all parts /including/ CommentParts, {@see getAllParts()}.
|
||||
*
|
||||
* @return IHeaderPart[] The array of parts.
|
||||
*/
|
||||
public function getParts() : array;
|
||||
|
||||
/**
|
||||
* Returns an array of all IHeaderPart objects the header's value has been
|
||||
* parsed into, including any CommentParts.
|
||||
*
|
||||
* @return IHeaderPart[] The array of parts.
|
||||
*/
|
||||
public function getAllParts() : array;
|
||||
|
||||
/**
|
||||
* Returns an array of comments parsed from the header. If there are no
|
||||
* comments in the header, an empty array is returned.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getComments() : array;
|
||||
|
||||
/**
|
||||
* Returns the parsed 'value' of the header.
|
||||
*
|
||||
* For headers that contain multiple parts, like address headers (To, From)
|
||||
* or parameter headers (Content-Type), the 'value' is the value of the
|
||||
* first parsed part that isn't a comment.
|
||||
*
|
||||
* @return string The value
|
||||
*/
|
||||
public function getValue() : ?string;
|
||||
|
||||
/**
|
||||
* Returns the raw value of the header.
|
||||
*
|
||||
* @return string The raw value.
|
||||
*/
|
||||
public function getRawValue() : string;
|
||||
|
||||
/**
|
||||
* Returns the name of the header.
|
||||
*
|
||||
* @return string The name.
|
||||
*/
|
||||
public function getName() : string;
|
||||
|
||||
/**
|
||||
* Returns the string representation of the header.
|
||||
*
|
||||
* i.e.: '<HeaderName>: <RawValue>'
|
||||
*
|
||||
* @return string The string representation.
|
||||
*/
|
||||
public function __toString() : string;
|
||||
}
|
||||
36
plugins/vendor/zbateson/mail-mime-parser/src/Header/IHeaderPart.php
vendored
Normal file
36
plugins/vendor/zbateson/mail-mime-parser/src/Header/IHeaderPart.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use Stringable;
|
||||
use ZBateson\MailMimeParser\IErrorBag;
|
||||
|
||||
/**
|
||||
* Represents a single parsed part of a header line's value.
|
||||
*
|
||||
* For header values with multiple parts, for instance a list of addresses, each
|
||||
* address would be parsed into a single part.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IHeaderPart extends IErrorBag, Stringable
|
||||
{
|
||||
/**
|
||||
* Returns the part's value.
|
||||
*
|
||||
* @return string The value of the part
|
||||
*/
|
||||
public function getValue() : ?string;
|
||||
|
||||
/**
|
||||
* Returns any CommentParts under this part container.
|
||||
*
|
||||
* @return CommentPart[]
|
||||
*/
|
||||
public function getComments() : array;
|
||||
}
|
||||
71
plugins/vendor/zbateson/mail-mime-parser/src/Header/IdHeader.php
vendored
Normal file
71
plugins/vendor/zbateson/mail-mime-parser/src/Header/IdHeader.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\IdBaseConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\CommentPart;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* Represents a Content-ID, Message-ID, In-Reply-To or References header.
|
||||
*
|
||||
* For a multi-id header like In-Reply-To or References, all IDs can be
|
||||
* retrieved by calling {@see IdHeader::getIds()}. Otherwise, to retrieve the
|
||||
* first (or only) ID call {@see IdHeader::getValue()}.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class IdHeader extends MimeEncodedHeader
|
||||
{
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $value,
|
||||
?LoggerInterface $logger = null,
|
||||
?MimeTokenPartFactory $mimeTokenPartFactory = null,
|
||||
?IdBaseConsumerService $consumerService = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$mimeTokenPartFactory ?? $di->get(MimeTokenPartFactory::class),
|
||||
$consumerService ?? $di->get(IdBaseConsumerService::class),
|
||||
$name,
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID. Synonymous to calling getValue().
|
||||
*
|
||||
* @return string|null The ID
|
||||
*/
|
||||
public function getId() : ?string
|
||||
{
|
||||
return $this->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all IDs parsed for a multi-id header like References or
|
||||
* In-Reply-To.
|
||||
*
|
||||
* @return string[] An array of IDs
|
||||
*/
|
||||
public function getIds() : array
|
||||
{
|
||||
return \array_values(\array_map(
|
||||
function($p) {
|
||||
return $p->getValue();
|
||||
},
|
||||
\array_filter($this->parts, function($p) {
|
||||
return !($p instanceof CommentPart);
|
||||
})
|
||||
));
|
||||
}
|
||||
}
|
||||
66
plugins/vendor/zbateson/mail-mime-parser/src/Header/MimeEncodedHeader.php
vendored
Normal file
66
plugins/vendor/zbateson/mail-mime-parser/src/Header/MimeEncodedHeader.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\IConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeToken;
|
||||
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* Allows a header to be mime-encoded and be decoded with a consumer after
|
||||
* decoding.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class MimeEncodedHeader extends AbstractHeader
|
||||
{
|
||||
/**
|
||||
* @var MimeTokenPartFactory for mime decoding.
|
||||
*/
|
||||
protected MimeTokenPartFactory $mimeTokenPartFactory;
|
||||
|
||||
/**
|
||||
* @var MimeLiteralPart[] the mime encoded parsed parts contained in this
|
||||
* header
|
||||
*/
|
||||
protected $mimeEncodedParsedParts = [];
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MimeTokenPartFactory $mimeTokenPartFactory,
|
||||
IConsumerService $consumerService,
|
||||
string $name,
|
||||
string $value
|
||||
) {
|
||||
$this->mimeTokenPartFactory = $mimeTokenPartFactory;
|
||||
parent::__construct($logger, $consumerService, $name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mime-decodes any mime-encoded parts prior to invoking
|
||||
* parent::parseHeaderValue.
|
||||
*/
|
||||
protected function parseHeaderValue(IConsumerService $consumer, string $value) : void
|
||||
{
|
||||
// handled differently from MimeLiteralPart's decoding which ignores
|
||||
// whitespace between parts, etc...
|
||||
$matchp = '~(' . MimeToken::MIME_PART_PATTERN . ')~';
|
||||
$aMimeParts = \preg_split($matchp, $value, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
$this->mimeEncodedParsedParts = \array_map([$this->mimeTokenPartFactory, 'newInstance'], $aMimeParts);
|
||||
parent::parseHeaderValue(
|
||||
$consumer,
|
||||
\implode('', \array_map(fn ($part) => $part->getValue(), $this->mimeEncodedParsedParts))
|
||||
);
|
||||
}
|
||||
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return \array_values(\array_filter(\array_merge($this->getAllParts(), $this->mimeEncodedParsedParts)));
|
||||
}
|
||||
}
|
||||
99
plugins/vendor/zbateson/mail-mime-parser/src/Header/ParameterHeader.php
vendored
Normal file
99
plugins/vendor/zbateson/mail-mime-parser/src/Header/ParameterHeader.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\IConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\ParameterConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\NameValuePart;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* Represents a header containing an optional main value part and subsequent
|
||||
* name/value pairs.
|
||||
*
|
||||
* If header doesn't contain a non-parameterized 'main' value part, 'getValue()'
|
||||
* will return the value of the first parameter.
|
||||
*
|
||||
* For example: 'Content-Type: text/html; charset=utf-8; name=test.ext'
|
||||
*
|
||||
* The 'text/html' portion is considered the 'main' value, and 'charset' and
|
||||
* 'name' are added as parameterized name/value pairs.
|
||||
*
|
||||
* With the Autocrypt header, there is no main value portion, for example:
|
||||
* 'Autocrypt: addr=zb@example.com; keydata=b64-data'
|
||||
*
|
||||
* In that example, calling ```php $header->getValue() ``` would return
|
||||
* 'zb@example.com', as would calling ```php $header->getValueFor('addr'); ```.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ParameterHeader extends AbstractHeader
|
||||
{
|
||||
/**
|
||||
* @var ParameterPart[] key map of lower-case parameter names and associated
|
||||
* ParameterParts.
|
||||
*/
|
||||
protected array $parameters = [];
|
||||
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $value,
|
||||
?LoggerInterface $logger = null,
|
||||
?ParameterConsumerService $consumerService = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$consumerService ?? $di->get(ParameterConsumerService::class),
|
||||
$name,
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to assign ParameterParts to a map of lower-case parameter
|
||||
* names to ParameterParts.
|
||||
*/
|
||||
protected function parseHeaderValue(IConsumerService $consumer, string $value) : void
|
||||
{
|
||||
parent::parseHeaderValue($consumer, $value);
|
||||
foreach ($this->parts as $part) {
|
||||
if ($part instanceof NameValuePart) {
|
||||
$this->parameters[\strtolower($part->getName())] = $part;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a parameter exists with the passed name.
|
||||
*
|
||||
* @param string $name The parameter to look up.
|
||||
*/
|
||||
public function hasParameter(string $name) : bool
|
||||
{
|
||||
return isset($this->parameters[\strtolower($name)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the parameter with the given name, or $defaultValue
|
||||
* if not set.
|
||||
*
|
||||
* @param string $name The parameter to retrieve.
|
||||
* @param string $defaultValue Optional default value (defaulting to null if
|
||||
* not provided).
|
||||
* @return string|null The parameter's value.
|
||||
*/
|
||||
public function getValueFor(string $name, ?string $defaultValue = null) : ?string
|
||||
{
|
||||
if (!$this->hasParameter($name)) {
|
||||
return $defaultValue;
|
||||
}
|
||||
return $this->parameters[\strtolower($name)]->getValue();
|
||||
}
|
||||
}
|
||||
86
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/AddressGroupPart.php
vendored
Normal file
86
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/AddressGroupPart.php
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Holds a group of addresses and a group name.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class AddressGroupPart extends NameValuePart
|
||||
{
|
||||
/**
|
||||
* @var AddressPart[] an array of AddressParts
|
||||
*/
|
||||
protected array $addresses;
|
||||
|
||||
/**
|
||||
* Creates an AddressGroupPart out of the passed array of AddressParts/
|
||||
* AddressGroupParts and name.
|
||||
*
|
||||
* @param HeaderPart[] $nameParts
|
||||
* @param AddressPart[]|AddressGroupPart[] $addressesAndGroupParts
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
array $nameParts,
|
||||
array $addressesAndGroupParts
|
||||
) {
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$charsetConverter,
|
||||
$nameParts,
|
||||
$addressesAndGroupParts
|
||||
);
|
||||
$this->addresses = \array_merge(...\array_map(
|
||||
fn ($p) => ($p instanceof AddressGroupPart) ? $p->getAddresses() : [$p],
|
||||
$addressesAndGroupParts
|
||||
));
|
||||
// for backwards compatibility
|
||||
$this->value = $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AddressGroupPart's array of addresses.
|
||||
*
|
||||
* @return AddressPart[] An array of address parts.
|
||||
*/
|
||||
public function getAddresses() : array
|
||||
{
|
||||
return $this->addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AddressPart at the passed index or null.
|
||||
*
|
||||
* @param int $index The 0-based index.
|
||||
* @return ?AddressPart The address.
|
||||
*/
|
||||
public function getAddress(int $index) : ?AddressPart
|
||||
{
|
||||
if (!isset($this->addresses[$index])) {
|
||||
return null;
|
||||
}
|
||||
return $this->addresses[$index];
|
||||
}
|
||||
|
||||
protected function validate() : void
|
||||
{
|
||||
if ($this->name === null || \mb_strlen($this->name) === 0) {
|
||||
$this->addError('Address group doesn\'t have a name', LogLevel::ERROR);
|
||||
}
|
||||
if (empty($this->addresses)) {
|
||||
$this->addError('Address group doesn\'t have any email addresses defined in it', LogLevel::NOTICE);
|
||||
}
|
||||
}
|
||||
}
|
||||
57
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/AddressPart.php
vendored
Normal file
57
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/AddressPart.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* Holds a single address or name/address pair.
|
||||
*
|
||||
* The name part of the address may be mime-encoded, but the email address part
|
||||
* can't be mime-encoded. Any whitespace in the email address part is stripped
|
||||
* out.
|
||||
*
|
||||
* A convenience method, getEmail, is provided for clarity -- but getValue
|
||||
* returns the email address as well.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class AddressPart extends NameValuePart
|
||||
{
|
||||
protected function getValueFromParts(array $parts) : string
|
||||
{
|
||||
return \implode('', \array_map(
|
||||
function($p) {
|
||||
if ($p instanceof AddressPart) {
|
||||
return $p->getValue();
|
||||
} elseif ($p instanceof QuotedLiteralPart && $p->getValue() !== '') {
|
||||
return '"' . \preg_replace('/(["\\\])/', '\\\$1', $p->getValue()) . '"';
|
||||
}
|
||||
return \preg_replace('/\s+/', '', $p->getValue());
|
||||
},
|
||||
$parts
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the email address.
|
||||
*
|
||||
* @return string The email address.
|
||||
*/
|
||||
public function getEmail() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
protected function validate() : void
|
||||
{
|
||||
if (empty($this->value)) {
|
||||
$this->addError('Address doesn\'t contain an email address', LogLevel::ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
77
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/CommentPart.php
vendored
Normal file
77
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/CommentPart.php
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Represents a mime header comment -- text in a structured mime header
|
||||
* value existing within parentheses.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class CommentPart extends ContainerPart
|
||||
{
|
||||
/**
|
||||
* @var HeaderPartFactory used to create intermediate parts.
|
||||
*/
|
||||
protected HeaderPartFactory $partFactory;
|
||||
|
||||
/**
|
||||
* @var string the contents of the comment
|
||||
*/
|
||||
protected string $comment;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
HeaderPartFactory $partFactory,
|
||||
array $children
|
||||
) {
|
||||
$this->partFactory = $partFactory;
|
||||
parent::__construct($logger, $charsetConverter, $children);
|
||||
$this->comment = $this->value;
|
||||
$this->value = '';
|
||||
$this->isSpace = true;
|
||||
$this->canIgnoreSpacesBefore = true;
|
||||
$this->canIgnoreSpacesAfter = true;
|
||||
}
|
||||
|
||||
protected function getValueFromParts(array $parts) : string
|
||||
{
|
||||
$partFactory = $this->partFactory;
|
||||
return parent::getValueFromParts(\array_map(
|
||||
function($p) use ($partFactory) {
|
||||
if ($p instanceof CommentPart) {
|
||||
return $partFactory->newQuotedLiteralPart([$partFactory->newToken('(' . $p->getComment() . ')')]);
|
||||
} elseif ($p instanceof QuotedLiteralPart) {
|
||||
return $partFactory->newQuotedLiteralPart([$partFactory->newToken('"' . \str_replace('(["\\])', '\$1', $p->getValue()) . '"')]);
|
||||
}
|
||||
return $p;
|
||||
},
|
||||
$parts
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the comment's text.
|
||||
*/
|
||||
public function getComment() : string
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty string.
|
||||
*/
|
||||
public function getValue() : string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
128
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/ContainerPart.php
vendored
Normal file
128
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/ContainerPart.php
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Base HeaderPart for a part that consists of other parts.
|
||||
*
|
||||
* The base container part constructs a string value out of the passed parts by
|
||||
* concatenating their values, discarding whitespace between parts that can be
|
||||
* ignored (in general allows for a single space but removes extras.)
|
||||
*
|
||||
* A ContainerPart can also contain any number of child comment parts. The
|
||||
* CommentParts in this and all child parts can be returned by calling
|
||||
* getComments.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ContainerPart extends HeaderPart
|
||||
{
|
||||
/**
|
||||
* @var HeaderPart[] parts that were used to create this part, collected for
|
||||
* proper error reporting and validation.
|
||||
*/
|
||||
protected $children = [];
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
array $children
|
||||
) {
|
||||
ErrorBag::__construct($logger);
|
||||
$this->charsetConverter = $charsetConverter;
|
||||
$this->children = $children;
|
||||
$str = (!empty($children)) ? $this->getValueFromParts($children) : '';
|
||||
parent::__construct(
|
||||
$logger,
|
||||
$this->charsetConverter,
|
||||
$str
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out ignorable space tokens.
|
||||
*
|
||||
* Spaces are removed if parts on either side of it have their
|
||||
* canIgnoreSpaceAfter/canIgnoreSpaceBefore properties set to true.
|
||||
*
|
||||
* @param HeaderPart[] $parts
|
||||
* @return HeaderPart[]
|
||||
*/
|
||||
protected function filterIgnoredSpaces(array $parts) : array
|
||||
{
|
||||
$ends = (object) ['isSpace' => true, 'canIgnoreSpacesAfter' => true, 'canIgnoreSpacesBefore' => true, 'value' => ''];
|
||||
|
||||
$spaced = \array_merge($parts, [$ends]);
|
||||
$filtered = \array_slice(\array_reduce(
|
||||
\array_slice(\array_keys($spaced), 0, -1),
|
||||
function($carry, $key) use ($spaced, $ends) {
|
||||
$p = $spaced[$key];
|
||||
$l = \end($carry);
|
||||
$a = $spaced[$key + 1];
|
||||
if ($p->isSpace && $a === $ends) {
|
||||
// trim
|
||||
if ($l->isSpace) {
|
||||
\array_pop($carry);
|
||||
}
|
||||
return $carry;
|
||||
} elseif ($p->isSpace && ($l->isSpace || ($l->canIgnoreSpacesAfter && $a->canIgnoreSpacesBefore))) {
|
||||
return $carry;
|
||||
}
|
||||
return \array_merge($carry, [$p]);
|
||||
},
|
||||
[$ends]
|
||||
), 1);
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the string value representation of this part constructed from the
|
||||
* child parts passed to it.
|
||||
*
|
||||
* The default implementation filters out ignorable whitespace between
|
||||
* parts, and concatenates parts calling 'getValue'.
|
||||
*
|
||||
* @param HeaderParts[] $parts
|
||||
*/
|
||||
protected function getValueFromParts(array $parts) : string
|
||||
{
|
||||
return \array_reduce($this->filterIgnoredSpaces($parts), fn ($c, $p) => $c . $p->getValue(), '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the child parts this container part consists of.
|
||||
*
|
||||
* @return IHeaderPart[]
|
||||
*/
|
||||
public function getChildParts() : array
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
public function getComments() : array
|
||||
{
|
||||
return \array_merge(...\array_filter(\array_map(
|
||||
fn ($p) => ($p instanceof CommentPart) ? [$p] : $p->getComments(),
|
||||
$this->children
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this part's children, same as getChildParts().
|
||||
*
|
||||
* @return ErrorBag
|
||||
*/
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
}
|
||||
72
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/DatePart.php
vendored
Normal file
72
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/DatePart.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Represents the value of a date header, parsing the date into a \DateTime
|
||||
* object.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class DatePart extends ContainerPart
|
||||
{
|
||||
/**
|
||||
* @var DateTime the parsed date, or null if the date could not be parsed
|
||||
*/
|
||||
protected ?DateTime $date = null;
|
||||
|
||||
/**
|
||||
* Tries parsing the passed token as an RFC 2822 date, and failing that into
|
||||
* an RFC 822 date, and failing that, tries to parse it by calling
|
||||
* new DateTime($value).
|
||||
*
|
||||
* @param HeaderPart[] $children
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
array $children
|
||||
) {
|
||||
// parent::__construct converts character encoding -- may cause problems sometimes.
|
||||
parent::__construct($logger, $charsetConverter, $children);
|
||||
$this->value = $dateToken = \trim($this->value);
|
||||
|
||||
// Missing "+" in timezone definition. eg: Thu, 13 Mar 2014 15:02:47 0000 (not RFC compliant)
|
||||
// Won't result in an Exception, but in a valid DateTime in year `0000` - therefore we need to check this first:
|
||||
if (\preg_match('# [0-9]{4}$#', $dateToken)) {
|
||||
$dateToken = \preg_replace('# ([0-9]{4})$#', ' +$1', $dateToken);
|
||||
// @see https://bugs.php.net/bug.php?id=42486
|
||||
} elseif (\preg_match('#UT$#', $dateToken)) {
|
||||
$dateToken = $dateToken . 'C';
|
||||
}
|
||||
|
||||
try {
|
||||
$this->date = new DateTime($dateToken);
|
||||
} catch (Exception $e) {
|
||||
$this->addError(
|
||||
"Unable to parse date from header: \"{$dateToken}\"",
|
||||
LogLevel::ERROR,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a DateTime object or null if it can't be parsed.
|
||||
*/
|
||||
public function getDateTime() : ?DateTime
|
||||
{
|
||||
return $this->date;
|
||||
}
|
||||
}
|
||||
116
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/HeaderPart.php
vendored
Normal file
116
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/HeaderPart.php
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
use ZBateson\MbWrapper\UnsupportedCharsetException;
|
||||
|
||||
/**
|
||||
* Abstract base class representing a single part of a parsed header.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class HeaderPart extends ErrorBag implements IHeaderPart
|
||||
{
|
||||
/**
|
||||
* @var string the representative value of the part after any conversion or
|
||||
* processing has been done on it (e.g. removing new lines, converting,
|
||||
* whatever else).
|
||||
*/
|
||||
protected string $value;
|
||||
|
||||
/**
|
||||
* @var MbWrapper $charsetConverter the charset converter used for
|
||||
* converting strings in HeaderPart::convertEncoding
|
||||
*/
|
||||
protected MbWrapper $charsetConverter;
|
||||
|
||||
/**
|
||||
* @var bool set to true to ignore spaces before this part
|
||||
*/
|
||||
protected bool $canIgnoreSpacesBefore = false;
|
||||
|
||||
/**
|
||||
* @var bool set to true to ignore spaces after this part
|
||||
*/
|
||||
protected bool $canIgnoreSpacesAfter = false;
|
||||
|
||||
/**
|
||||
* True if the part is a space token
|
||||
*/
|
||||
protected bool $isSpace = false;
|
||||
|
||||
public function __construct(LoggerInterface $logger, MbWrapper $charsetConverter, string $value)
|
||||
{
|
||||
parent::__construct($logger);
|
||||
$this->charsetConverter = $charsetConverter;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part's representative value after any necessary processing
|
||||
* has been performed. For the raw value, call getRawValue().
|
||||
*/
|
||||
public function getValue() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the part (which is a string).
|
||||
*
|
||||
* @return string the value
|
||||
*/
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the encoding of the passed string is set to UTF-8.
|
||||
*
|
||||
* The method does nothing if the passed $from charset is UTF-8 already, or
|
||||
* if $force is set to false and mb_check_encoding for $str returns true
|
||||
* for 'UTF-8'.
|
||||
*
|
||||
* @return string utf-8 string
|
||||
*/
|
||||
protected function convertEncoding(string $str, string $from = 'ISO-8859-1', bool $force = false) : string
|
||||
{
|
||||
if ($from !== 'UTF-8') {
|
||||
// mime header part decoding will force it. This is necessary for
|
||||
// UTF-7 because mb_check_encoding will return true
|
||||
if ($force || !($this->charsetConverter->checkEncoding($str, 'UTF-8'))) {
|
||||
try {
|
||||
return $this->charsetConverter->convert($str, $from, 'UTF-8');
|
||||
} catch (UnsupportedCharsetException $ce) {
|
||||
$this->addError('Unable to convert charset', LogLevel::ERROR, $ce);
|
||||
return $this->charsetConverter->convert($str, 'ISO-8859-1', 'UTF-8');
|
||||
}
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function getComments() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation returns an empty array.
|
||||
*/
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
176
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/HeaderPartFactory.php
vendored
Normal file
176
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/HeaderPartFactory.php
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Constructs and returns IHeaderPart objects.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class HeaderPartFactory
|
||||
{
|
||||
/**
|
||||
* @var MbWrapper $charsetConverter passed to IHeaderPart constructors
|
||||
* for converting strings in IHeaderPart::convertEncoding
|
||||
*/
|
||||
protected MbWrapper $charsetConverter;
|
||||
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
public function __construct(LoggerInterface $logger, MbWrapper $charsetConverter)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->charsetConverter = $charsetConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a default IHeaderPart for this factory, allowing
|
||||
* subclass factories for specialized IHeaderParts.
|
||||
*
|
||||
* The default implementation returns a new Token
|
||||
*/
|
||||
public function newInstance(string $value) : IHeaderPart
|
||||
{
|
||||
return $this->newToken($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new Token.
|
||||
*/
|
||||
public function newToken(string $value, bool $isLiteral = false, bool $preserveSpaces = false) : Token
|
||||
{
|
||||
return new Token($this->logger, $this->charsetConverter, $value, $isLiteral, $preserveSpaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new SubjectToken.
|
||||
*/
|
||||
public function newSubjectToken(string $value) : SubjectToken
|
||||
{
|
||||
return new SubjectToken($this->logger, $this->charsetConverter, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new MimeToken.
|
||||
*/
|
||||
public function newMimeToken(string $value) : MimeToken
|
||||
{
|
||||
return new MimeToken($this->logger, $this->charsetConverter, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new ContainerPart.
|
||||
*
|
||||
* @param HeaderPart[] $children
|
||||
*/
|
||||
public function newContainerPart(array $children) : ContainerPart
|
||||
{
|
||||
return new ContainerPart($this->logger, $this->charsetConverter, $children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates and returns a SplitParameterPart.
|
||||
*
|
||||
* @param ParameterPart[] $children
|
||||
*/
|
||||
public function newSplitParameterPart(array $children) : SplitParameterPart
|
||||
{
|
||||
return new SplitParameterPart($this->logger, $this->charsetConverter, $this, $children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new QuotedLiteralPart.
|
||||
*
|
||||
* @param HeaderPart[] $parts
|
||||
*/
|
||||
public function newQuotedLiteralPart(array $parts) : QuotedLiteralPart
|
||||
{
|
||||
return new QuotedLiteralPart($this->logger, $this->charsetConverter, $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new CommentPart.
|
||||
*
|
||||
* @param HeaderPart[] $children
|
||||
*/
|
||||
public function newCommentPart(array $children) : CommentPart
|
||||
{
|
||||
return new CommentPart($this->logger, $this->charsetConverter, $this, $children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new AddressPart.
|
||||
*
|
||||
* @param HeaderPart[] $nameParts
|
||||
* @param HeaderPart[] $emailParts
|
||||
*/
|
||||
public function newAddress(array $nameParts, array $emailParts) : AddressPart
|
||||
{
|
||||
return new AddressPart($this->logger, $this->charsetConverter, $nameParts, $emailParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new AddressGroupPart
|
||||
*
|
||||
* @param HeaderPart[] $nameParts
|
||||
* @param AddressPart[]|AddressGroupPart[] $addressesAndGroups
|
||||
*/
|
||||
public function newAddressGroupPart(array $nameParts, array $addressesAndGroups) : AddressGroupPart
|
||||
{
|
||||
return new AddressGroupPart($this->logger, $this->charsetConverter, $nameParts, $addressesAndGroups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new DatePart
|
||||
*
|
||||
* @param HeaderPart[] $children
|
||||
*/
|
||||
public function newDatePart(array $children) : DatePart
|
||||
{
|
||||
return new DatePart($this->logger, $this->charsetConverter, $children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new ParameterPart.
|
||||
*
|
||||
* @param HeaderPart[] $nameParts
|
||||
*/
|
||||
public function newParameterPart(array $nameParts, ContainerPart $valuePart) : ParameterPart
|
||||
{
|
||||
return new ParameterPart($this->logger, $this->charsetConverter, $nameParts, $valuePart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new ReceivedPart.
|
||||
*
|
||||
* @param HeaderPart[] $children
|
||||
*/
|
||||
public function newReceivedPart(string $name, array $children) : ReceivedPart
|
||||
{
|
||||
return new ReceivedPart($this->logger, $this->charsetConverter, $name, $children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a new ReceivedDomainPart.
|
||||
*
|
||||
* @param HeaderPart[] $children
|
||||
*/
|
||||
public function newReceivedDomainPart(string $name, array $children) : ReceivedDomainPart
|
||||
{
|
||||
return new ReceivedDomainPart(
|
||||
$this->logger,
|
||||
$this->charsetConverter,
|
||||
$name,
|
||||
$children
|
||||
);
|
||||
}
|
||||
}
|
||||
109
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/MimeToken.php
vendored
Normal file
109
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/MimeToken.php
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Represents a single mime header part token, with the possibility of it being
|
||||
* MIME-Encoded as per RFC-2047.
|
||||
*
|
||||
* MimeToken automatically decodes the value if it's encoded.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class MimeToken extends Token
|
||||
{
|
||||
/**
|
||||
* @var string regex pattern matching a mime-encoded part
|
||||
*/
|
||||
public const MIME_PART_PATTERN = '=\?[^?=]+\?[QBqb]\?[^\?]+\?=';
|
||||
|
||||
/**
|
||||
* @var string regex pattern used when parsing parameterized headers
|
||||
*/
|
||||
public const MIME_PART_PATTERN_NO_QUOTES = '=\?[^\?=]+\?[QBqb]\?[^\?"]+\?=';
|
||||
|
||||
/**
|
||||
* @var ?string the language code if any, or null otherwise
|
||||
*/
|
||||
protected ?string $language = null;
|
||||
|
||||
/**
|
||||
* @var ?string the charset if any, or null otherwise
|
||||
*/
|
||||
protected ?string $charset = null;
|
||||
|
||||
public function __construct(LoggerInterface $logger, MbWrapper $charsetConverter, string $value)
|
||||
{
|
||||
parent::__construct($logger, $charsetConverter, $value);
|
||||
$this->value = $this->decodeMime(\preg_replace('/\r|\n/', '', $this->value));
|
||||
$pattern = self::MIME_PART_PATTERN;
|
||||
$this->canIgnoreSpacesBefore = (bool) \preg_match("/^\s*{$pattern}|\s+/", $this->rawValue);
|
||||
$this->canIgnoreSpacesAfter = (bool) \preg_match("/{$pattern}\s*|\s+\$/", $this->rawValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and replaces mime parts with their values.
|
||||
*
|
||||
* The method splits the token value into an array on mime-part-patterns,
|
||||
* either replacing a mime part with its value by calling iconv_mime_decode
|
||||
* or converts the encoding on the text part by calling convertEncoding.
|
||||
*/
|
||||
protected function decodeMime(string $value) : string
|
||||
{
|
||||
if (\preg_match('/^=\?([A-Za-z\-_0-9]+)\*?([A-Za-z\-_0-9]+)?\?([QBqb])\?([^\?]*)\?=$/', $value, $matches)) {
|
||||
return $this->decodeMatchedEntity($matches);
|
||||
}
|
||||
return $this->convertEncoding($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a matched mime entity part into a string and returns it, after
|
||||
* adding the string into the languages array.
|
||||
*
|
||||
* @param string[] $matches
|
||||
*/
|
||||
private function decodeMatchedEntity(array $matches) : string
|
||||
{
|
||||
$body = $matches[4];
|
||||
if (\strtoupper($matches[3]) === 'Q') {
|
||||
$body = \quoted_printable_decode(\str_replace('_', '=20', $body));
|
||||
} else {
|
||||
$body = \base64_decode($body);
|
||||
}
|
||||
$this->charset = $matches[1];
|
||||
$this->language = (!empty($matches[2])) ? $matches[2] : null;
|
||||
if ($this->charset !== null) {
|
||||
return $this->convertEncoding($body, $this->charset, true);
|
||||
}
|
||||
return $this->convertEncoding($body, 'ISO-8859-1', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the language code for the mime part.
|
||||
*/
|
||||
public function getLanguage() : ?string
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset for the encoded part.
|
||||
*/
|
||||
public function getCharset() : ?string
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
public function getRawValue() : string
|
||||
{
|
||||
return $this->rawValue;
|
||||
}
|
||||
}
|
||||
27
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/MimeTokenPartFactory.php
vendored
Normal file
27
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/MimeTokenPartFactory.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\IHeaderPart;
|
||||
|
||||
/**
|
||||
* Extends HeaderPartFactory to instantiate MimeTokens for its
|
||||
* newInstance method.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class MimeTokenPartFactory extends HeaderPartFactory
|
||||
{
|
||||
/**
|
||||
* Creates and returns a MimeToken.
|
||||
*/
|
||||
public function newInstance(string $value) : IHeaderPart
|
||||
{
|
||||
return $this->newMimeToken($value);
|
||||
}
|
||||
}
|
||||
65
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/NameValuePart.php
vendored
Normal file
65
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/NameValuePart.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Represents a name/value pair part of a header.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class NameValuePart extends ContainerPart
|
||||
{
|
||||
/**
|
||||
* @var string the name of the part
|
||||
*/
|
||||
protected string $name;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
array $nameParts,
|
||||
array $valueParts
|
||||
) {
|
||||
ErrorBag::__construct($logger);
|
||||
$this->charsetConverter = $charsetConverter;
|
||||
$this->name = (!empty($nameParts)) ? $this->getNameFromParts($nameParts) : '';
|
||||
parent::__construct($logger, $charsetConverter, $valueParts);
|
||||
\array_unshift($this->children, ...$nameParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the string 'name' representation of this part constructed from
|
||||
* the child name parts passed to it.
|
||||
*
|
||||
* @param HeaderParts[] $parts
|
||||
*/
|
||||
protected function getNameFromParts(array $parts) : string
|
||||
{
|
||||
return \array_reduce($this->filterIgnoredSpaces($parts), fn ($c, $p) => $c . $p->getValue(), '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the name/value part.
|
||||
*/
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
protected function validate() : void
|
||||
{
|
||||
if ($this->value === '') {
|
||||
$this->addError('NameValuePart value is empty', LogLevel::NOTICE);
|
||||
}
|
||||
}
|
||||
}
|
||||
119
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/ParameterPart.php
vendored
Normal file
119
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/ParameterPart.php
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Represents a name/value parameter part of a header.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ParameterPart extends NameValuePart
|
||||
{
|
||||
/**
|
||||
* @var string the RFC-1766 language tag if set.
|
||||
*/
|
||||
protected ?string $language = null;
|
||||
|
||||
/**
|
||||
* @var string charset of content if set.
|
||||
*/
|
||||
protected ?string $charset = null;
|
||||
|
||||
/**
|
||||
* @var int the zero-based index of the part if part of a 'continuation' in
|
||||
* an RFC-2231 split parameter.
|
||||
*/
|
||||
protected ?int $index = null;
|
||||
|
||||
/**
|
||||
* @var bool true if the part is an RFC-2231 encoded part, and the value
|
||||
* needs to be decoded.
|
||||
*/
|
||||
protected bool $encoded = false;
|
||||
|
||||
/**
|
||||
* @param HeaderPart[] $nameParts
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
array $nameParts,
|
||||
ContainerPart $valuePart
|
||||
) {
|
||||
parent::__construct($logger, $charsetConverter, $nameParts, $valuePart->children);
|
||||
}
|
||||
|
||||
protected function getNameFromParts(array $parts) : string
|
||||
{
|
||||
$name = parent::getNameFromParts($parts);
|
||||
if (\preg_match('~^\s*([^\*]+)\*(\d*)(\*)?$~', $name, $matches)) {
|
||||
$name = $matches[1];
|
||||
$this->index = ($matches[2] !== '') ? (int) ($matches[2]) : null;
|
||||
$this->encoded = (($matches[2] === '') || !empty($matches[3]));
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
protected function decodePartValue(string $value, ?string $charset = null) : string
|
||||
{
|
||||
if ($charset !== null) {
|
||||
return $this->convertEncoding(\rawurldecode($value), $charset, true);
|
||||
}
|
||||
return $this->convertEncoding(\rawurldecode($value));
|
||||
}
|
||||
|
||||
protected function getValueFromParts(array $parts) : string
|
||||
{
|
||||
$value = parent::getValueFromParts($parts);
|
||||
if ($this->encoded && \preg_match('~^([^\']*)\'?([^\']*)\'?(.*)$~', $value, $matches)) {
|
||||
$this->charset = (!empty($matches[1]) && !empty($matches[3])) ? $matches[1] : $this->charset;
|
||||
$this->language = (!empty($matches[2])) ? $matches[2] : $this->language;
|
||||
$ev = (empty($matches[3])) ? $matches[1] : $matches[3];
|
||||
// only if it's not part of a SplitParameterPart
|
||||
if ($this->index === null) {
|
||||
// subsequent parts are decoded as a SplitParameterPart since only
|
||||
// the first part are supposed to have charset/language fields
|
||||
return $this->decodePartValue($ev, $this->charset);
|
||||
}
|
||||
return $ev;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset if the part is an RFC-2231 part with a charset set.
|
||||
*/
|
||||
public function getCharset() : ?string
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RFC-1766 (or subset) language tag, if the parameter is an
|
||||
* RFC-2231 part with a language tag set.
|
||||
*
|
||||
* @return ?string the language if set, or null if not
|
||||
*/
|
||||
public function getLanguage() : ?string
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
public function isUrlEncoded() : bool
|
||||
{
|
||||
return $this->encoded;
|
||||
}
|
||||
|
||||
public function getIndex() : ?int
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
}
|
||||
46
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/QuotedLiteralPart.php
vendored
Normal file
46
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/QuotedLiteralPart.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
/**
|
||||
* A quoted literal header string part. The value of the part is stripped of CR
|
||||
* and LF characters, and whitespace between two adjacent MimeTokens is removed.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class QuotedLiteralPart extends ContainerPart
|
||||
{
|
||||
/**
|
||||
* Strips spaces found between two adjacent MimeToken parts.
|
||||
* Other whitespace is returned as-is.
|
||||
*
|
||||
* @param HeaderPart[] $parts
|
||||
* @return HeaderPart[]
|
||||
*/
|
||||
protected function filterIgnoredSpaces(array $parts) : array
|
||||
{
|
||||
$filtered = \array_reduce(
|
||||
\array_keys($parts),
|
||||
function($carry, $key) use ($parts) {
|
||||
$cur = $parts[$key];
|
||||
$last = ($carry !== null) ? \end($carry) : null;
|
||||
$next = (count($parts) > $key + 1) ? $parts[$key + 1] : null;
|
||||
if ($last !== null && $next !== null && $cur->isSpace && (
|
||||
$last->canIgnoreSpacesAfter
|
||||
&& $next->canIgnoreSpacesBefore
|
||||
&& $last instanceof MimeToken
|
||||
&& $next instanceof MimeToken
|
||||
)) {
|
||||
return $carry;
|
||||
}
|
||||
return \array_merge($carry ?? [], [$cur]);
|
||||
}
|
||||
);
|
||||
return $filtered;
|
||||
}
|
||||
}
|
||||
103
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/ReceivedDomainPart.php
vendored
Normal file
103
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/ReceivedDomainPart.php
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Holds extra information about a parsed Received header part, for FROM and BY
|
||||
* parts, namely: ehlo name, hostname, and address.
|
||||
*
|
||||
* The parsed parts would be mapped as follows:
|
||||
*
|
||||
* FROM ehlo name (hostname [address]), for example: FROM computer (domain.com
|
||||
* [1.2.3.4]) would contain "computer" for getEhloName(), domain.com for
|
||||
* getHostname and 1.2.3.4 for getAddress().
|
||||
*
|
||||
* This doesn't change if the ehlo name is an address, it is still returned in
|
||||
* getEhloName(), and not in getAddress(). Additionally square brackets are not
|
||||
* stripped from getEhloName() if its an address. For example: "FROM [1.2.3.4]"
|
||||
* would return "[1.2.3.4]" in a call to getEhloName().
|
||||
*
|
||||
* For further information on how the header's parsed, check the documentation
|
||||
* for {@see \ZBateson\MailMimeParser\Header\Consumer\Received\DomainConsumer}.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ReceivedDomainPart extends ReceivedPart
|
||||
{
|
||||
/**
|
||||
* @var string The name used to identify the server in the EHLO line.
|
||||
*/
|
||||
protected ?string $ehloName = null;
|
||||
|
||||
/**
|
||||
* @var string The hostname.
|
||||
*/
|
||||
protected ?string $hostname = null;
|
||||
|
||||
/**
|
||||
* @var string The address.
|
||||
*/
|
||||
protected ?string $address = null;
|
||||
|
||||
/**
|
||||
* @param HeaderPart[] $children
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
string $name,
|
||||
array $children
|
||||
) {
|
||||
parent::__construct($logger, $charsetConverter, $name, $children);
|
||||
|
||||
$this->ehloName = ($this->value !== '') ? $this->value : null;
|
||||
$cps = $this->getComments();
|
||||
$commentPart = (!empty($cps)) ? $cps[0] : null;
|
||||
|
||||
$pattern = '~^(\[(IPv[64])?(?P<addr1>[a-f\d\.\:]+)\])?\s*(helo=)?(?P<name>[a-z0-9\-]+[a-z0-9\-\.]+)?\s*(\[(IPv[64])?(?P<addr2>[a-f\d\.\:]+)\])?$~i';
|
||||
if ($commentPart !== null && \preg_match($pattern, $commentPart->getComment(), $matches)) {
|
||||
$this->value .= ' (' . $commentPart->getComment() . ')';
|
||||
$this->hostname = (!empty($matches['name'])) ? $matches['name'] : null;
|
||||
$this->address = (!empty($matches['addr1'])) ? $matches['addr1'] : ((!empty($matches['addr2'])) ? $matches['addr2'] : null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name used to identify the server in the first part of the
|
||||
* extended-domain line.
|
||||
*
|
||||
* Note that this is not necessarily the name used in the EHLO line to an
|
||||
* SMTP server, since implementations differ so much, not much can be
|
||||
* guaranteed except the position it was parsed in.
|
||||
*/
|
||||
public function getEhloName() : ?string
|
||||
{
|
||||
return $this->ehloName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname of the server, or whatever string in the hostname
|
||||
* position when parsing (but never an address).
|
||||
*/
|
||||
public function getHostname() : ?string
|
||||
{
|
||||
return $this->hostname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the server, or whatever string that looks like an
|
||||
* address in the address position when parsing (but never a hostname).
|
||||
*/
|
||||
public function getAddress() : ?string
|
||||
{
|
||||
return $this->address;
|
||||
}
|
||||
}
|
||||
37
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/ReceivedPart.php
vendored
Normal file
37
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/ReceivedPart.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Represents one parameter in a parsed 'Received' header, e.g. the FROM or VIA
|
||||
* part.
|
||||
*
|
||||
* Note that FROM and BY actually get parsed into a sub-class,
|
||||
* ReceivedDomainPart which keeps track of other sub-parts that can be parsed
|
||||
* from them.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ReceivedPart extends NameValuePart
|
||||
{
|
||||
/**
|
||||
* @param HeaderPart[] $children
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
string $name,
|
||||
array $children
|
||||
) {
|
||||
parent::__construct($logger, $charsetConverter, [], $children);
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
102
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/SplitParameterPart.php
vendored
Normal file
102
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/SplitParameterPart.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Holds a running value for an RFC-2231 split header parameter.
|
||||
*
|
||||
* ParameterConsumer creates SplitParameterTokens when a split header parameter
|
||||
* is first found, and adds subsequent split parts to an already created one if
|
||||
* the parameter name matches.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class SplitParameterPart extends ParameterPart
|
||||
{
|
||||
/**
|
||||
* @var HeaderPartFactory used to create combined MimeToken parts.
|
||||
*/
|
||||
protected HeaderPartFactory $partFactory;
|
||||
|
||||
/**
|
||||
* Initializes a SplitParameterToken.
|
||||
*
|
||||
* @param ParameterPart[] $children
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
HeaderPartFactory $headerPartFactory,
|
||||
array $children
|
||||
) {
|
||||
$this->partFactory = $headerPartFactory;
|
||||
NameValuePart::__construct($logger, $charsetConverter, [$children[0]], $children);
|
||||
$this->children = $children;
|
||||
}
|
||||
|
||||
protected function getNameFromParts(array $parts) : string
|
||||
{
|
||||
return $parts[0]->getName();
|
||||
}
|
||||
|
||||
private function getMimeTokens(string $value) : array
|
||||
{
|
||||
$pattern = MimeToken::MIME_PART_PATTERN;
|
||||
// remove whitespace between two adjacent mime encoded parts
|
||||
$normed = \preg_replace("/($pattern)\\s+(?=$pattern)/", '$1', $value);
|
||||
// with PREG_SPLIT_DELIM_CAPTURE, matched and unmatched parts are returned
|
||||
$aMimeParts = \preg_split("/($pattern)/", $normed, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
return \array_map(
|
||||
fn ($p) => (\preg_match("/$pattern/", $p)) ? $this->partFactory->newMimeToken($p) : $this->partFactory->newToken($p, true, true),
|
||||
$aMimeParts
|
||||
);
|
||||
}
|
||||
|
||||
private function combineAdjacentUnencodedParts(array $parts) : array
|
||||
{
|
||||
$runningValue = '';
|
||||
$returnedParts = [];
|
||||
foreach ($parts as $part) {
|
||||
if (!$part->encoded) {
|
||||
$runningValue .= $part->value;
|
||||
continue;
|
||||
}
|
||||
if (!empty($runningValue)) {
|
||||
$returnedParts = \array_merge($returnedParts, $this->getMimeTokens($runningValue));
|
||||
$runningValue = '';
|
||||
}
|
||||
$returnedParts[] = $part;
|
||||
}
|
||||
if (!empty($runningValue)) {
|
||||
$returnedParts = \array_merge($returnedParts, $this->getMimeTokens($runningValue));
|
||||
}
|
||||
return $returnedParts;
|
||||
}
|
||||
|
||||
protected function getValueFromParts(array $parts) : string
|
||||
{
|
||||
$sorted = $parts;
|
||||
\usort($sorted, fn ($a, $b) => $a->index <=> $b->index);
|
||||
|
||||
$first = $sorted[0];
|
||||
$this->language = $first->language;
|
||||
$charset = $this->charset = $first->charset;
|
||||
|
||||
$combined = $this->combineAdjacentUnencodedParts($sorted);
|
||||
|
||||
return \implode('', \array_map(
|
||||
fn ($p) => ($p instanceof ParameterPart && $p->encoded)
|
||||
? $this->decodePartValue($p->getValue(), ($p->charset === null) ? $charset : $p->charset)
|
||||
: $p->getValue(),
|
||||
$combined
|
||||
));
|
||||
}
|
||||
}
|
||||
40
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/SubjectToken.php
vendored
Normal file
40
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/SubjectToken.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Specialized token for subjects that preserves whitespace, except for new
|
||||
* lines.
|
||||
*
|
||||
* New lines are either discarded if followed by a whitespace as should happen
|
||||
* with folding whitespace, or replaced by a single space character if somehow
|
||||
* aren't followed by whitespace.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class SubjectToken extends Token
|
||||
{
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
string $value
|
||||
) {
|
||||
parent::__construct($logger, $charsetConverter, $value, true);
|
||||
$this->value = \preg_replace(['/(\r|\n)+(\s)\s*/', '/(\r|\n)+/'], ['$2', ' '], $value);
|
||||
$this->isSpace = (\preg_match('/^\s*$/m', $this->value) === 1);
|
||||
$this->canIgnoreSpacesBefore = $this->canIgnoreSpacesAfter = $this->isSpace;
|
||||
}
|
||||
|
||||
public function getValue() : string
|
||||
{
|
||||
return $this->convertEncoding($this->value);
|
||||
}
|
||||
}
|
||||
66
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/Token.php
vendored
Normal file
66
plugins/vendor/zbateson/mail-mime-parser/src/Header/Part/Token.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header\Part;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Holds a string value token that will require additional processing by a
|
||||
* consumer prior to returning to a client.
|
||||
*
|
||||
* A Token is meant to hold a value for further processing -- for instance when
|
||||
* consuming an address list header (like From or To) -- before it's known what
|
||||
* type of IHeaderPart it is (could be an email address, could be a name, or
|
||||
* could be a group.)
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class Token extends HeaderPart
|
||||
{
|
||||
/**
|
||||
* @var string the raw value of the part.
|
||||
*/
|
||||
protected string $rawValue;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MbWrapper $charsetConverter,
|
||||
string $value,
|
||||
bool $isLiteral = false,
|
||||
bool $preserveSpaces = false
|
||||
) {
|
||||
parent::__construct($logger, $charsetConverter, $value);
|
||||
$this->rawValue = $value;
|
||||
if (!$isLiteral) {
|
||||
$this->value = \preg_replace(['/(\r|\n)+(\s)/', '/(\r|\n)+/'], ['$2', ' '], $value);
|
||||
if (!$preserveSpaces) {
|
||||
$this->value = \preg_replace('/^\s+$/m', ' ', $this->value);
|
||||
}
|
||||
}
|
||||
$this->isSpace = ($this->value === '' || (!$isLiteral && \preg_match('/^\s*$/m', $this->value) === 1));
|
||||
$this->canIgnoreSpacesBefore = $this->canIgnoreSpacesAfter = $this->isSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part's representative value after any necessary processing
|
||||
* has been performed. For the raw value, call getRawValue().
|
||||
*/
|
||||
public function getValue() : string
|
||||
{
|
||||
return $this->convertEncoding($this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part's raw value.
|
||||
*/
|
||||
public function getRawValue() : string
|
||||
{
|
||||
return $this->rawValue;
|
||||
}
|
||||
}
|
||||
235
plugins/vendor/zbateson/mail-mime-parser/src/Header/ReceivedHeader.php
vendored
Normal file
235
plugins/vendor/zbateson/mail-mime-parser/src/Header/ReceivedHeader.php
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use DateTime;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\ReceivedConsumerService;
|
||||
use ZBateson\MailMimeParser\Header\Part\DatePart;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* Represents a Received header.
|
||||
*
|
||||
* The returned header value (as returned by a call to {@see
|
||||
* ReceivedHeader::getValue()}) for a
|
||||
* ReceivedHeader is the same as the raw value (as returned by a call to
|
||||
* {@see ReceivedHeader::getRawValue()}) since the header doesn't have a single
|
||||
* 'value' to consider 'the value'.
|
||||
*
|
||||
* The parsed parts of a Received header can be accessed as parameters. To
|
||||
* check if a part exists, call {@see ReceivedHeader::hasParameter()} with the
|
||||
* name of the part, for example: ```php $header->hasParameter('from') ``` or
|
||||
* ```php $header->hasParameter('id') ```. The value of the part can be obtained
|
||||
* by calling {@see ReceivedHeader::getValueFor()}, for example
|
||||
* ```php $header->getValueFor('with'); ```.
|
||||
*
|
||||
* Additional parsing is performed on the "FROM" and "BY" parts of a received
|
||||
* header in an attempt to extract the self-identified name of the server, its
|
||||
* hostname, and its address (depending on what's included). These can be
|
||||
* accessed directly from the ReceivedHeader object by calling one of the
|
||||
* following methods:
|
||||
*
|
||||
* o {@see ReceivedHeader::getFromName()} -- the name portion of the FROM part
|
||||
* o {@see ReceivedHeader::getFromHostname()} -- the hostname of the FROM part
|
||||
* o {@see ReceivedHeader::getFromAddress()} -- the adddress portion of the FROM
|
||||
* part
|
||||
* o {@see ReceivedHeader::getByName()} -- same as getFromName, but for the BY
|
||||
* part, and etc... below
|
||||
* o {@see ReceivedHeader::getByHostname()}
|
||||
* o {@see ReceivedHeader::getByAddress()}
|
||||
*
|
||||
* The parsed parts of the FROM and BY parts are determined as follows:
|
||||
*
|
||||
* o Anything outside and before a parenthesized expression is considered "the
|
||||
* name", for example "FROM AlainDeBotton", "AlainDeBotton" would be the name,
|
||||
* but also if the name is an address, but exists outside the parenthesized
|
||||
* expression, it's still considered "the name". For example:
|
||||
* "From [1.2.3.4]", getFromName would return "[1.2.3.4]".
|
||||
* o A parenthesized expression MUST match what looks like either a domain name
|
||||
* on its own, or a domain name and an address. Otherwise the parenthesized
|
||||
* expression is considered a comment, and not parsed into hostname and
|
||||
* address. The rules are defined loosely because many implementations differ
|
||||
* in how strictly they follow the standard. For a domain, it's enough that
|
||||
* the expression starts with any alphanumeric character and contains at least
|
||||
* one '.', followed by any number of '.', '-' and alphanumeric characters.
|
||||
* The address portion must be surrounded in square brackets, and contain any
|
||||
* sequence of '.', ':', numbers, and characters 'a' through 'f'. In addition
|
||||
* the string 'ipv6' may start the expression (for instance, '[ipv6:::1]'
|
||||
* would be valid). A port number may also be considered valid as part of the
|
||||
* address, for example: [1.2.3.4:3231]. No additional validation on the
|
||||
* address is done, and so an invalid address such as '....' could be
|
||||
* returned, so users using the 'address' header are encouraged to validate it
|
||||
* before using it. The square brackets are parsed out of the returned
|
||||
* address, so the value returned by getFromAddress() would be "2.2.2.2", not
|
||||
* "[2.2.2.2]".
|
||||
*
|
||||
* The date/time stamp can be accessed as a DateTime object by calling
|
||||
* {@see ReceivedHeader::getDateTime()}.
|
||||
*
|
||||
* Parsed comments can be accessed by calling {@see
|
||||
* ReceivedHeader::getComments()}. Some implementations may include connection
|
||||
* encryption information or other details in non-standardized comments.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ReceivedHeader extends ParameterHeader
|
||||
{
|
||||
/**
|
||||
* @var DateTime the date/time stamp in the header.
|
||||
*/
|
||||
private ?DateTime $date = null;
|
||||
|
||||
/**
|
||||
* @var bool set to true once $date has been looked for
|
||||
*/
|
||||
private bool $dateSet = false;
|
||||
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $value,
|
||||
?LoggerInterface $logger = null,
|
||||
?ReceivedConsumerService $consumerService = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
AbstractHeader::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$consumerService ?? $di->get(ReceivedConsumerService::class),
|
||||
$name,
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw, unparsed header value, same as {@see
|
||||
* ReceivedHeader::getRawValue()}.
|
||||
*/
|
||||
public function getValue() : ?string
|
||||
{
|
||||
return $this->rawValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name identified in the FROM part of the header or null if not
|
||||
* defined or the format wasn't parsed.
|
||||
*
|
||||
* The returned value may either be a name or an address in the form
|
||||
* "[1.2.3.4]". Validation is not performed on this value, and so whatever
|
||||
* exists in this position is returned -- be it contains spaces, or invalid
|
||||
* characters, etc...
|
||||
*
|
||||
* @return ?string The 'FROM' name.
|
||||
*/
|
||||
public function getFromName() : ?string
|
||||
{
|
||||
return (isset($this->parameters['from'])) ?
|
||||
$this->parameters['from']->getEhloName() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname part of a parenthesized FROM part or null if not
|
||||
* defined or the format wasn't parsed.
|
||||
*
|
||||
* For example, "FROM name (host.name)" would return the string "host.name".
|
||||
* Validation of the hostname is not performed, and the returned value may
|
||||
* not be valid. More details on how the value is parsed and extracted can
|
||||
* be found in the class description for {@see ReceivedHeader}.
|
||||
*
|
||||
* @return ?string The 'FROM' hostname.
|
||||
*/
|
||||
public function getFromHostname() : ?string
|
||||
{
|
||||
return (isset($this->parameters['from'])) ?
|
||||
$this->parameters['from']->getHostname() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address part of a parenthesized FROM part or null if not
|
||||
* defined or the format wasn't parsed.
|
||||
*
|
||||
* For example, "FROM name ([1.2.3.4])" would return the string "1.2.3.4".
|
||||
* Validation of the address is not performed, and the returned value may
|
||||
* not be valid. More details on how the value is parsed and extracted can
|
||||
* be found in the class description for {@see ReceivedHeader}.
|
||||
*
|
||||
* @return ?string The 'FROM' address.
|
||||
*/
|
||||
public function getFromAddress() : ?string
|
||||
{
|
||||
return (isset($this->parameters['from'])) ?
|
||||
$this->parameters['from']->getAddress() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name identified in the BY part of the header or null if not
|
||||
* defined or the format wasn't parsed.
|
||||
*
|
||||
* The returned value may either be a name or an address in the form
|
||||
* "[1.2.3.4]". Validation is not performed on this value, and so whatever
|
||||
* exists in this position is returned -- be it contains spaces, or invalid
|
||||
* characters, etc...
|
||||
*
|
||||
* @return ?string The 'BY' name.
|
||||
*/
|
||||
public function getByName() : ?string
|
||||
{
|
||||
return (isset($this->parameters['by'])) ?
|
||||
$this->parameters['by']->getEhloName() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname part of a parenthesized BY part or null if not
|
||||
* defined or the format wasn't parsed.
|
||||
*
|
||||
* For example, "BY name (host.name)" would return the string "host.name".
|
||||
* Validation of the hostname is not performed, and the returned value may
|
||||
* not be valid. More details on how the value is parsed and extracted can
|
||||
* be found in the class description for {@see ReceivedHeader}.
|
||||
*
|
||||
* @return ?string The 'BY' hostname.
|
||||
*/
|
||||
public function getByHostname() : ?string
|
||||
{
|
||||
return (isset($this->parameters['by'])) ?
|
||||
$this->parameters['by']->getHostname() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address part of a parenthesized BY part or null if not
|
||||
* defined or the format wasn't parsed.
|
||||
*
|
||||
* For example, "BY name ([1.2.3.4])" would return the string "1.2.3.4".
|
||||
* Validation of the address is not performed, and the returned value may
|
||||
* not be valid. More details on how the value is parsed and extracted can
|
||||
* be found in the class description for {@see ReceivedHeader}.
|
||||
*
|
||||
* @return ?string The 'BY' address.
|
||||
*/
|
||||
public function getByAddress() : ?string
|
||||
{
|
||||
return (isset($this->parameters['by'])) ?
|
||||
$this->parameters['by']->getAddress() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date/time stamp for the received header if set, or null
|
||||
* otherwise.
|
||||
*/
|
||||
public function getDateTime() : ?DateTime
|
||||
{
|
||||
if ($this->dateSet === false) {
|
||||
foreach ($this->parts as $part) {
|
||||
if ($part instanceof DatePart) {
|
||||
$this->date = $part->getDateTime();
|
||||
}
|
||||
}
|
||||
$this->dateSet = true;
|
||||
}
|
||||
return $this->date;
|
||||
}
|
||||
}
|
||||
38
plugins/vendor/zbateson/mail-mime-parser/src/Header/SubjectHeader.php
vendored
Normal file
38
plugins/vendor/zbateson/mail-mime-parser/src/Header/SubjectHeader.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Header;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\Consumer\SubjectConsumerService;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* Reads a subject header.
|
||||
*
|
||||
* The subject header is unique in that it doesn't include comments or quoted
|
||||
* parts.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class SubjectHeader extends AbstractHeader
|
||||
{
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $value,
|
||||
?LoggerInterface $logger = null,
|
||||
?SubjectConsumerService $consumerService = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$consumerService ?? $di->get(SubjectConsumerService::class),
|
||||
$name,
|
||||
$value
|
||||
);
|
||||
}
|
||||
}
|
||||
86
plugins/vendor/zbateson/mail-mime-parser/src/IErrorBag.php
vendored
Normal file
86
plugins/vendor/zbateson/mail-mime-parser/src/IErrorBag.php
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Defines an object that may contain a set of errors, and optionally perform
|
||||
* additional validation.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IErrorBag
|
||||
{
|
||||
/**
|
||||
* Returns a context name for the current object to help identify it in
|
||||
* logs.
|
||||
*/
|
||||
public function getErrorLoggingContextName() : string;
|
||||
|
||||
/**
|
||||
* Creates and adds an Error object to this ErrorBag.
|
||||
*/
|
||||
public function addError(string $message, string $psrLogLevel, ?Throwable $exception = null) : static;
|
||||
|
||||
/**
|
||||
* Returns true if this object has an error in its error bag at or above
|
||||
* the passed $minPsrLevel (defaults to ERROR). If $validate is true,
|
||||
* additional validation may be performed.
|
||||
*
|
||||
* The PSR levels are defined in Psr\Log\LogLevel.
|
||||
*/
|
||||
public function hasErrors(bool $validate = false, string $minPsrLevel = LogLevel::ERROR) : bool;
|
||||
|
||||
/**
|
||||
* Returns any local errors this object has at or above the passed PSR log
|
||||
* level in Psr\Log\LogLevel (defaulting to LogLevel::ERROR).
|
||||
*
|
||||
* If $validate is true, additional validation may be performed on the
|
||||
* object to check for errors.
|
||||
*
|
||||
* @return Error[]
|
||||
*/
|
||||
public function getErrors(bool $validate = false, string $minPsrLevel = LogLevel::ERROR) : array;
|
||||
|
||||
/**
|
||||
* Returns true if there are errors on this object, or any IErrorBag child
|
||||
* of this object at or above the passed PSR log level in Psr\Log\LogLevel
|
||||
* (defaulting to LogLevel::ERROR). Note that this will stop after finding
|
||||
* the first error and return, so may be slightly more performant if an
|
||||
* error actually exists over calling getAllErrors if only interested in
|
||||
* whether an error exists.
|
||||
*
|
||||
* Care should be taken using this if the intention is to only 'preview' a
|
||||
* message without parsing it entirely, since this will cause the whole
|
||||
* message to be parsed as it traverses children, and could be slow on
|
||||
* messages with large attachments, etc...
|
||||
*
|
||||
* If $validate is true, additional validation may be performed to check for
|
||||
* errors.
|
||||
*/
|
||||
public function hasAnyErrors(bool $validate = false, string $minPsrLevel = LogLevel::ERROR) : bool;
|
||||
|
||||
/**
|
||||
* Returns any errors on this object, and all IErrorBag children of this
|
||||
* object at or above the passed PSR log level from Psr\Log\LogLevel
|
||||
* (defaulting to LogLevel::ERROR).
|
||||
*
|
||||
* Care should be taken using this if the intention is to only 'preview' a
|
||||
* message without parsing it entirely, since this will cause the whole
|
||||
* message to be parsed as it traverses children, and could be slow on
|
||||
* messages with large attachments, etc...
|
||||
*
|
||||
* If $validate is true, additional validation may be performed on children
|
||||
* to check for errors.
|
||||
*
|
||||
* @return Error[]
|
||||
*/
|
||||
public function getAllErrors(bool $validate = false, string $minPsrLevel = LogLevel::ERROR) : array;
|
||||
}
|
||||
433
plugins/vendor/zbateson/mail-mime-parser/src/IMessage.php
vendored
Normal file
433
plugins/vendor/zbateson/mail-mime-parser/src/IMessage.php
vendored
Normal file
@@ -0,0 +1,433 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use ZBateson\MailMimeParser\Message\IMessagePart;
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
|
||||
/**
|
||||
* An interface representing an email message.
|
||||
*
|
||||
* Defines an interface to retrieve content, attachments and other parts of an
|
||||
* email message.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IMessage extends IMimePart
|
||||
{
|
||||
/**
|
||||
* Returns the subject of the message, retrieved from the 'Subject' header,
|
||||
* or null if the message has none set.
|
||||
*/
|
||||
public function getSubject() : ?string;
|
||||
|
||||
/**
|
||||
* Returns the inline text/plain IMessagePart for a message.
|
||||
*
|
||||
* If the message contains more than one text/plain 'inline' part, the
|
||||
* default behavior is to return the first part. Additional parts can be
|
||||
* returned by passing a 0-based index.
|
||||
*
|
||||
* If there are no inline text/plain parts in this message, null is
|
||||
* returned.
|
||||
*
|
||||
* @see IMessage::getTextPartCount() to get a count of text parts.
|
||||
* @see IMessage::getTextStream() to get the text content stream directly.
|
||||
* @see IMessage::getTextContent() to get the text content in a string.
|
||||
* @see IMessage::getHtmlPart() to get the HTML part(s).
|
||||
* @see IMessage::getHtmlPartCount() to get a count of html parts.
|
||||
* @param int $index Optional index of part to return.
|
||||
*/
|
||||
public function getTextPart(int $index = 0) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Returns the number of inline text/plain parts this message contains.
|
||||
*
|
||||
* @see IMessage::getTextPart() to get the text part(s).
|
||||
* @see IMessage::getHtmlPart() to get the HTML part(s).
|
||||
* @see IMessage::getHtmlPartCount() to get a count of html parts.
|
||||
*/
|
||||
public function getTextPartCount() : int;
|
||||
|
||||
/**
|
||||
* Returns the inline text/html IMessagePart for a message.
|
||||
*
|
||||
* If the message contains more than one text/html 'inline' part, the
|
||||
* default behavior is to return the first part. Additional parts can be
|
||||
* returned by passing a 0-based index.
|
||||
*
|
||||
* If there are no inline text/html parts in this message, null is
|
||||
* returned.
|
||||
*
|
||||
* @see IMessage::getHtmlStream() to get the html content stream directly.
|
||||
* @see IMessage::getHtmlStream() to get the html content in a string.
|
||||
* @see IMessage::getTextPart() to get the text part(s).
|
||||
* @see IMessage::getTextPartCount() to get a count of text parts.
|
||||
* @see IMessage::getHtmlPartCount() to get a count of html parts.
|
||||
* @param int $index Optional index of part to return.
|
||||
*/
|
||||
public function getHtmlPart(int $index = 0) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Returns the number of inline text/html parts this message contains.
|
||||
*
|
||||
* @see IMessage::getTextPart() to get the text part(s).
|
||||
* @see IMessage::getTextPartCount() to get a count of text parts.
|
||||
* @see IMessage::getHtmlPart() to get the HTML part(s).
|
||||
*/
|
||||
public function getHtmlPartCount() : int;
|
||||
|
||||
/**
|
||||
* Returns a Psr7 Stream for the 'inline' text/plain content.
|
||||
*
|
||||
* If the message contains more than one text/plain 'inline' part, the
|
||||
* default behavior is to return the first part. The streams for additional
|
||||
* parts can be returned by passing a 0-based index.
|
||||
*
|
||||
* If a part at the passed index doesn't exist, null is returned.
|
||||
*
|
||||
* @see IMessage::getTextPart() to get the text part(s).
|
||||
* @see IMessage::getTextContent() to get the text content in a string.
|
||||
* @param int $index Optional 0-based index of inline text part stream.
|
||||
* @param string $charset Optional charset to encode the stream with.
|
||||
*/
|
||||
public function getTextStream(int $index = 0, string $charset = MailMimeParser::DEFAULT_CHARSET) : ?StreamInterface;
|
||||
|
||||
/**
|
||||
* Returns the content of the inline text/plain part as a string.
|
||||
*
|
||||
* If the message contains more than one text/plain 'inline' part, the
|
||||
* default behavior is to return the first part. The content for additional
|
||||
* parts can be returned by passing a 0-based index.
|
||||
*
|
||||
* If a part at the passed index doesn't exist, null is returned.
|
||||
*
|
||||
* @see IMessage::getTextPart() to get the text part(s).
|
||||
* @see IMessage::getTextStream() to get the text content stream directly.
|
||||
* @param int $index Optional 0-based index of inline text part content.
|
||||
* @param string $charset Optional charset for the returned string to be
|
||||
* encoded in.
|
||||
*/
|
||||
public function getTextContent(int $index = 0, string $charset = MailMimeParser::DEFAULT_CHARSET) : ?string;
|
||||
|
||||
/**
|
||||
* Returns a Psr7 Stream for the 'inline' text/html content.
|
||||
*
|
||||
* If the message contains more than one text/html 'inline' part, the
|
||||
* default behavior is to return the first part. The streams for additional
|
||||
* parts can be returned by passing a 0-based index.
|
||||
*
|
||||
* If a part at the passed index doesn't exist, null is returned.
|
||||
*
|
||||
* @see IMessage::getHtmlPart() to get the html part(s).
|
||||
* @see IMessage::getHtmlContent() to get the html content in a string.
|
||||
* @param int $index Optional 0-based index of inline html part stream.
|
||||
* @param string $charset Optional charset to encode the stream with.
|
||||
*/
|
||||
public function getHtmlStream(int $index = 0, string $charset = MailMimeParser::DEFAULT_CHARSET) : ?StreamInterface;
|
||||
|
||||
/**
|
||||
* Returns the content of the inline text/html part as a string.
|
||||
*
|
||||
* If the message contains more than one text/html 'inline' part, the
|
||||
* default behavior is to return the first part. The content for additional
|
||||
* parts can be returned by passing a 0-based index.
|
||||
*
|
||||
* If a part at the passed index doesn't exist, null is returned.
|
||||
*
|
||||
* @see IMessage::getHtmlPart() to get the html part(s).
|
||||
* @see IMessage::getHtmlStream() to get the html content stream directly.
|
||||
* @param int $index Optional 0-based index of inline html part content.
|
||||
* @param string $charset Optional charset for the returned string to be
|
||||
* encoded in.
|
||||
*/
|
||||
public function getHtmlContent(int $index = 0, string $charset = MailMimeParser::DEFAULT_CHARSET) : ?string;
|
||||
|
||||
/**
|
||||
* Sets the text/plain part of the message to the passed $resource, either
|
||||
* creating a new part if one doesn't exist for text/plain, or assigning the
|
||||
* value of $resource to an existing text/plain part.
|
||||
*
|
||||
* The optional $contentTypeCharset parameter is the charset for the
|
||||
* text/plain part's Content-Type, not the charset of the passed $resource.
|
||||
* $resource must be encoded in UTF-8 regardless of the target charset.
|
||||
*
|
||||
* @see IMessage::setHtmlPart() to set the html part
|
||||
* @see IMessage::removeTextPart() to remove a text part
|
||||
* @see IMessage::removeAllTextParts() to remove all text parts
|
||||
* @param string|resource|\Psr\Http\Message\StreamInterface $resource UTF-8
|
||||
* encoded content.
|
||||
* @param string $contentTypeCharset the charset to use as the text/plain
|
||||
* part's content-type header charset value.
|
||||
*/
|
||||
public function setTextPart(mixed $resource, string $contentTypeCharset = 'UTF-8') : static;
|
||||
|
||||
/**
|
||||
* Sets the text/html part of the message to the passed $resource, either
|
||||
* creating a new part if one doesn't exist for text/html, or assigning the
|
||||
* value of $resource to an existing text/html part.
|
||||
*
|
||||
* The optional $contentTypeCharset parameter is the charset for the
|
||||
* text/html part's Content-Type, not the charset of the passed $resource.
|
||||
* $resource must be encoded in UTF-8 regardless of the target charset.
|
||||
*
|
||||
* @see IMessage::setTextPart() to set the text part
|
||||
* @see IMessage::removeHtmlPart() to remove an html part
|
||||
* @see IMessage::removeAllHtmlParts() to remove all html parts
|
||||
* @param string|resource|\Psr\Http\Message\StreamInterface $resource UTF-8
|
||||
* encoded content.
|
||||
* @param string $contentTypeCharset the charset to use as the text/html
|
||||
* part's content-type header charset value.
|
||||
*/
|
||||
public function setHtmlPart(mixed $resource, string $contentTypeCharset = 'UTF-8') : static;
|
||||
|
||||
/**
|
||||
* Removes the text/plain part of the message at the passed index if one
|
||||
* exists (defaults to first part if an index isn't passed).
|
||||
*
|
||||
* Returns true if a part exists at the passed index and has been removed.
|
||||
*
|
||||
* @see IMessage::setTextPart() to set the text part
|
||||
* @see IMessage::removeHtmlPart() to remove an html part
|
||||
* @see IMessage::removeAllTextParts() to remove all text parts
|
||||
* @param int $index Optional 0-based index of inline text part to remove.
|
||||
* @return bool true on success
|
||||
*/
|
||||
public function removeTextPart(int $index = 0) : bool;
|
||||
|
||||
/**
|
||||
* Removes all text/plain inline parts in this message.
|
||||
*
|
||||
* If the message contains a multipart/alternative part, the text parts are
|
||||
* removed from below the alternative part only. If there is only one
|
||||
* remaining part after that, it is moved up, replacing the
|
||||
* multipart/alternative part.
|
||||
*
|
||||
* If the multipart/alternative part further contains a multipart/related
|
||||
* (or mixed) part which holds an inline text part, only parts from that
|
||||
* child multipart are removed, and if the passed
|
||||
* $moveRelatedPartsBelowMessage is true, any non-text parts are moved to be
|
||||
* below the message directly (changing the message into a multipart/mixed
|
||||
* message if need be).
|
||||
*
|
||||
* For more control, call
|
||||
* {@see \ZBateson\MailMimeParser\Message\IMessagePart::removePart()} with
|
||||
* parts you wish to remove.
|
||||
*
|
||||
* @see IMessage::setTextPart() to set the text part
|
||||
* @see IMessage::removeTextPart() to remove a text part
|
||||
* @see IMessage::removeAllHtmlParts() to remove all html parts
|
||||
* @param bool $moveRelatedPartsBelowMessage Optionally pass false to remove
|
||||
* related parts.
|
||||
* @return bool true on success
|
||||
*/
|
||||
public function removeAllTextParts(bool $moveRelatedPartsBelowMessage = true) : bool;
|
||||
|
||||
/**
|
||||
* Removes the text/html part of the message at the passed index if one
|
||||
* exists (defaults to first part if an index isn't passed).
|
||||
*
|
||||
* Returns true if a part exists at the passed index and has been removed.
|
||||
*
|
||||
* @see IMessage::setHtmlPart() to set the html part
|
||||
* @see IMessage::removeTextPart() to remove a text part
|
||||
* @see IMessage::removeAllHtmlParts() to remove all html parts
|
||||
* @param int $index Optional 0-based index of inline html part to remove.
|
||||
* @return bool true on success
|
||||
*/
|
||||
public function removeHtmlPart(int $index = 0) : bool;
|
||||
|
||||
/**
|
||||
* Removes all text/html inline parts in this message.
|
||||
*
|
||||
* If the message contains a multipart/alternative part, the html parts are
|
||||
* removed from below the alternative part only. If there is only one
|
||||
* remaining part after that, it is moved up, replacing the
|
||||
* multipart/alternative part.
|
||||
*
|
||||
* If the multipart/alternative part further contains a multipart/related
|
||||
* (or mixed) part which holds an inline html part, only parts from that
|
||||
* child multipart are removed, and if the passed
|
||||
* $moveRelatedPartsBelowMessage is true, any non-html parts are moved to be
|
||||
* below the message directly (changing the message into a multipart/mixed
|
||||
* message if need be).
|
||||
*
|
||||
* For more control, call
|
||||
* {@see \ZBateson\MailMimeParser\Message\IMessagePart::removePart()} with
|
||||
* parts you wish to remove.
|
||||
*
|
||||
* @see IMessage::setHtmlPart() to set the html part
|
||||
* @see IMessage::removeHtmlPart() to remove an html part
|
||||
* @see IMessage::removeAllTextParts() to remove all html parts
|
||||
* @param bool $moveRelatedPartsBelowMessage Optionally pass false to remove
|
||||
* related parts.
|
||||
* @return bool true on success
|
||||
*/
|
||||
public function removeAllHtmlParts(bool $moveRelatedPartsBelowMessage = true) : bool;
|
||||
|
||||
/**
|
||||
* Returns the attachment part at the given 0-based index, or null if none
|
||||
* is set.
|
||||
*
|
||||
* The method returns all parts other than the main content part for a
|
||||
* non-mime message, and all parts under a mime message except:
|
||||
* - text/plain and text/html parts with a Content-Disposition not set to
|
||||
* 'attachment'
|
||||
* - all multipart/* parts
|
||||
* - any signature part
|
||||
*
|
||||
* @see IMessage::getAllAttachmentParts() to get an array of all parts.
|
||||
* @see IMessage::getAttachmentCount() to get the number of attachments.
|
||||
* @param int $index the 0-based index of the attachment part to return.
|
||||
*/
|
||||
public function getAttachmentPart(int $index) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Returns all attachment parts.
|
||||
*
|
||||
* The method returns all parts other than the main content part for a
|
||||
* non-mime message, and all parts under a mime message except:
|
||||
* - text/plain and text/html parts with a Content-Disposition not set to
|
||||
* 'attachment'
|
||||
* - all multipart/* parts
|
||||
* - any signature part
|
||||
*
|
||||
* @see IMessage::getAttachmentPart() to get a single attachment.
|
||||
* @see IMessage::getAttachmentCount() to get the number of attachments.
|
||||
* @return IMessagePart[]
|
||||
*/
|
||||
public function getAllAttachmentParts() : array;
|
||||
|
||||
/**
|
||||
* Returns the number of attachments available.
|
||||
*
|
||||
* @see IMessage::getAttachmentPart() to get a single attachment.
|
||||
* @see IMessage::getAllAttachmentParts() to get an array of all parts.
|
||||
*/
|
||||
public function getAttachmentCount() : int;
|
||||
|
||||
/**
|
||||
* Adds an attachment part for the passed raw data string, handle, or stream
|
||||
* and given parameters.
|
||||
*
|
||||
* Note that $disposition must be one of 'inline' or 'attachment', and will
|
||||
* default to 'attachment' if a different value is passed.
|
||||
*
|
||||
* @param string|resource|\Psr\Http\Message\StreamInterface $resource the
|
||||
* part's content
|
||||
* @param string $mimeType the mime-type of the attachment
|
||||
* @param string $filename Optional filename (to set relevant header params)
|
||||
* @param string $disposition Optional Content-Disposition value.
|
||||
* @param string $encoding defaults to 'base64', only applied for a mime
|
||||
* email
|
||||
*/
|
||||
public function addAttachmentPart(mixed $resource, string $mimeType, ?string $filename = null, string $disposition = 'attachment', string $encoding = 'base64') : static;
|
||||
|
||||
/**
|
||||
* Adds an attachment part using the passed file.
|
||||
*
|
||||
* Essentially creates a psr7 stream and calls
|
||||
* {@see IMessage::addAttachmentPart}.
|
||||
*
|
||||
* Note that $disposition must be one of 'inline' or 'attachment', and will
|
||||
* default to 'attachment' if a different value is passed.
|
||||
*
|
||||
* @param string $filePath file to attach
|
||||
* @param string $mimeType the mime-type of the attachment
|
||||
* @param string $filename Optional filename (to set relevant header params)
|
||||
* @param string $disposition Optional Content-Disposition value.
|
||||
* @param string $encoding defaults to 'base64', only applied for a mime
|
||||
* email
|
||||
*/
|
||||
public function addAttachmentPartFromFile(string $filePath, string $mimeType, ?string $filename = null, string $disposition = 'attachment', string $encoding = 'base64') : static;
|
||||
|
||||
/**
|
||||
* Removes the attachment at the given index.
|
||||
*
|
||||
* Attachments are considered to be all parts other than the main content
|
||||
* part for a non-mime message, and all parts under a mime message except:
|
||||
* - text/plain and text/html parts with a Content-Disposition not set to
|
||||
* 'attachment'
|
||||
* - all multipart/* parts
|
||||
* - any signature part
|
||||
*/
|
||||
public function removeAttachmentPart(int $index) : static;
|
||||
|
||||
/**
|
||||
* Returns a stream that can be used to read the content part of a signed
|
||||
* message, which can be used to sign an email or verify a signature.
|
||||
*
|
||||
* The method simply returns the stream for the first child. No
|
||||
* verification of whether the message is in fact a signed message is
|
||||
* performed.
|
||||
*
|
||||
* Note that unlike getSignedMessageAsString, getSignedMessageStream doesn't
|
||||
* replace new lines, and before calculating a signature, LFs not preceded
|
||||
* by CR should be replaced with CRLFs.
|
||||
*
|
||||
* @see IMessage::getSignedMessageAsString to get a string with CRLFs
|
||||
* normalized
|
||||
* @return ?StreamInterface null if the message doesn't have any children
|
||||
*/
|
||||
public function getSignedMessageStream() : ?StreamInterface;
|
||||
|
||||
/**
|
||||
* Returns a string containing the entire body of a signed message for
|
||||
* verification or calculating a signature.
|
||||
*
|
||||
* Non-CRLF new lines are replaced to always be CRLF.
|
||||
*
|
||||
* @see IMessage::setAsMultipartSigned to make the message a
|
||||
* multipart/signed message.
|
||||
* @return ?string null if the message doesn't have any children
|
||||
*/
|
||||
public function getSignedMessageAsString() : ?string;
|
||||
|
||||
/**
|
||||
* Returns the signature part of a multipart/signed message or null.
|
||||
*
|
||||
* The signature part is determined to always be the 2nd child of a
|
||||
* multipart/signed message, the first being the 'body'.
|
||||
*
|
||||
* Using the 'protocol' parameter of the Content-Type header is unreliable
|
||||
* in some instances (for instance a difference of x-pgp-signature versus
|
||||
* pgp-signature).
|
||||
*/
|
||||
public function getSignaturePart() : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Turns the message into a multipart/signed message, moving the actual
|
||||
* message into a child part, sets the content-type of the main message to
|
||||
* multipart/signed and adds an empty signature part as well.
|
||||
*
|
||||
* After calling setAsMultipartSigned, call getSignedMessageAsString to
|
||||
* get the normalized string content to be used for calculated the message's
|
||||
* hash.
|
||||
*
|
||||
* @see IMessage::getSignedMessageAsString
|
||||
* @param string $micalg The Message Integrity Check algorithm being used
|
||||
* @param string $protocol The mime-type of the signature body
|
||||
*/
|
||||
public function setAsMultipartSigned(string $micalg, string $protocol) : static;
|
||||
|
||||
/**
|
||||
* Sets the signature body of the message to the passed $body for a
|
||||
* multipart/signed message.
|
||||
*
|
||||
* @param string $body the message's hash
|
||||
*/
|
||||
public function setSignature(string $body) : static;
|
||||
|
||||
/**
|
||||
* Returns the value of the 'Message-ID' header, or null if not set.
|
||||
*
|
||||
* @return string|null the ID.
|
||||
*/
|
||||
public function getMessageId() : ?string;
|
||||
}
|
||||
219
plugins/vendor/zbateson/mail-mime-parser/src/MailMimeParser.php
vendored
Normal file
219
plugins/vendor/zbateson/mail-mime-parser/src/MailMimeParser.php
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser;
|
||||
|
||||
use DI\Container;
|
||||
use DI\ContainerBuilder;
|
||||
use DI\Definition\Source\DefinitionSource;
|
||||
use GuzzleHttp\Psr7\CachingStream;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Parser\MessageParserService;
|
||||
|
||||
/**
|
||||
* Parses a MIME message into an {@see IMessage} object.
|
||||
*
|
||||
* The class sets up the dependency injection container (using PHP-DI) with the
|
||||
* ability to override and/or provide specialized classes. To override you can:
|
||||
*
|
||||
* - Provide an array|string|DefinitionSource to the constructor to affect
|
||||
* classes used on a single instance of MailMimeParser
|
||||
* - Call MailMimeParser::addGlobalContainerDefinition with an
|
||||
* array|string|DefinitionSource to to override it globally on all instances
|
||||
* of MailMimeParser
|
||||
* - Call MailMimeParser::getGlobalContainer(), and use set() to override
|
||||
* individual definitions globally.
|
||||
*
|
||||
* You may also provide a LoggerInterface on the constructor for a single
|
||||
* instance, or override it globally by calling setGlobalLogger. This is the
|
||||
* same as setting up Psr\Log\LoggerInterface with your logger class in a Php-Di
|
||||
* configuration in one of the above methods.
|
||||
*
|
||||
* To invoke the parser, call `parse` on a MailMimeParser object.
|
||||
*
|
||||
* ```php
|
||||
* $parser = new MailMimeParser();
|
||||
* // the resource is attached due to the second parameter being true and will
|
||||
* // be closed when the returned IMessage is destroyed
|
||||
* $message = $parser->parse(fopen('path/to/file.txt'), true);
|
||||
* // use $message here
|
||||
* ```
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class MailMimeParser
|
||||
{
|
||||
/**
|
||||
* @var string the default charset used to encode strings (or string content
|
||||
* like streams) returned by MailMimeParser (for e.g. the string
|
||||
* returned by calling $message->getTextContent()).
|
||||
*/
|
||||
public const DEFAULT_CHARSET = 'UTF-8';
|
||||
|
||||
/**
|
||||
* @var string the default definition file.
|
||||
*/
|
||||
private const DEFAULT_DEFINITIONS_FILE = __DIR__ . '/di_config.php';
|
||||
|
||||
/**
|
||||
* @var Container The instance's dependency injection container.
|
||||
*/
|
||||
protected Container $container;
|
||||
|
||||
/**
|
||||
* @var MessageParserService for parsing messages
|
||||
*/
|
||||
protected MessageParserService $messageParser;
|
||||
|
||||
/**
|
||||
* @var Container The static global container
|
||||
*/
|
||||
private static ?Container $globalContainer = null;
|
||||
|
||||
/**
|
||||
* @var array<array|string|DefinitionSource> an array of global definitions
|
||||
* being used.
|
||||
*/
|
||||
private static array $globalDefinitions = [self::DEFAULT_DEFINITIONS_FILE];
|
||||
|
||||
/**
|
||||
* Returns the default ContainerBuilder with default loaded definitions.
|
||||
*/
|
||||
private static function getGlobalContainerBuilder() : ContainerBuilder
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
foreach (self::$globalDefinitions as $def) {
|
||||
$builder->addDefinitions($def);
|
||||
}
|
||||
return $builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets global configuration for php-di. Overrides all previously set
|
||||
* definitions. You can optionally not use the default MMP definitions file
|
||||
* by passing 'false' to the $useDefaultDefinitionsFile argument.
|
||||
*
|
||||
* @var array<array|string|DefinitionSource> array of definitions
|
||||
*/
|
||||
public static function setGlobalPhpDiConfigurations(array $phpDiConfigs, bool $useDefaultDefinitionsFile = true) : void
|
||||
{
|
||||
self::$globalDefinitions = \array_merge(
|
||||
($useDefaultDefinitionsFile) ? [self::DEFAULT_DEFINITIONS_FILE] : [],
|
||||
$phpDiConfigs
|
||||
);
|
||||
self::$globalContainer = null;
|
||||
}
|
||||
|
||||
public static function addGlobalPhpDiContainerDefinition(array|string|DefinitionSource $phpDiConfig) : void
|
||||
{
|
||||
self::$globalDefinitions[] = $phpDiConfig;
|
||||
self::$globalContainer = null;
|
||||
}
|
||||
|
||||
public static function resetGlobalPhpDiContainerDefinitions() : void
|
||||
{
|
||||
self::$globalDefinitions = [self::DEFAULT_DEFINITIONS_FILE];
|
||||
self::$globalContainer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global php-di container instance.
|
||||
*
|
||||
*/
|
||||
public static function getGlobalContainer() : Container
|
||||
{
|
||||
if (self::$globalContainer === null) {
|
||||
$builder = self::getGlobalContainerBuilder();
|
||||
self::$globalContainer = $builder->build();
|
||||
}
|
||||
return self::$globalContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the provided logger globally.
|
||||
*/
|
||||
public static function setGlobalLogger(LoggerInterface $logger) : void
|
||||
{
|
||||
self::$globalDefinitions[] = [LoggerInterface::class => $logger];
|
||||
self::$globalContainer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide custom php-di configuration to customize dependency injection, or
|
||||
* provide a custom logger for the instance only.
|
||||
*
|
||||
* Note: this only affects instances created through this instance of the
|
||||
* MailMimeParser, or the container itself. Calling 'new MimePart()'
|
||||
* directly for instance, would use the global service locator to setup any
|
||||
* dependencies MimePart needs. This applies to a provided $logger too --
|
||||
* it would only affect instances of objects created through the provided
|
||||
* MailMimeParser.
|
||||
*
|
||||
* Passing false to $useGlobalDefinitions will cause MMP to not use any
|
||||
* global definitions. The default definitions file
|
||||
* MailMimeParser::DEFAULT_DEFINITIONS_FILE will still be added though.
|
||||
*
|
||||
* @see MailMimeParser::setGlobalPhpDiConfiguration() to register
|
||||
* configuration globally.
|
||||
* @see MailMimeParser::setGlobalLogger() to set a global logger
|
||||
*/
|
||||
public function __construct(
|
||||
?LoggerInterface $logger = null,
|
||||
array|string|DefinitionSource|null $phpDiContainerConfig = null,
|
||||
bool $useGlobalDefinitions = true
|
||||
) {
|
||||
if ($phpDiContainerConfig !== null || $logger !== null) {
|
||||
if ($useGlobalDefinitions) {
|
||||
$builder = self::getGlobalContainerBuilder();
|
||||
} else {
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->addDefinitions(self::DEFAULT_DEFINITIONS_FILE);
|
||||
}
|
||||
if ($phpDiContainerConfig !== null) {
|
||||
$builder->addDefinitions($phpDiContainerConfig);
|
||||
}
|
||||
if ($logger !== null) {
|
||||
$builder->addDefinitions([LoggerInterface::class => $logger]);
|
||||
}
|
||||
$this->container = $builder->build();
|
||||
} else {
|
||||
$this->container = self::getGlobalContainer();
|
||||
}
|
||||
$this->messageParser = $this->container->get(MessageParserService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the passed stream handle or string into an {@see IMessage} object
|
||||
* and returns it.
|
||||
*
|
||||
* If the passed $resource is a resource handle or StreamInterface, the
|
||||
* resource must remain open while the returned IMessage object exists.
|
||||
* Pass true as the second argument to have the resource attached to the
|
||||
* IMessage and closed for you when it's destroyed, or pass false to
|
||||
* manually close it if it should remain open after the IMessage object is
|
||||
* destroyed.
|
||||
*
|
||||
* @param resource|StreamInterface|string $resource The resource handle to
|
||||
* the input stream of the mime message, or a string containing a
|
||||
* mime message.
|
||||
* @param bool $attached pass true to have it attached to the returned
|
||||
* IMessage and destroyed with it.
|
||||
*/
|
||||
public function parse(mixed $resource, bool $attached) : IMessage
|
||||
{
|
||||
$stream = Utils::streamFor(
|
||||
$resource,
|
||||
['metadata' => ['mmp-detached-stream' => ($attached !== true)]]
|
||||
);
|
||||
if (!$stream->isSeekable()) {
|
||||
$stream = new CachingStream($stream);
|
||||
}
|
||||
return $this->messageParser->parse($stream);
|
||||
}
|
||||
}
|
||||
342
plugins/vendor/zbateson/mail-mime-parser/src/Message.php
vendored
Normal file
342
plugins/vendor/zbateson/mail-mime-parser/src/Message.php
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
use ZBateson\MailMimeParser\Message\Helper\MultipartHelper;
|
||||
use ZBateson\MailMimeParser\Message\Helper\PrivacyHelper;
|
||||
use ZBateson\MailMimeParser\Message\IMessagePart;
|
||||
use ZBateson\MailMimeParser\Message\MimePart;
|
||||
use ZBateson\MailMimeParser\Message\PartChildrenContainer;
|
||||
use ZBateson\MailMimeParser\Message\PartFilter;
|
||||
use ZBateson\MailMimeParser\Message\PartHeaderContainer;
|
||||
use ZBateson\MailMimeParser\Message\PartStreamContainer;
|
||||
|
||||
/**
|
||||
* An email message.
|
||||
*
|
||||
* The message could represent a simple text email, a multipart message with
|
||||
* children, or a non-mime message containing UUEncoded parts.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class Message extends MimePart implements IMessage
|
||||
{
|
||||
/**
|
||||
* @var MultipartHelper service providing functions for multipart messages.
|
||||
*/
|
||||
private MultipartHelper $multipartHelper;
|
||||
|
||||
/**
|
||||
* @var PrivacyHelper service providing functions for multipart/signed
|
||||
* messages.
|
||||
*/
|
||||
private PrivacyHelper $privacyHelper;
|
||||
|
||||
public function __construct(
|
||||
?LoggerInterface $logger = null,
|
||||
?PartStreamContainer $streamContainer = null,
|
||||
?PartHeaderContainer $headerContainer = null,
|
||||
?PartChildrenContainer $partChildrenContainer = null,
|
||||
?MultipartHelper $multipartHelper = null,
|
||||
?PrivacyHelper $privacyHelper = null
|
||||
) {
|
||||
parent::__construct(
|
||||
null,
|
||||
$logger,
|
||||
$streamContainer,
|
||||
$headerContainer,
|
||||
$partChildrenContainer
|
||||
);
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
$this->multipartHelper = $multipartHelper ?? $di->get(MultipartHelper::class);
|
||||
$this->privacyHelper = $privacyHelper ?? $di->get(PrivacyHelper::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to parse a handle or string into an IMessage without
|
||||
* requiring including MailMimeParser, instantiating it, and calling parse.
|
||||
*
|
||||
* If the passed $resource is a resource handle or StreamInterface, the
|
||||
* resource must remain open while the returned IMessage object exists.
|
||||
* Pass true as the second argument to have the resource attached to the
|
||||
* IMessage and closed for you when it's destroyed, or pass false to
|
||||
* manually close it if it should remain open after the IMessage object is
|
||||
* destroyed.
|
||||
*
|
||||
* @param resource|StreamInterface|string $resource The resource handle to
|
||||
* the input stream of the mime message, or a string containing a
|
||||
* mime message.
|
||||
* @param bool $attached pass true to have it attached to the returned
|
||||
* IMessage and destroyed with it.
|
||||
*/
|
||||
public static function from(mixed $resource, bool $attached) : IMessage
|
||||
{
|
||||
static $mmp = null;
|
||||
if ($mmp === null) {
|
||||
$mmp = new MailMimeParser();
|
||||
}
|
||||
return $mmp->parse($resource, $attached);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current part is a mime part.
|
||||
*
|
||||
* The message is considered 'mime' if it has either a Content-Type or
|
||||
* MIME-Version header defined.
|
||||
*
|
||||
*/
|
||||
public function isMime() : bool
|
||||
{
|
||||
$contentType = $this->getHeaderValue(HeaderConsts::CONTENT_TYPE);
|
||||
$mimeVersion = $this->getHeaderValue(HeaderConsts::MIME_VERSION);
|
||||
return ($contentType !== null || $mimeVersion !== null);
|
||||
}
|
||||
|
||||
public function getSubject() : ?string
|
||||
{
|
||||
return $this->getHeaderValue(HeaderConsts::SUBJECT);
|
||||
}
|
||||
|
||||
public function getTextPart(int $index = 0) : ?IMessagePart
|
||||
{
|
||||
return $this->getPart(
|
||||
$index,
|
||||
PartFilter::fromInlineContentType('text/plain')
|
||||
);
|
||||
}
|
||||
|
||||
public function getTextPartCount() : int
|
||||
{
|
||||
return $this->getPartCount(
|
||||
PartFilter::fromInlineContentType('text/plain')
|
||||
);
|
||||
}
|
||||
|
||||
public function getHtmlPart(int $index = 0) : ?IMessagePart
|
||||
{
|
||||
return $this->getPart(
|
||||
$index,
|
||||
PartFilter::fromInlineContentType('text/html')
|
||||
);
|
||||
}
|
||||
|
||||
public function getHtmlPartCount() : int
|
||||
{
|
||||
return $this->getPartCount(
|
||||
PartFilter::fromInlineContentType('text/html')
|
||||
);
|
||||
}
|
||||
|
||||
public function getTextStream(int $index = 0, string $charset = MailMimeParser::DEFAULT_CHARSET) : ?StreamInterface
|
||||
{
|
||||
$textPart = $this->getTextPart($index);
|
||||
if ($textPart !== null) {
|
||||
return $textPart->getContentStream($charset);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getTextContent(int $index = 0, string $charset = MailMimeParser::DEFAULT_CHARSET) : ?string
|
||||
{
|
||||
$part = $this->getTextPart($index);
|
||||
if ($part !== null) {
|
||||
return $part->getContent($charset);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getHtmlStream(int $index = 0, string $charset = MailMimeParser::DEFAULT_CHARSET) : ?StreamInterface
|
||||
{
|
||||
$htmlPart = $this->getHtmlPart($index);
|
||||
if ($htmlPart !== null) {
|
||||
return $htmlPart->getContentStream($charset);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getHtmlContent(int $index = 0, string $charset = MailMimeParser::DEFAULT_CHARSET) : ?string
|
||||
{
|
||||
$part = $this->getHtmlPart($index);
|
||||
if ($part !== null) {
|
||||
return $part->getContent($charset);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setTextPart(mixed $resource, string $charset = 'UTF-8') : static
|
||||
{
|
||||
$this->multipartHelper
|
||||
->setContentPartForMimeType(
|
||||
$this,
|
||||
'text/plain',
|
||||
$resource,
|
||||
$charset
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHtmlPart(mixed $resource, string $charset = 'UTF-8') : static
|
||||
{
|
||||
$this->multipartHelper
|
||||
->setContentPartForMimeType(
|
||||
$this,
|
||||
'text/html',
|
||||
$resource,
|
||||
$charset
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeTextPart(int $index = 0) : bool
|
||||
{
|
||||
return $this->multipartHelper
|
||||
->removePartByMimeType(
|
||||
$this,
|
||||
'text/plain',
|
||||
$index
|
||||
);
|
||||
}
|
||||
|
||||
public function removeAllTextParts(bool $moveRelatedPartsBelowMessage = true) : bool
|
||||
{
|
||||
return $this->multipartHelper
|
||||
->removeAllContentPartsByMimeType(
|
||||
$this,
|
||||
'text/plain',
|
||||
$moveRelatedPartsBelowMessage
|
||||
);
|
||||
}
|
||||
|
||||
public function removeHtmlPart(int $index = 0) : bool
|
||||
{
|
||||
return $this->multipartHelper
|
||||
->removePartByMimeType(
|
||||
$this,
|
||||
'text/html',
|
||||
$index
|
||||
);
|
||||
}
|
||||
|
||||
public function removeAllHtmlParts(bool $moveRelatedPartsBelowMessage = true) : bool
|
||||
{
|
||||
return $this->multipartHelper
|
||||
->removeAllContentPartsByMimeType(
|
||||
$this,
|
||||
'text/html',
|
||||
$moveRelatedPartsBelowMessage
|
||||
);
|
||||
}
|
||||
|
||||
public function getAttachmentPart(int $index) : ?IMessagePart
|
||||
{
|
||||
return $this->getPart(
|
||||
$index,
|
||||
PartFilter::fromAttachmentFilter()
|
||||
);
|
||||
}
|
||||
|
||||
public function getAllAttachmentParts() : array
|
||||
{
|
||||
return $this->getAllParts(
|
||||
PartFilter::fromAttachmentFilter()
|
||||
);
|
||||
}
|
||||
|
||||
public function getAttachmentCount() : int
|
||||
{
|
||||
return \count($this->getAllAttachmentParts());
|
||||
}
|
||||
|
||||
public function addAttachmentPart(mixed $resource, string $mimeType, ?string $filename = null, string $disposition = 'attachment', string $encoding = 'base64') : static
|
||||
{
|
||||
$this->multipartHelper
|
||||
->createAndAddPartForAttachment(
|
||||
$this,
|
||||
$resource,
|
||||
$mimeType,
|
||||
(\strcasecmp($disposition, 'inline') === 0) ? 'inline' : 'attachment',
|
||||
$filename,
|
||||
$encoding
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addAttachmentPartFromFile(string $filePath, string $mimeType, ?string $filename = null, string $disposition = 'attachment', string $encoding = 'base64') : static
|
||||
{
|
||||
$handle = Psr7\Utils::streamFor(\fopen($filePath, 'r'));
|
||||
if ($filename === null) {
|
||||
$filename = \basename($filePath);
|
||||
}
|
||||
$this->addAttachmentPart($handle, $mimeType, $filename, $disposition, $encoding);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeAttachmentPart(int $index) : static
|
||||
{
|
||||
$part = $this->getAttachmentPart($index);
|
||||
$this->removePart($part);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSignedMessageStream() : ?StreamInterface
|
||||
{
|
||||
return $this
|
||||
->privacyHelper
|
||||
->getSignedMessageStream($this);
|
||||
}
|
||||
|
||||
public function getSignedMessageAsString() : ?string
|
||||
{
|
||||
return $this
|
||||
->privacyHelper
|
||||
->getSignedMessageAsString($this);
|
||||
}
|
||||
|
||||
public function getSignaturePart() : ?IMessagePart
|
||||
{
|
||||
if (\strcasecmp($this->getContentType(), 'multipart/signed') === 0) {
|
||||
return $this->getChild(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setAsMultipartSigned(string $micalg, string $protocol) : static
|
||||
{
|
||||
$this->privacyHelper
|
||||
->setMessageAsMultipartSigned($this, $micalg, $protocol);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSignature(string $body) : static
|
||||
{
|
||||
$this->privacyHelper
|
||||
->setSignature($this, $body);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMessageId() : ?string
|
||||
{
|
||||
return $this->getHeaderValue(HeaderConsts::MESSAGE_ID);
|
||||
}
|
||||
|
||||
public function getErrorLoggingContextName() : string
|
||||
{
|
||||
$params = '';
|
||||
if (!empty($this->getMessageId())) {
|
||||
$params .= ', message-id=' . $this->getContentId();
|
||||
}
|
||||
$params .= ', content-type=' . $this->getContentType();
|
||||
$nsClass = static::class;
|
||||
$class = \substr($nsClass, (\strrpos($nsClass, '\\') ?? -1) + 1);
|
||||
return $class . '(' . \spl_object_id($this) . $params . ')';
|
||||
}
|
||||
}
|
||||
42
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IMessagePartFactory.php
vendored
Normal file
42
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IMessagePartFactory.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Message\IMessagePart;
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
use ZBateson\MailMimeParser\Stream\StreamFactory;
|
||||
|
||||
/**
|
||||
* Abstract factory for subclasses of IMessagePart.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class IMessagePartFactory
|
||||
{
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
protected StreamFactory $streamFactory;
|
||||
|
||||
protected PartStreamContainerFactory $partStreamContainerFactory;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
StreamFactory $streamFactory,
|
||||
PartStreamContainerFactory $partStreamContainerFactory
|
||||
) {
|
||||
$this->logger = $logger;
|
||||
$this->streamFactory = $streamFactory;
|
||||
$this->partStreamContainerFactory = $partStreamContainerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new IMessagePart object and returns it
|
||||
*/
|
||||
abstract public function newInstance(?IMimePart $parent = null) : IMessagePart;
|
||||
}
|
||||
55
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IMimePartFactory.php
vendored
Normal file
55
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IMimePartFactory.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
use ZBateson\MailMimeParser\Message\MimePart;
|
||||
use ZBateson\MailMimeParser\Stream\StreamFactory;
|
||||
|
||||
/**
|
||||
* Responsible for creating IMimePart instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class IMimePartFactory extends IMessagePartFactory
|
||||
{
|
||||
protected PartHeaderContainerFactory $partHeaderContainerFactory;
|
||||
|
||||
protected PartChildrenContainerFactory $partChildrenContainerFactory;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
StreamFactory $streamFactory,
|
||||
PartStreamContainerFactory $partStreamContainerFactory,
|
||||
PartHeaderContainerFactory $partHeaderContainerFactory,
|
||||
PartChildrenContainerFactory $partChildrenContainerFactory
|
||||
) {
|
||||
parent::__construct($logger, $streamFactory, $partStreamContainerFactory);
|
||||
$this->partHeaderContainerFactory = $partHeaderContainerFactory;
|
||||
$this->partChildrenContainerFactory = $partChildrenContainerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new IMimePart object and returns it
|
||||
*/
|
||||
public function newInstance(?IMimePart $parent = null) : IMimePart
|
||||
{
|
||||
$streamContainer = $this->partStreamContainerFactory->newInstance();
|
||||
$headerContainer = $this->partHeaderContainerFactory->newInstance();
|
||||
$part = new MimePart(
|
||||
$parent,
|
||||
$this->logger,
|
||||
$streamContainer,
|
||||
$headerContainer,
|
||||
$this->partChildrenContainerFactory->newInstance()
|
||||
);
|
||||
$streamContainer->setStream($this->streamFactory->newMessagePartStream($part));
|
||||
return $part;
|
||||
}
|
||||
}
|
||||
37
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IUUEncodedPartFactory.php
vendored
Normal file
37
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/IUUEncodedPartFactory.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
use ZBateson\MailMimeParser\Message\IUUEncodedPart;
|
||||
use ZBateson\MailMimeParser\Message\UUEncodedPart;
|
||||
|
||||
/**
|
||||
* Responsible for creating UUEncodedPart instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class IUUEncodedPartFactory extends IMessagePartFactory
|
||||
{
|
||||
/**
|
||||
* Constructs a new UUEncodedPart object and returns it
|
||||
*/
|
||||
public function newInstance(?IMimePart $parent = null) : IUUEncodedPart
|
||||
{
|
||||
$streamContainer = $this->partStreamContainerFactory->newInstance();
|
||||
$part = new UUEncodedPart(
|
||||
null,
|
||||
null,
|
||||
$parent,
|
||||
$this->logger,
|
||||
$streamContainer
|
||||
);
|
||||
$streamContainer->setStream($this->streamFactory->newMessagePartStream($part));
|
||||
return $part;
|
||||
}
|
||||
}
|
||||
23
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartChildrenContainerFactory.php
vendored
Normal file
23
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartChildrenContainerFactory.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use ZBateson\MailMimeParser\Message\PartChildrenContainer;
|
||||
|
||||
/**
|
||||
* Creates PartChildrenContainer instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartChildrenContainerFactory
|
||||
{
|
||||
public function newInstance() : PartChildrenContainer
|
||||
{
|
||||
return new PartChildrenContainer();
|
||||
}
|
||||
}
|
||||
45
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartHeaderContainerFactory.php
vendored
Normal file
45
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartHeaderContainerFactory.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Header\HeaderFactory;
|
||||
use ZBateson\MailMimeParser\Message\PartHeaderContainer;
|
||||
|
||||
/**
|
||||
* Creates PartHeaderContainer instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartHeaderContainerFactory
|
||||
{
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
/**
|
||||
* @var HeaderFactory the HeaderFactory passed to HeaderContainer instances.
|
||||
*/
|
||||
protected HeaderFactory $headerFactory;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
public function __construct(LoggerInterface $logger, HeaderFactory $headerFactory)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->headerFactory = $headerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a PartHeaderContainer.
|
||||
*/
|
||||
public function newInstance(?PartHeaderContainer $from = null) : PartHeaderContainer
|
||||
{
|
||||
return new PartHeaderContainer($this->logger, $this->headerFactory, $from);
|
||||
}
|
||||
}
|
||||
51
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartStreamContainerFactory.php
vendored
Normal file
51
plugins/vendor/zbateson/mail-mime-parser/src/Message/Factory/PartStreamContainerFactory.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Factory;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\Message\PartStreamContainer;
|
||||
use ZBateson\MailMimeParser\Stream\StreamFactory;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* Creates PartStreamContainer instances.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartStreamContainerFactory
|
||||
{
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
protected StreamFactory $streamFactory;
|
||||
|
||||
protected MbWrapper $mbWrapper;
|
||||
|
||||
protected bool $throwExceptionReadingPartContentFromUnsupportedCharsets;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
StreamFactory $streamFactory,
|
||||
MbWrapper $mbWrapper,
|
||||
bool $throwExceptionReadingPartContentFromUnsupportedCharsets
|
||||
) {
|
||||
$this->logger = $logger;
|
||||
$this->streamFactory = $streamFactory;
|
||||
$this->mbWrapper = $mbWrapper;
|
||||
$this->throwExceptionReadingPartContentFromUnsupportedCharsets = $throwExceptionReadingPartContentFromUnsupportedCharsets;
|
||||
}
|
||||
|
||||
public function newInstance() : PartStreamContainer
|
||||
{
|
||||
return new PartStreamContainer(
|
||||
$this->logger,
|
||||
$this->streamFactory,
|
||||
$this->mbWrapper,
|
||||
$this->throwExceptionReadingPartContentFromUnsupportedCharsets
|
||||
);
|
||||
}
|
||||
}
|
||||
37
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/AbstractHelper.php
vendored
Normal file
37
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/AbstractHelper.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Helper;
|
||||
|
||||
use ZBateson\MailMimeParser\Message\Factory\IMimePartFactory;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IUUEncodedPartFactory;
|
||||
|
||||
/**
|
||||
* Base class for message helpers.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class AbstractHelper
|
||||
{
|
||||
/**
|
||||
* @var IMimePartFactory to create parts for attachments/content
|
||||
*/
|
||||
protected IMimePartFactory $mimePartFactory;
|
||||
|
||||
/**
|
||||
* @var IUUEncodedPartFactory to create parts for attachments
|
||||
*/
|
||||
protected IUUEncodedPartFactory $uuEncodedPartFactory;
|
||||
|
||||
public function __construct(
|
||||
IMimePartFactory $mimePartFactory,
|
||||
IUUEncodedPartFactory $uuEncodedPartFactory
|
||||
) {
|
||||
$this->mimePartFactory = $mimePartFactory;
|
||||
$this->uuEncodedPartFactory = $uuEncodedPartFactory;
|
||||
}
|
||||
}
|
||||
161
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/GenericHelper.php
vendored
Normal file
161
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/GenericHelper.php
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Helper;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
use ZBateson\MailMimeParser\Header\IHeader;
|
||||
use ZBateson\MailMimeParser\IMessage;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
|
||||
/**
|
||||
* Provides common Message helper routines for Message manipulation.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class GenericHelper extends AbstractHelper
|
||||
{
|
||||
/**
|
||||
* @var string[] non mime content fields that are not related to the content
|
||||
* of a part.
|
||||
*/
|
||||
private static array $nonMimeContentFields = ['contentreturn', 'contentidentifier'];
|
||||
|
||||
/**
|
||||
* Returns true if the passed header's name is a Content-* header other than
|
||||
* one defined in the static $nonMimeContentFields
|
||||
*
|
||||
*/
|
||||
private function isMimeContentField(IHeader $header, array $exceptions = []) : bool
|
||||
{
|
||||
return (\stripos($header->getName(), 'Content') === 0
|
||||
&& !\in_array(\strtolower(\str_replace('-', '', $header->getName())), \array_merge(self::$nonMimeContentFields, $exceptions)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the passed $header from $from, to $to or sets the header to
|
||||
* $default if it doesn't exist in $from.
|
||||
*
|
||||
* @param string $header
|
||||
* @param string $default
|
||||
*/
|
||||
public function copyHeader(IMimePart $from, IMimePart $to, $header, $default = null) : static
|
||||
{
|
||||
$fromHeader = $from->getHeader($header);
|
||||
$set = ($fromHeader !== null) ? $fromHeader->getRawValue() : $default;
|
||||
if ($set !== null) {
|
||||
$to->setRawHeader($header, $set);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes Content-* headers from the passed part, then detaches its content
|
||||
* stream.
|
||||
*
|
||||
* An exception is made for the obsolete Content-Return header, which isn't
|
||||
* isn't a MIME content field and so isn't removed.
|
||||
*/
|
||||
public function removeContentHeadersAndContent(IMimePart $part) : static
|
||||
{
|
||||
foreach ($part->getAllHeaders() as $header) {
|
||||
if ($this->isMimeContentField($header)) {
|
||||
$part->removeHeader($header->getName());
|
||||
}
|
||||
}
|
||||
$part->detachContentStream();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies Content-* headers from the $from header into the $to header. If
|
||||
* the Content-Type header isn't defined in $from, defaults to text/plain
|
||||
* with utf-8 and quoted-printable as its Content-Transfer-Encoding.
|
||||
*
|
||||
* An exception is made for the obsolete Content-Return header, which isn't
|
||||
* isn't a MIME content field and so isn't copied.
|
||||
*
|
||||
* @param bool $move
|
||||
*/
|
||||
public function copyContentHeadersAndContent(IMimePart $from, IMimePart $to, $move = false) : static
|
||||
{
|
||||
$this->copyHeader($from, $to, HeaderConsts::CONTENT_TYPE, 'text/plain; charset=utf-8');
|
||||
if ($from->getHeader(HeaderConsts::CONTENT_TYPE) === null) {
|
||||
$this->copyHeader($from, $to, HeaderConsts::CONTENT_TRANSFER_ENCODING, 'quoted-printable');
|
||||
} else {
|
||||
$this->copyHeader($from, $to, HeaderConsts::CONTENT_TRANSFER_ENCODING);
|
||||
}
|
||||
foreach ($from->getAllHeaders() as $header) {
|
||||
if ($this->isMimeContentField($header, ['contenttype', 'contenttransferencoding'])) {
|
||||
$this->copyHeader($from, $to, $header->getName());
|
||||
}
|
||||
}
|
||||
if ($from->hasContent()) {
|
||||
$to->attachContentStream($from->getContentStream(), MailMimeParser::DEFAULT_CHARSET);
|
||||
}
|
||||
if ($move) {
|
||||
$this->removeContentHeadersAndContent($from);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new content part from the passed part, allowing the part to be
|
||||
* used for something else (e.g. changing a non-mime message to a multipart
|
||||
* mime message).
|
||||
*
|
||||
* @return IMimePart the newly-created IMimePart
|
||||
*/
|
||||
public function createNewContentPartFrom(IMimePart $part) : IMimePart
|
||||
{
|
||||
$mime = $this->mimePartFactory->newInstance();
|
||||
$this->copyContentHeadersAndContent($part, $mime, true);
|
||||
return $mime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies type headers (Content-Type, Content-Disposition,
|
||||
* Content-Transfer-Encoding) from the $from MimePart to $to. Attaches the
|
||||
* content resource handle of $from to $to, and loops over child parts,
|
||||
* removing them from $from and adding them to $to.
|
||||
*
|
||||
*/
|
||||
public function movePartContentAndChildren(IMimePart $from, IMimePart $to) : static
|
||||
{
|
||||
$this->copyContentHeadersAndContent($from, $to, true);
|
||||
if ($from->getChildCount() > 0) {
|
||||
foreach ($from->getChildIterator() as $child) {
|
||||
$from->removePart($child);
|
||||
$to->addChild($child);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the $part IMimePart with $replacement.
|
||||
*
|
||||
* Essentially removes $part from its parent, and adds $replacement in its
|
||||
* same position. If $part is the IMessage, then $part can't be removed and
|
||||
* replaced, and instead $replacement's type headers are copied to $message,
|
||||
* and any children below $replacement are added directly below $message.
|
||||
*/
|
||||
public function replacePart(IMessage $message, IMimePart $part, IMimePart $replacement) : static
|
||||
{
|
||||
$position = $message->removePart($replacement);
|
||||
if ($part === $message) {
|
||||
$this->movePartContentAndChildren($replacement, $message);
|
||||
return $this;
|
||||
}
|
||||
$parent = $part->getParent();
|
||||
$parent->addChild($replacement, $position);
|
||||
$parent->removePart($part);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
396
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/MultipartHelper.php
vendored
Normal file
396
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/MultipartHelper.php
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Helper;
|
||||
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
use ZBateson\MailMimeParser\IMessage;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IMimePartFactory;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IUUEncodedPartFactory;
|
||||
use ZBateson\MailMimeParser\Message\IMessagePart;
|
||||
use ZBateson\MailMimeParser\Message\IMimePart;
|
||||
use ZBateson\MailMimeParser\Message\IMultiPart;
|
||||
use ZBateson\MailMimeParser\Message\PartFilter;
|
||||
|
||||
/**
|
||||
* Provides various routines to manipulate and create multipart messages from an
|
||||
* existing message (e.g. to make space for attachments in a message, or to
|
||||
* change a simple message to a multipart/alternative one, etc...)
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class MultipartHelper extends AbstractHelper
|
||||
{
|
||||
/**
|
||||
* @var GenericHelper a GenericHelper instance
|
||||
*/
|
||||
private GenericHelper $genericHelper;
|
||||
|
||||
public function __construct(
|
||||
IMimePartFactory $mimePartFactory,
|
||||
IUUEncodedPartFactory $uuEncodedPartFactory,
|
||||
GenericHelper $genericHelper
|
||||
) {
|
||||
parent::__construct($mimePartFactory, $uuEncodedPartFactory);
|
||||
$this->genericHelper = $genericHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a unique boundary.
|
||||
*
|
||||
* @param string $mimeType first 3 characters of a multipart type are used,
|
||||
* e.g. REL for relative or ALT for alternative
|
||||
*/
|
||||
public function getUniqueBoundary(string $mimeType) : string
|
||||
{
|
||||
$type = \ltrim(\strtoupper(\preg_replace('/^(multipart\/(.{3}).*|.*)$/i', '$2-', $mimeType)), '-');
|
||||
return \uniqid('----=MMP-' . $type . '-', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a unique mime boundary and assigns it to the passed part's
|
||||
* Content-Type header with the passed mime type.
|
||||
*/
|
||||
public function setMimeHeaderBoundaryOnPart(IMimePart $part, string $mimeType) : static
|
||||
{
|
||||
$part->setRawHeader(
|
||||
HeaderConsts::CONTENT_TYPE,
|
||||
"$mimeType;\r\n\tboundary=\""
|
||||
. $this->getUniqueBoundary($mimeType) . '"'
|
||||
);
|
||||
$part->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the passed message as multipart/mixed.
|
||||
*
|
||||
* If the message has content, a new part is created and added as a child of
|
||||
* the message. The message's content and content headers are moved to the
|
||||
* new part.
|
||||
*/
|
||||
public function setMessageAsMixed(IMessage $message) : static
|
||||
{
|
||||
if ($message->hasContent()) {
|
||||
$part = $this->genericHelper->createNewContentPartFrom($message);
|
||||
$message->addChild($part, 0);
|
||||
}
|
||||
$this->setMimeHeaderBoundaryOnPart($message, 'multipart/mixed');
|
||||
$atts = $message->getAllAttachmentParts();
|
||||
if (!empty($atts)) {
|
||||
foreach ($atts as $att) {
|
||||
$att->notify();
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the passed message as multipart/alternative.
|
||||
*
|
||||
* If the message has content, a new part is created and added as a child of
|
||||
* the message. The message's content and content headers are moved to the
|
||||
* new part.
|
||||
*/
|
||||
public function setMessageAsAlternative(IMessage $message) : static
|
||||
{
|
||||
if ($message->hasContent()) {
|
||||
$part = $this->genericHelper->createNewContentPartFrom($message);
|
||||
$message->addChild($part, 0);
|
||||
}
|
||||
$this->setMimeHeaderBoundaryOnPart($message, 'multipart/alternative');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the passed $alternativePart for a part with the passed mime type
|
||||
* and returns its parent.
|
||||
*
|
||||
* Used for alternative mime types that have a multipart/mixed or
|
||||
* multipart/related child containing a content part of $mimeType, where
|
||||
* the whole mixed/related part should be removed.
|
||||
*
|
||||
* @param string $mimeType the content-type to find below $alternativePart
|
||||
* @param IMimePart $alternativePart The multipart/alternative part to look
|
||||
* under
|
||||
* @return bool|IMimePart false if a part is not found
|
||||
*/
|
||||
public function getContentPartContainerFromAlternative($mimeType, IMimePart $alternativePart) : bool|IMimePart
|
||||
{
|
||||
$part = $alternativePart->getPart(0, PartFilter::fromInlineContentType($mimeType));
|
||||
$contPart = null;
|
||||
do {
|
||||
if ($part === null) {
|
||||
return false;
|
||||
}
|
||||
$contPart = $part;
|
||||
$part = $part->getParent();
|
||||
} while ($part !== $alternativePart);
|
||||
return $contPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all parts of $mimeType from $alternativePart.
|
||||
*
|
||||
* If $alternativePart contains a multipart/mixed or multipart/relative part
|
||||
* with other parts of different content-types, the multipart part is
|
||||
* removed, and parts of different content-types can optionally be moved to
|
||||
* the main message part.
|
||||
*/
|
||||
public function removeAllContentPartsFromAlternative(
|
||||
IMessage $message,
|
||||
string $mimeType,
|
||||
IMimePart $alternativePart,
|
||||
bool $keepOtherContent
|
||||
) : bool {
|
||||
$rmPart = $this->getContentPartContainerFromAlternative($mimeType, $alternativePart);
|
||||
if ($rmPart === false) {
|
||||
return false;
|
||||
}
|
||||
if ($keepOtherContent && $rmPart->getChildCount() > 0) {
|
||||
$this->moveAllNonMultiPartsToMessageExcept($message, $rmPart, $mimeType);
|
||||
$alternativePart = $message->getPart(0, PartFilter::fromInlineContentType('multipart/alternative'));
|
||||
}
|
||||
$message->removePart($rmPart);
|
||||
if ($alternativePart !== null && $alternativePart instanceof IMultiPart) {
|
||||
if ($alternativePart->getChildCount() === 1) {
|
||||
$this->genericHelper->replacePart($message, $alternativePart, $alternativePart->getChild(0));
|
||||
} elseif ($alternativePart->getChildCount() === 0) {
|
||||
$message->removePart($alternativePart);
|
||||
}
|
||||
}
|
||||
while ($message->getChildCount() === 1) {
|
||||
$this->genericHelper->replacePart($message, $message, $message->getChild(0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new mime part as a multipart/alternative and assigns the passed
|
||||
* $contentPart as a part below it before returning it.
|
||||
*
|
||||
* @return IMimePart the alternative part
|
||||
*/
|
||||
public function createAlternativeContentPart(IMessage $message, IMessagePart $contentPart) : IMimePart
|
||||
{
|
||||
$altPart = $this->mimePartFactory->newInstance();
|
||||
$this->setMimeHeaderBoundaryOnPart($altPart, 'multipart/alternative');
|
||||
$message->removePart($contentPart);
|
||||
$message->addChild($altPart, 0);
|
||||
$altPart->addChild($contentPart, 0);
|
||||
return $altPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves all parts under $from into this message except those with a
|
||||
* content-type equal to $exceptMimeType. If the message is not a
|
||||
* multipart/mixed message, it is set to multipart/mixed first.
|
||||
*/
|
||||
public function moveAllNonMultiPartsToMessageExcept(IMessage $message, IMimePart $from, string $exceptMimeType) : static
|
||||
{
|
||||
$parts = $from->getAllParts(function(IMessagePart $part) use ($exceptMimeType) {
|
||||
if ($part instanceof IMimePart && $part->isMultiPart()) {
|
||||
return false;
|
||||
}
|
||||
return \strcasecmp($part->getContentType(), $exceptMimeType) !== 0;
|
||||
});
|
||||
if (\strcasecmp($message->getContentType(), 'multipart/mixed') !== 0) {
|
||||
$this->setMessageAsMixed($message);
|
||||
}
|
||||
foreach ($parts as $key => $part) {
|
||||
$from->removePart($part);
|
||||
$message->addChild($part);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the message to be a mime message for a non-mime (e.g. uuencoded
|
||||
* or unspecified) message. If the message has uuencoded attachments, sets
|
||||
* up the message as a multipart/mixed message and creates a separate
|
||||
* content part.
|
||||
*/
|
||||
public function enforceMime(IMessage $message) : static
|
||||
{
|
||||
if (!$message->isMime()) {
|
||||
if ($message->getAttachmentCount()) {
|
||||
$this->setMessageAsMixed($message);
|
||||
} else {
|
||||
$message->setRawHeader(HeaderConsts::CONTENT_TYPE, "text/plain;\r\n\tcharset=\"iso-8859-1\"");
|
||||
}
|
||||
$message->setRawHeader(HeaderConsts::MIME_VERSION, '1.0');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multipart/related part out of 'inline' children of $parent and
|
||||
* returns it.
|
||||
*/
|
||||
public function createMultipartRelatedPartForInlineChildrenOf(IMimePart $parent) : IMimePart
|
||||
{
|
||||
$relatedPart = $this->mimePartFactory->newInstance();
|
||||
$this->setMimeHeaderBoundaryOnPart($relatedPart, 'multipart/related');
|
||||
foreach ($parent->getChildParts(PartFilter::fromDisposition('inline')) as $part) {
|
||||
$parent->removePart($part);
|
||||
$relatedPart->addChild($part);
|
||||
}
|
||||
$parent->addChild($relatedPart, 0);
|
||||
return $relatedPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an alternative inline part in the message and returns it if one
|
||||
* exists.
|
||||
*
|
||||
* If the passed $mimeType is text/plain, searches for a text/html part.
|
||||
* Otherwise searches for a text/plain part to return.
|
||||
*
|
||||
* @return IMimePart or null if not found
|
||||
*/
|
||||
public function findOtherContentPartFor(IMessage $message, string $mimeType) : ?IMimePart
|
||||
{
|
||||
$altPart = $message->getPart(
|
||||
0,
|
||||
PartFilter::fromInlineContentType(($mimeType === 'text/plain') ? 'text/html' : 'text/plain')
|
||||
);
|
||||
if ($altPart !== null && $altPart->getParent() !== null && $altPart->getParent()->isMultiPart()) {
|
||||
$altPartParent = $altPart->getParent();
|
||||
if ($altPartParent->getChildCount(PartFilter::fromDisposition('inline')) !== 1) {
|
||||
$altPart = $this->createMultipartRelatedPartForInlineChildrenOf($altPartParent);
|
||||
}
|
||||
}
|
||||
return $altPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new content part for the passed mimeType and charset, making
|
||||
* space by creating a multipart/alternative if needed
|
||||
*/
|
||||
public function createContentPartForMimeType(IMessage $message, string $mimeType, string $charset) : IMimePart
|
||||
{
|
||||
$mimePart = $this->mimePartFactory->newInstance();
|
||||
$mimePart->setRawHeader(HeaderConsts::CONTENT_TYPE, "$mimeType;\r\n\tcharset=\"$charset\"");
|
||||
$mimePart->setRawHeader(HeaderConsts::CONTENT_TRANSFER_ENCODING, 'quoted-printable');
|
||||
|
||||
$this->enforceMime($message);
|
||||
$altPart = $this->findOtherContentPartFor($message, $mimeType);
|
||||
|
||||
if ($altPart === $message) {
|
||||
$this->setMessageAsAlternative($message);
|
||||
$message->addChild($mimePart);
|
||||
} elseif ($altPart !== null) {
|
||||
$mimeAltPart = $this->createAlternativeContentPart($message, $altPart);
|
||||
$mimeAltPart->addChild($mimePart, 1);
|
||||
} else {
|
||||
$message->addChild($mimePart, 0);
|
||||
}
|
||||
|
||||
return $mimePart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds a IMimePart for the passed content and options as an
|
||||
* attachment.
|
||||
*
|
||||
* @param string|resource|\Psr\Http\Message\StreamInterface $resource
|
||||
*/
|
||||
public function createAndAddPartForAttachment(
|
||||
IMessage $message,
|
||||
$resource,
|
||||
string $mimeType,
|
||||
string $disposition,
|
||||
?string $filename = null,
|
||||
string $encoding = 'base64'
|
||||
) : IMessagePart {
|
||||
if ($filename === null) {
|
||||
$filename = 'file' . \uniqid();
|
||||
}
|
||||
|
||||
$safe = \iconv('UTF-8', 'US-ASCII//translit//ignore', $filename);
|
||||
if ($message->isMime()) {
|
||||
$part = $this->mimePartFactory->newInstance();
|
||||
$part->setRawHeader(HeaderConsts::CONTENT_TRANSFER_ENCODING, $encoding);
|
||||
if (\strcasecmp($message->getContentType(), 'multipart/mixed') !== 0) {
|
||||
$this->setMessageAsMixed($message);
|
||||
}
|
||||
$part->setRawHeader(HeaderConsts::CONTENT_TYPE, "$mimeType;\r\n\tname=\"$safe\"");
|
||||
$part->setRawHeader(HeaderConsts::CONTENT_DISPOSITION, "$disposition;\r\n\tfilename=\"$safe\"");
|
||||
} else {
|
||||
$part = $this->uuEncodedPartFactory->newInstance();
|
||||
$part->setFilename($safe);
|
||||
}
|
||||
$part->setContent($resource);
|
||||
$message->addChild($part);
|
||||
return $part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the content part of the message with the passed mime type. If
|
||||
* there is a remaining content part and it is an alternative part of the
|
||||
* main message, the content part is moved to the message part.
|
||||
*
|
||||
* If the content part is part of an alternative part beneath the message,
|
||||
* the alternative part is replaced by the remaining content part,
|
||||
* optionally keeping other parts if $keepOtherContent is set to true.
|
||||
*
|
||||
* @return bool true on success
|
||||
*/
|
||||
public function removeAllContentPartsByMimeType(IMessage $message, string $mimeType, bool $keepOtherContent = false) : bool
|
||||
{
|
||||
$alt = $message->getPart(0, PartFilter::fromInlineContentType('multipart/alternative'));
|
||||
if ($alt !== null) {
|
||||
return $this->removeAllContentPartsFromAlternative($message, $mimeType, $alt, $keepOtherContent);
|
||||
}
|
||||
$message->removeAllParts(PartFilter::fromInlineContentType($mimeType));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the 'inline' part with the passed contentType, at the given index
|
||||
* defaulting to the first
|
||||
*
|
||||
* @return bool true on success
|
||||
*/
|
||||
public function removePartByMimeType(IMessage $message, string $mimeType, int $index = 0) : bool
|
||||
{
|
||||
$parts = $message->getAllParts(PartFilter::fromInlineContentType($mimeType));
|
||||
$alt = $message->getPart(0, PartFilter::fromInlineContentType('multipart/alternative'));
|
||||
if ($parts === null || !isset($parts[$index])) {
|
||||
return false;
|
||||
} elseif (\count($parts) === 1) {
|
||||
return $this->removeAllContentPartsByMimeType($message, $mimeType, true);
|
||||
}
|
||||
$part = $parts[$index];
|
||||
$message->removePart($part);
|
||||
if ($alt !== null && $alt->getChildCount() === 1) {
|
||||
$this->genericHelper->replacePart($message, $alt, $alt->getChild(0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Either creates a mime part or sets the existing mime part with the passed
|
||||
* mimeType to $strongOrHandle.
|
||||
*
|
||||
* @param string|resource $stringOrHandle
|
||||
*/
|
||||
public function setContentPartForMimeType(IMessage $message, string $mimeType, mixed $stringOrHandle, string $charset) : static
|
||||
{
|
||||
$part = ($mimeType === 'text/html') ? $message->getHtmlPart() : $message->getTextPart();
|
||||
if ($part === null) {
|
||||
$part = $this->createContentPartForMimeType($message, $mimeType, $charset);
|
||||
} else {
|
||||
$contentType = $part->getContentType();
|
||||
if ($part instanceof IMimePart) {
|
||||
$part->setRawHeader(HeaderConsts::CONTENT_TYPE, "$contentType;\r\n\tcharset=\"$charset\"");
|
||||
}
|
||||
}
|
||||
$part->setContent($stringOrHandle);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
159
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/PrivacyHelper.php
vendored
Normal file
159
plugins/vendor/zbateson/mail-mime-parser/src/Message/Helper/PrivacyHelper.php
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message\Helper;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
use ZBateson\MailMimeParser\IMessage;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IMimePartFactory;
|
||||
use ZBateson\MailMimeParser\Message\Factory\IUUEncodedPartFactory;
|
||||
use ZBateson\MailMimeParser\Message\IMessagePart;
|
||||
|
||||
/**
|
||||
* Provides routines to set or retrieve the signature part of a signed message.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PrivacyHelper extends AbstractHelper
|
||||
{
|
||||
/**
|
||||
* @var GenericHelper a GenericHelper instance
|
||||
*/
|
||||
private GenericHelper $genericHelper;
|
||||
|
||||
/**
|
||||
* @var MultipartHelper a MultipartHelper instance
|
||||
*/
|
||||
private MultipartHelper $multipartHelper;
|
||||
|
||||
public function __construct(
|
||||
IMimePartFactory $mimePartFactory,
|
||||
IUUEncodedPartFactory $uuEncodedPartFactory,
|
||||
GenericHelper $genericHelper,
|
||||
MultipartHelper $multipartHelper
|
||||
) {
|
||||
parent::__construct($mimePartFactory, $uuEncodedPartFactory);
|
||||
$this->genericHelper = $genericHelper;
|
||||
$this->multipartHelper = $multipartHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* The passed message is set as multipart/signed, and a new part is created
|
||||
* below it with content headers, content and children copied from the
|
||||
* message.
|
||||
*
|
||||
* @param string $micalg
|
||||
* @param string $protocol
|
||||
*/
|
||||
public function setMessageAsMultipartSigned(IMessage $message, $micalg, $protocol) : static
|
||||
{
|
||||
if (\strcasecmp($message->getContentType(), 'multipart/signed') !== 0) {
|
||||
$this->multipartHelper->enforceMime($message);
|
||||
$messagePart = $this->mimePartFactory->newInstance();
|
||||
$this->genericHelper->movePartContentAndChildren($message, $messagePart);
|
||||
$message->addChild($messagePart);
|
||||
$boundary = $this->multipartHelper->getUniqueBoundary('multipart/signed');
|
||||
$message->setRawHeader(
|
||||
HeaderConsts::CONTENT_TYPE,
|
||||
"multipart/signed;\r\n\tboundary=\"$boundary\";\r\n\tmicalg=\"$micalg\"; protocol=\"$protocol\""
|
||||
);
|
||||
}
|
||||
$this->overwrite8bitContentEncoding($message);
|
||||
$this->setSignature($message, 'Empty');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the signature of the message to $body, creating a signature part if
|
||||
* one doesn't exist.
|
||||
*
|
||||
* @param string $body
|
||||
*/
|
||||
public function setSignature(IMessage $message, $body) : static
|
||||
{
|
||||
$signedPart = $message->getSignaturePart();
|
||||
if ($signedPart === null) {
|
||||
$signedPart = $this->mimePartFactory->newInstance();
|
||||
$message->addChild($signedPart);
|
||||
}
|
||||
$signedPart->setRawHeader(
|
||||
HeaderConsts::CONTENT_TYPE,
|
||||
$message->getHeaderParameter(HeaderConsts::CONTENT_TYPE, 'protocol')
|
||||
);
|
||||
$signedPart->setContent($body);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops over parts of the message and sets the content-transfer-encoding
|
||||
* header to quoted-printable for text/* mime parts, and to base64
|
||||
* otherwise for parts that are '8bit' encoded.
|
||||
*
|
||||
* Used for multipart/signed messages which doesn't support 8bit transfer
|
||||
* encodings.
|
||||
*/
|
||||
public function overwrite8bitContentEncoding(IMessage $message) : static
|
||||
{
|
||||
$parts = $message->getAllParts(function(IMessagePart $part) {
|
||||
return \strcasecmp($part->getContentTransferEncoding(), '8bit') === 0;
|
||||
});
|
||||
foreach ($parts as $part) {
|
||||
$contentType = \strtolower($part->getContentType());
|
||||
$part->setRawHeader(
|
||||
HeaderConsts::CONTENT_TRANSFER_ENCODING,
|
||||
($contentType === 'text/plain' || $contentType === 'text/html') ?
|
||||
'quoted-printable' :
|
||||
'base64'
|
||||
);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream that can be used to read the content part of a signed
|
||||
* message, which can be used to sign an email or verify a signature.
|
||||
*
|
||||
* The method simply returns the stream for the first child. No
|
||||
* verification of whether the message is in fact a signed message is
|
||||
* performed.
|
||||
*
|
||||
* Note that unlike getSignedMessageAsString, getSignedMessageStream doesn't
|
||||
* replace new lines.
|
||||
*
|
||||
* @return ?StreamInterface null if the message doesn't have any children
|
||||
*/
|
||||
public function getSignedMessageStream(IMessage $message) : ?StreamInterface
|
||||
{
|
||||
$child = $message->getChild(0);
|
||||
if ($child !== null) {
|
||||
return $child->getStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing the entire body (content) of a signed message
|
||||
* for verification or calculating a signature.
|
||||
*
|
||||
* Non-CRLF new lines are replaced to always be CRLF.
|
||||
*
|
||||
* @return ?string null if the message doesn't have any children
|
||||
*/
|
||||
public function getSignedMessageAsString(IMessage $message) : ?string
|
||||
{
|
||||
$stream = $this->getSignedMessageStream($message);
|
||||
if ($stream !== null) {
|
||||
return \preg_replace(
|
||||
'/\r\n|\r|\n/',
|
||||
"\r\n",
|
||||
$stream->getContents()
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
386
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMessagePart.php
vendored
Normal file
386
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMessagePart.php
vendored
Normal file
@@ -0,0 +1,386 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use SplSubject;
|
||||
use ZBateson\MailMimeParser\IErrorBag;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* An interface representing a single part of an email.
|
||||
*
|
||||
* The base type for a message or any child part of a message. The part may
|
||||
* contain content, have a parent, and identify the type of content (e.g.
|
||||
* mime-type or charset) agnostically.
|
||||
*
|
||||
* The interface extends SplSubject -- any modifications to a message must
|
||||
* notify any attached observers.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IMessagePart extends IErrorBag, SplSubject
|
||||
{
|
||||
/**
|
||||
* Returns this part's parent.
|
||||
*/
|
||||
public function getParent() : ?IMimePart;
|
||||
|
||||
/**
|
||||
* Returns true if the part contains a 'body' (content).
|
||||
*
|
||||
*/
|
||||
public function hasContent() : bool;
|
||||
|
||||
/**
|
||||
* Returns true if the content of this part is plain text.
|
||||
*
|
||||
*/
|
||||
public function isTextPart() : bool;
|
||||
|
||||
/**
|
||||
* Returns the mime type of the content, or $default if one is not set.
|
||||
*
|
||||
* @param string $default Optional override for the default return value of
|
||||
* 'text/plain.
|
||||
* @return string the mime type
|
||||
*/
|
||||
public function getContentType(string $default = 'text/plain') : ?string;
|
||||
|
||||
/**
|
||||
* Returns the charset of the content, or null if not applicable/defined.
|
||||
*
|
||||
* @return string|null the charset
|
||||
*/
|
||||
public function getCharset() : ?string;
|
||||
|
||||
/**
|
||||
* Returns the content's disposition, or returns the value of $default if
|
||||
* not defined.
|
||||
*
|
||||
* @param string $default Optional default value to return if not
|
||||
* applicable/defined
|
||||
* @return string|null the disposition.
|
||||
*/
|
||||
public function getContentDisposition(?string $default = null) : ?string;
|
||||
|
||||
/**
|
||||
* Returns the content transfer encoding used to encode the content on this
|
||||
* part, or the value of $default if not defined.
|
||||
*
|
||||
* @param ?string $default Optional default value to return if not
|
||||
* applicable/defined
|
||||
* @return string|null the transfer encoding defined for the part.
|
||||
*/
|
||||
public function getContentTransferEncoding(?string $default = null) : ?string;
|
||||
|
||||
/**
|
||||
* Returns the Content ID of the part, or null if not defined.
|
||||
*
|
||||
* @return string|null the content ID.
|
||||
*/
|
||||
public function getContentId() : ?string;
|
||||
|
||||
/**
|
||||
* Returns a filename for the part if one is defined, or null otherwise.
|
||||
*
|
||||
* @return string|null the file name
|
||||
*/
|
||||
public function getFilename() : ?string;
|
||||
|
||||
/**
|
||||
* Returns true if the current part is a mime part.
|
||||
*
|
||||
*/
|
||||
public function isMime() : bool;
|
||||
|
||||
/**
|
||||
* Overrides the default character set used for reading content from content
|
||||
* streams in cases where a user knows the source charset is not what is
|
||||
* specified.
|
||||
*
|
||||
* If set, the returned value from {@see IMessagePart::getCharset()} must be
|
||||
* ignored during subsequent read operations and streams created out of this
|
||||
* part's content.
|
||||
*
|
||||
* Note that setting an override on an
|
||||
* {@see \ZBateson\MailMimeParser\IMessage} and calling getTextStream,
|
||||
* getTextContent, getHtmlStream or getHtmlContent will not be applied to
|
||||
* those sub-parts, unless the text/html part is the IMessage itself.
|
||||
* Instead, {@see \ZBateson\MailMimeParser\IMessage::getTextPart()} should
|
||||
* be called, and setCharsetOverride called on the returned IMessagePart.
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream.
|
||||
* @param string $charsetOverride the actual charset of the content.
|
||||
* @param bool $onlyIfNoCharset if true, $charsetOverride is used only if
|
||||
* getCharset returns null.
|
||||
*/
|
||||
public function setCharsetOverride(string $charsetOverride, bool $onlyIfNoCharset = false) : static;
|
||||
|
||||
/**
|
||||
* Returns the StreamInterface for the part's content or null if the part
|
||||
* doesn't have a content section.
|
||||
*
|
||||
* To get a stream without charset conversion if you know the part's content
|
||||
* contains a binary stream, call {@see self::getBinaryContentStream()}
|
||||
* instead.
|
||||
*
|
||||
* The library automatically handles decoding and charset conversion (to the
|
||||
* target passed $charset) based on the part's transfer encoding as returned
|
||||
* by {@see IMessagePart::getContentTransferEncoding()} and the part's
|
||||
* charset as returned by {@see IMessagePart::getCharset()}. The returned
|
||||
* stream is ready to be read from directly.
|
||||
*
|
||||
* Note that the returned Stream is a shared object. If called multiple
|
||||
* times with the same $charset, and the value of the part's
|
||||
* Content-Transfer-Encoding header has not changed, the stream will be
|
||||
* rewound. This would affect other existing variables referencing the
|
||||
* stream, for example:
|
||||
*
|
||||
* ```php
|
||||
* // assuming $part is a part containing the following
|
||||
* // string for its content: '12345678'
|
||||
* $stream = $part->getContentStream();
|
||||
* $someChars = $part->read(4);
|
||||
*
|
||||
* $stream2 = $part->getContentStream();
|
||||
* $moreChars = $part->read(4);
|
||||
* echo ($someChars === $moreChars); //1
|
||||
* ```
|
||||
*
|
||||
* In this case the Stream was rewound, and $stream's second call to read 4
|
||||
* bytes reads the same first 4.
|
||||
*
|
||||
* @see IMessagePart::getBinaryContentStream() to get the content stream
|
||||
* without any charset conversions.
|
||||
* @see IMessagePart::saveContent() to save the binary contents to file.
|
||||
* @see IMessagePart::setCharsetOverride() to override the charset of the
|
||||
* content and ignore the charset returned from calling
|
||||
* IMessagePart::getCharset() when reading.
|
||||
* @param string $charset Optional charset for the returned stream.
|
||||
* @return StreamInterface|null the stream
|
||||
*/
|
||||
public function getContentStream(string $charset = MailMimeParser::DEFAULT_CHARSET) : ?StreamInterface;
|
||||
|
||||
/**
|
||||
* Returns the raw data stream for the current part, if it exists, or null
|
||||
* if there's no content associated with the stream.
|
||||
*
|
||||
* This is basically the same as calling
|
||||
* {@see IMessagePart::getContentStream()}, except no automatic charset
|
||||
* conversion is done. Note that for non-text streams, this doesn't have an
|
||||
* effect, as charset conversion is not performed in that case, and is
|
||||
* useful only when:
|
||||
*
|
||||
* - The charset defined is not correct, and the conversion produces errors;
|
||||
* or
|
||||
* - You'd like to read the raw contents without conversion, for instance to
|
||||
* save it to file or allow a user to download it as-is (in a download
|
||||
* link for example).
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream with
|
||||
* charset conversions applied.
|
||||
* @see IMessagePart::getBinaryContentResourceHandle() to get a resource
|
||||
* handle instead.
|
||||
* @see IMessagePart::saveContent() to save the binary contents to file.
|
||||
* @return StreamInterface|null the stream
|
||||
*/
|
||||
public function getBinaryContentStream() : ?StreamInterface;
|
||||
|
||||
/**
|
||||
* Returns a resource handle for the content's raw data stream, or null if
|
||||
* the part doesn't have a content stream.
|
||||
*
|
||||
* The method wraps a call to {@see IMessagePart::getBinaryContentStream()}
|
||||
* and returns a resource handle for the returned Stream.
|
||||
*
|
||||
* @see IMessagePart::getBinaryContentStream() to get a stream instead.
|
||||
* @see IMessagePart::saveContent() to save the binary contents to file.
|
||||
* @return resource|null the resource
|
||||
*/
|
||||
public function getBinaryContentResourceHandle() : mixed;
|
||||
|
||||
/**
|
||||
* Saves the binary content of the stream to the passed file, resource or
|
||||
* stream.
|
||||
*
|
||||
* Note that charset conversion is not performed in this case, and the
|
||||
* contents of the part are saved in their binary format as transmitted (but
|
||||
* after any content-transfer decoding is performed). {@see
|
||||
* IMessagePart::getBinaryContentStream()} for a more detailed description
|
||||
* of the stream.
|
||||
*
|
||||
* If the passed parameter is a string, it's assumed to be a filename to
|
||||
* write to. The file is opened in 'w+' mode, and closed before returning.
|
||||
*
|
||||
* When passing a resource or Psr7 Stream, the resource is not closed, nor
|
||||
* rewound.
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream with
|
||||
* charset conversions applied.
|
||||
* @see IMessagePart::getBinaryContentStream() to get the content as a
|
||||
* binary stream.
|
||||
* @see IMessagePart::getBinaryContentResourceHandle() to get the content as
|
||||
* a resource handle.
|
||||
* @param string|resource|StreamInterface $filenameResourceOrStream
|
||||
*/
|
||||
public function saveContent($filenameResourceOrStream) : static;
|
||||
|
||||
/**
|
||||
* Shortcut to reading stream content and assigning it to a string. Returns
|
||||
* null if the part doesn't have a content stream.
|
||||
*
|
||||
* The returned string is encoded to the passed $charset character encoding.
|
||||
*
|
||||
* @see IMessagePart::getContentStream()
|
||||
* @param string $charset the target charset for the returned string
|
||||
* @return ?string the content
|
||||
*/
|
||||
public function getContent(string $charset = MailMimeParser::DEFAULT_CHARSET) : ?string;
|
||||
|
||||
/**
|
||||
* Attaches the stream or resource handle for the part's content. The
|
||||
* stream is closed when another stream is attached, or the MimePart is
|
||||
* destroyed.
|
||||
*
|
||||
* @see IMessagePart::setContent() to pass a string as the content.
|
||||
* @see IMessagePart::getContentStream() to get the content stream.
|
||||
* @see IMessagePart::detachContentStream() to detach the content stream.
|
||||
* @param StreamInterface $stream the content
|
||||
* @param string $streamCharset the charset of $stream
|
||||
*/
|
||||
public function attachContentStream(StreamInterface $stream, string $streamCharset = MailMimeParser::DEFAULT_CHARSET) : static;
|
||||
|
||||
/**
|
||||
* Detaches the content stream.
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream.
|
||||
* @see IMessagePart::attachContentStream() to attach a content stream.
|
||||
*/
|
||||
public function detachContentStream() : static;
|
||||
|
||||
/**
|
||||
* Sets the content of the part to the passed string, resource, or stream.
|
||||
*
|
||||
* @see IMessagePart::getContentStream() to get the content stream.
|
||||
* @see IMessagePart::attachContentStream() to attach a content stream.
|
||||
* @see IMessagePart::detachContentStream() to detach the content stream.
|
||||
* @param string|resource|StreamInterface $resource the content.
|
||||
* @param string $resourceCharset the charset of the passed $resource.
|
||||
*/
|
||||
public function setContent($resource, string $resourceCharset = MailMimeParser::DEFAULT_CHARSET) : static;
|
||||
|
||||
/**
|
||||
* Returns a resource handle for the string representation of this part,
|
||||
* containing its headers, content and children. For an IMessage, this
|
||||
* would be the entire RFC822 (or greater) email.
|
||||
*
|
||||
* If the part has not been modified and represents a parsed part, the
|
||||
* original stream should be returned. Otherwise a stream representation of
|
||||
* the part including its modifications should be returned. This insures
|
||||
* that an unmodified, signed message could be passed on that way even after
|
||||
* parsing and reading.
|
||||
*
|
||||
* The returned stream is not guaranteed to be RFC822 (or greater) compliant
|
||||
* for the following reasons:
|
||||
*
|
||||
* - The original email or part, if not modified, is returned as-is and may
|
||||
* not be compliant.
|
||||
* - Although certain parts may have been modified, an original unmodified
|
||||
* header from the original email or part may not be compliant.
|
||||
* - A user may set headers in a non-compliant format.
|
||||
*
|
||||
* @see IMessagePart::getStream() to get a Psr7 StreamInterface instead of a
|
||||
* resource handle.
|
||||
* @see IMessagePart::__toString() to write the part to a string and return
|
||||
* it.
|
||||
* @see IMessage::save() to write the part to a file, resource handle or
|
||||
* Psr7 stream.
|
||||
* @return resource the resource handle containing the part.
|
||||
*/
|
||||
public function getResourceHandle() : mixed;
|
||||
|
||||
/**
|
||||
* Returns a Psr7 StreamInterface for the string representation of this
|
||||
* part, containing its headers, content and children.
|
||||
*
|
||||
* If the part has not been modified and represents a parsed part, the
|
||||
* original stream should be returned. Otherwise a stream representation of
|
||||
* the part including its modifications should be returned. This insures
|
||||
* that an unmodified, signed message could be passed on that way even after
|
||||
* parsing and reading.
|
||||
*
|
||||
* The returned stream is not guaranteed to be RFC822 (or greater) compliant
|
||||
* for the following reasons:
|
||||
*
|
||||
* - The original email or part, if not modified, is returned as-is and may
|
||||
* not be compliant.
|
||||
* - Although certain parts may have been modified, an original unmodified
|
||||
* header from the original email or part may not be compliant.
|
||||
* - A user may set headers in a non-compliant format.
|
||||
*
|
||||
* @see IMessagePart::getResourceHandle() to get a resource handle.
|
||||
* @see IMessagePart::__toString() to write the part to a string and return
|
||||
* it.
|
||||
* @see IMessage::save() to write the part to a file, resource handle or
|
||||
* Psr7 stream.
|
||||
* @return StreamInterface the stream containing the part.
|
||||
*/
|
||||
public function getStream() : StreamInterface;
|
||||
|
||||
/**
|
||||
* Writes a string representation of this part, including its headers,
|
||||
* content and children to the passed file, resource, or stream.
|
||||
*
|
||||
* If the part has not been modified and represents a parsed part, the
|
||||
* original stream should be written to the file. Otherwise a stream
|
||||
* representation of the part including its modifications should be written.
|
||||
* This insures that an unmodified, signed message could be passed on this
|
||||
* way even after parsing and reading.
|
||||
*
|
||||
* The written stream is not guaranteed to be RFC822 (or greater) compliant
|
||||
* for the following reasons:
|
||||
*
|
||||
* - The original email or part, if not modified, is returned as-is and may
|
||||
* not be compliant.
|
||||
* - Although certain parts may have been modified, an original unmodified
|
||||
* header from the original email or part may not be compliant.
|
||||
* - A user may set headers in a non-compliant format.
|
||||
*
|
||||
* If the passed $filenameResourceOrStream is a string, it's assumed to be a
|
||||
* filename to write to.
|
||||
*
|
||||
* When passing a resource or Psr7 Stream, the resource is not closed, nor
|
||||
* rewound after being written to.
|
||||
*
|
||||
* @see IMessagePart::getResourceHandle() to get a resource handle.
|
||||
* @see IMessagePart::__toString() to get the part in a string.
|
||||
* @see IMessage::save() to write the part to a file, resource handle or
|
||||
* Psr7 stream.
|
||||
* @param string|resource|StreamInterface $filenameResourceOrStream the
|
||||
* file, resource, or stream to write to.
|
||||
* @param string $filemode Optional filemode to open a file in (if
|
||||
* $filenameResourceOrStream is a string)
|
||||
*/
|
||||
public function save(mixed $filenameResourceOrStream, string $filemode = 'w+') : static;
|
||||
|
||||
/**
|
||||
* Returns the message/part as a string, containing its headers, content and
|
||||
* children.
|
||||
*
|
||||
* Convenience method for calling getContents() on
|
||||
* {@see IMessagePart::getStream()}.
|
||||
*
|
||||
* @see IMessagePart::getStream() to get a Psr7 StreamInterface instead of a
|
||||
* string.
|
||||
* @see IMessagePart::getResourceHandle() to get a resource handle.
|
||||
* @see IMessage::save() to write the part to a file, resource handle or
|
||||
* Psr7 stream.
|
||||
*/
|
||||
public function __toString() : string;
|
||||
}
|
||||
323
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMimePart.php
vendored
Normal file
323
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMimePart.php
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use Traversable;
|
||||
use ZBateson\MailMimeParser\Header\IHeader;
|
||||
|
||||
/**
|
||||
* An interface representation of any MIME email part.
|
||||
*
|
||||
* A MIME part may contain any combination of headers, content and children.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IMimePart extends IMultiPart
|
||||
{
|
||||
/**
|
||||
* Returns true if this part's content type matches multipart/*
|
||||
*/
|
||||
public function isMultiPart() : bool;
|
||||
|
||||
/**
|
||||
* Returns true if this part is the 'signature' part of a signed message.
|
||||
*/
|
||||
public function isSignaturePart() : bool;
|
||||
|
||||
/**
|
||||
* Returns the IHeader object for the header with the given $name.
|
||||
*
|
||||
* If the optional $offset is passed, and multiple headers exist with the
|
||||
* same name, the one at the passed offset is returned.
|
||||
*
|
||||
* Note that mime header names aren't case sensitive, and the '-' character
|
||||
* is ignored, so ret
|
||||
*
|
||||
* If a header with the given $name and $offset doesn't exist, null is
|
||||
* returned.
|
||||
*
|
||||
* @see IMimePart::getHeaderAs() to parse a header into a provided IHeader
|
||||
* type and return it.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve a two-dimensional string[][]
|
||||
* array of raw headers in this part.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator traversing
|
||||
* a two-dimensional string[] array of raw headers.
|
||||
* @param string $name The name of the header to retrieve.
|
||||
* @param int $offset Optional offset if there are multiple headers with the
|
||||
* given name.
|
||||
* @return ?IHeader the header object if it exists, or null if not
|
||||
*/
|
||||
public function getHeader(string $name, int $offset = 0) : ?IHeader;
|
||||
|
||||
/**
|
||||
* Returns the IHeader object for the header with the given $name, using the
|
||||
* passed $iHeaderClass to construct it.
|
||||
*
|
||||
* If the optional $offset is passed, and multiple headers exist with the
|
||||
* same name, the one at the passed offset is returned.
|
||||
*
|
||||
* Note that mime headers aren't case sensitive, and the '-' character is
|
||||
*
|
||||
* If a header with the given $name and $offset doesn't exist, null is
|
||||
* returned.
|
||||
*
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve a two-dimensional string[][]
|
||||
* array of raw headers in this part.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator traversing
|
||||
* a two-dimensional string[] array of raw headers.
|
||||
* @param string $name The name of the header to retrieve.
|
||||
* @param int $offset Optional offset if there are multiple headers with the
|
||||
* given name.
|
||||
* @return ?IHeader the header object
|
||||
*/
|
||||
public function getHeaderAs(string $name, string $iHeaderClass, int $offset = 0) : ?IHeader;
|
||||
|
||||
/**
|
||||
* Returns an array of all headers in this part.
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve a two-dimensional string[][]
|
||||
* array of raw headers in this part.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator traversing
|
||||
* a two-dimensional string[] array of raw headers.
|
||||
* @return IHeader[] an array of header objects
|
||||
*/
|
||||
public function getAllHeaders() : array;
|
||||
|
||||
/**
|
||||
* Returns an array of headers that match the passed name.
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getRawHeaders() to retrieve a two-dimensional string[][]
|
||||
* array of raw headers in this part.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator traversing
|
||||
* a two-dimensional string[] array of raw headers.
|
||||
* @return IHeader[] an array of header objects
|
||||
*/
|
||||
public function getAllHeadersByName(string $name) : array;
|
||||
|
||||
/**
|
||||
* Returns a two dimensional string array of all headers for the mime part
|
||||
* with the first element holding the name, and the second its raw string
|
||||
* value:
|
||||
*
|
||||
* [ [ '1st-Header-Name', 'Header Value' ], [ '2nd-Header-Name', 'Header Value' ] ]
|
||||
*
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator instead of
|
||||
* the returned two-dimensional array
|
||||
* @return string[][] an array of raw headers
|
||||
*/
|
||||
public function getRawHeaders() : array;
|
||||
|
||||
/**
|
||||
* Returns an iterator to all headers in this part. Each returned element
|
||||
* is an array with its first element set to the header's name, and the
|
||||
* second to its raw value:
|
||||
*
|
||||
* [ 'Header-Name', 'Header Value' ]
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve the array the returned
|
||||
* iterator iterates over.
|
||||
* @return Traversable<array<string>> an iterator for raw headers
|
||||
*/
|
||||
public function getRawHeaderIterator() : Traversable;
|
||||
|
||||
/**
|
||||
* Returns the string value for the header with the given $name, or null if
|
||||
* the header doesn't exist and no alternative $defaultValue is passed.
|
||||
*
|
||||
* Note that mime headers aren't case sensitive.
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderParameter() to get the string value portion of a
|
||||
* specific header's parameter only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve the array the returned
|
||||
* iterator iterates over.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator instead of
|
||||
* the returned two-dimensional array
|
||||
* @param string $name The name of the header
|
||||
* @param ?string $defaultValue Optional default value to return if the
|
||||
* header doesn't exist on this part.
|
||||
* @return string|null the value of the header
|
||||
*/
|
||||
public function getHeaderValue(string $name, ?string $defaultValue = null) : ?string;
|
||||
|
||||
/**
|
||||
* Returns the value of the parameter named $param on a header with the
|
||||
* passed $header name, or null if the parameter doesn't exist and a
|
||||
* $defaultValue isn't passed.
|
||||
*
|
||||
* Only headers of type
|
||||
* {@see \ZBateson\MailMimeParser\Header\ParameterHeader} have parameters.
|
||||
* Content-Type and Content-Disposition are examples of headers with
|
||||
* parameters. "Charset" is a common parameter of Content-Type.
|
||||
*
|
||||
* @see IMimePart::getHeader() to retrieve a single header object.
|
||||
* @see IMimePart::getHeaderValue() to get the string value portion of a
|
||||
* specific header only.
|
||||
* @see IMimePart::getAllHeaders() to retrieve an array of all header
|
||||
* objects for this part.
|
||||
* @see IMimePart::getAllHeadersByName() to retrieve an array of all headers
|
||||
* with a certain name.
|
||||
* @see IMimePart::getRawHeaders() to retrieve the array the returned
|
||||
* iterator iterates over.
|
||||
* @see IMimePart::getRawHeaderIterator() to retrieve an iterator instead of
|
||||
* the returned two-dimensional array
|
||||
* @param string $header The name of the header.
|
||||
* @param string $param The name of the parameter.
|
||||
* @param ?string $defaultValue Optional default value to return if the
|
||||
* parameter doesn't exist.
|
||||
* @return string|null The value of the parameter.
|
||||
*/
|
||||
public function getHeaderParameter(string $header, string $param, ?string $defaultValue = null) : ?string;
|
||||
|
||||
/**
|
||||
* Adds a header with the given $name and $value. An optional $offset may
|
||||
* be passed, which will overwrite a header if one exists with the given
|
||||
* name and offset only. Otherwise a new header is added. The passed
|
||||
* $offset may be ignored in that case if it doesn't represent the next
|
||||
* insert position for the header with the passed name... instead it would
|
||||
* be 'pushed' on at the next position.
|
||||
*
|
||||
* ```
|
||||
* $part = $myMimePart;
|
||||
* $part->setRawHeader('New-Header', 'value');
|
||||
* echo $part->getHeaderValue('New-Header'); // 'value'
|
||||
*
|
||||
* $part->setRawHeader('New-Header', 'second', 4);
|
||||
* echo is_null($part->getHeader('New-Header', 4)); // '1' (true)
|
||||
* echo $part->getHeader('New-Header', 1)
|
||||
* ->getValue(); // 'second'
|
||||
* ```
|
||||
*
|
||||
* A new {@see \ZBateson\MailMimeParser\Header\IHeader} object is created
|
||||
* from the passed value. No processing on the passed string is performed,
|
||||
* and so the passed name and value must be formatted correctly according to
|
||||
* related RFCs. In particular, be careful to encode non-ascii data, to
|
||||
* keep lines under 998 characters in length, and to follow any special
|
||||
* formatting required for the type of header.
|
||||
*
|
||||
* @see IMimePart::addRawHeader() Adds a header to the part regardless of
|
||||
* whether or not a header with that name already exists.
|
||||
* @see IMimePart::removeHeader() Removes all headers on this part with the
|
||||
* passed name
|
||||
* @see IMimePart::removeSingleHeader() Removes a single header if more than
|
||||
* one with the passed name exists.
|
||||
* @param string $name The name of the new header, e.g. 'Content-Type'.
|
||||
* @param ?string $value The raw value of the new header.
|
||||
* @param int $offset An optional offset, defaulting to '0' and therefore
|
||||
* overriding the first header of the given $name if one exists.
|
||||
*/
|
||||
public function setRawHeader(string $name, ?string $value, int $offset = 0) : static;
|
||||
|
||||
/**
|
||||
* Adds a header with the given $name and $value.
|
||||
*
|
||||
* Note: If a header with the passed name already exists, a new header is
|
||||
* created with the same name. This should only be used when that is
|
||||
* intentional - in most cases {@see IMimePart::setRawHeader()} should be
|
||||
* called instead.
|
||||
*
|
||||
* A new {@see \ZBateson\MailMimeParser\Header\IHeader} object is created
|
||||
* from the passed value. No processing on the passed string is performed,
|
||||
* and so the passed name and value must be formatted correctly according to
|
||||
* related RFCs. In particular, be careful to encode non-ascii data, to
|
||||
* keep lines under 998 characters in length, and to follow any special
|
||||
* formatting required for the type of header.
|
||||
*
|
||||
* @see IMimePart::setRawHeader() Sets a header, potentially overwriting one
|
||||
* if it already exists.
|
||||
* @see IMimePart::removeHeader() Removes all headers on this part with the
|
||||
* passed name
|
||||
* @see IMimePart::removeSingleHeader() Removes a single header if more than
|
||||
* one with the passed name exists.
|
||||
* @param string $name The name of the header
|
||||
* @param string $value The raw value of the header.
|
||||
*/
|
||||
public function addRawHeader(string $name, string $value) : static;
|
||||
|
||||
/**
|
||||
* Removes all headers from this part with the passed name.
|
||||
*
|
||||
* @see IMimePart::addRawHeader() Adds a header to the part regardless of
|
||||
* whether or not a header with that name already exists.
|
||||
* @see IMimePart::setRawHeader() Sets a header, potentially overwriting one
|
||||
* if it already exists.
|
||||
* @see IMimePart::removeSingleHeader() Removes a single header if more than
|
||||
* one with the passed name exists.
|
||||
* @param string $name The name of the header(s) to remove.
|
||||
*/
|
||||
public function removeHeader(string $name) : static;
|
||||
|
||||
/**
|
||||
* Removes a single header with the passed name (in cases where more than
|
||||
* one may exist, and others should be preserved).
|
||||
*
|
||||
* @see IMimePart::addRawHeader() Adds a header to the part regardless of
|
||||
* whether or not a header with that name already exists.
|
||||
* @see IMimePart::setRawHeader() Sets a header, potentially overwriting one
|
||||
* if it already exists.
|
||||
* @see IMimePart::removeHeader() Removes all headers on this part with the
|
||||
* passed name
|
||||
* @param string $name The name of the header to remove
|
||||
* @param int $offset Optional offset of the header to remove (defaults to
|
||||
* 0 -- the first header).
|
||||
*/
|
||||
public function removeSingleHeader(string $name, int $offset = 0) : static;
|
||||
}
|
||||
292
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMultiPart.php
vendored
Normal file
292
plugins/vendor/zbateson/mail-mime-parser/src/Message/IMultiPart.php
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use RecursiveIterator;
|
||||
|
||||
/**
|
||||
* An interface representing a message part that contains children.
|
||||
*
|
||||
* An IMultiPart object may have any number of child parts, or may be a child
|
||||
* itself with its own parent or parents.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IMultiPart extends IMessagePart
|
||||
{
|
||||
/**
|
||||
* Returns the part at the given 0-based index for this part (part 0) and
|
||||
* all parts under it, or null if not found with the passed filter function.
|
||||
*
|
||||
* Note that the first part returned is the current part itself. This is
|
||||
* usually desirable for queries with a passed filter, e.g. looking for an
|
||||
* part with a specific Content-Type that may be satisfied by the current
|
||||
* part.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getAllParts() to get an array of all parts with an
|
||||
* optional filter.
|
||||
* @see IMultiPart::getPartCount() to get the number of parts with an
|
||||
* optional filter.
|
||||
* @see IMultiPart::getChild() to get a direct child of the current part.
|
||||
* @param int $index The 0-based index (0 being this part if $fnFilter is
|
||||
* null or this part is satisfied by the filter).
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return IMessagePart|null A matching part, or null if not found.
|
||||
*/
|
||||
public function getPart(int $index, ?callable $fnFilter = null) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Returns the current part, all child parts, and child parts of all
|
||||
* children optionally filtering them with the provided PartFilter.
|
||||
*
|
||||
* Note that the first part returned is the current part itself. This is
|
||||
* often desirable for queries with a passed filter, e.g. looking for an
|
||||
* IMessagePart with a specific Content-Type that may be satisfied by the
|
||||
* current part.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getPart() to find a part at a specific 0-based index
|
||||
* with an optional filter.
|
||||
* @see IMultiPart::getPartCount() to get the number of parts with an
|
||||
* optional filter.
|
||||
* @see IMultiPart::getChildParts() to get an array of all direct children
|
||||
* of the current part.
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return IMessagePart[] An array of matching parts.
|
||||
*/
|
||||
public function getAllParts(?callable $fnFilter = null) : array;
|
||||
|
||||
/**
|
||||
* Returns the total number of parts in this and all children.
|
||||
*
|
||||
* Note that the current part is considered, so the minimum getPartCount is
|
||||
* 1 without a filter.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getPart() to find a part at a specific 0-based index
|
||||
* with an optional filter.
|
||||
* @see IMultiPart::getAllParts() to get an array of all parts with an
|
||||
* optional filter.
|
||||
* @see IMultiPart::getChildCount() to get a count of direct children of
|
||||
* this part.
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return int The number of matching parts.
|
||||
*/
|
||||
public function getPartCount(?callable $fnFilter = null) : int;
|
||||
|
||||
/**
|
||||
* Returns the direct child at the given 0-based index and optional filter,
|
||||
* or null if none exist or do not match.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getChildParts() to get an array of all direct children
|
||||
* of the current part.
|
||||
* @see IMultiPart::getChildCount() to get a count of direct children of
|
||||
* this part.
|
||||
* @see IMultiPart::getChildIterator() to get an iterator of children of
|
||||
* this part.
|
||||
* @see IMultiPart::getPart() to find a part at a specific 0-based index
|
||||
* with an optional filter.
|
||||
* @param int $index 0-based index
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return IMessagePart|null The matching direct child part or null if not
|
||||
* found.
|
||||
*/
|
||||
public function getChild(int $index, ?callable $fnFilter = null) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Returns an array of all direct child parts, optionally filtering them
|
||||
* with a passed callable.
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getChild() to get a direct child of the current part.
|
||||
* @see IMultiPart::getChildCount() to get a count of direct children of
|
||||
* this part.
|
||||
* @see IMultiPart::getChildIterator() to get an iterator of children of
|
||||
* this part.
|
||||
* @see IMultiPart::getAllParts() to get an array of all parts with an
|
||||
* optional filter.
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return IMessagePart[] An array of matching child parts.
|
||||
*/
|
||||
public function getChildParts(?callable $fnFilter = null) : array;
|
||||
|
||||
/**
|
||||
* Returns the number of direct children under this part (optionally
|
||||
* counting only filtered items if a callable filter is passed).
|
||||
*
|
||||
* The passed callable must accept an {@see IMessagePart} as an argument,
|
||||
* and return true if it should be accepted, or false to filter the part
|
||||
* out. Some default filters are provided by static functions returning
|
||||
* callables in {@see PartFilter}.
|
||||
*
|
||||
* @see IMultiPart::getChild() to get a direct child of the current part.
|
||||
* @see IMultiPart::getChildParts() to get an array of all direct children
|
||||
* of the current part.
|
||||
* @see IMultiPart::getChildIterator() to get an iterator of children of
|
||||
* this part.
|
||||
* @see IMultiPart::getPartCount() to get the number of parts with an
|
||||
* optional filter.
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return int The number of children, or number of children matching the
|
||||
* the passed filtering callable.
|
||||
*/
|
||||
public function getChildCount(?callable $fnFilter = null) : int;
|
||||
|
||||
/**
|
||||
* Returns a \RecursiveIterator of child parts.
|
||||
*
|
||||
* The {@see https://www.php.net/manual/en/class.recursiveiterator.php \RecursiveIterator}
|
||||
* allows iterating over direct children, or using
|
||||
* a {@see https://www.php.net/manual/en/class.recursiveiteratoriterator.php \RecursiveIteratorIterator}
|
||||
* to iterate over direct children, and all their children.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/class.recursiveiterator.php
|
||||
* RecursiveIterator
|
||||
* @see https://www.php.net/manual/en/class.recursiveiteratoriterator.php
|
||||
* RecursiveIteratorIterator
|
||||
* @see IMultiPart::getChild() to get a direct child of the current part.
|
||||
* @see IMultiPart::getChildParts() to get an array of all direct children
|
||||
* of the current part.
|
||||
* @see IMultiPart::getChildCount() to get a count of direct children of
|
||||
* this part.
|
||||
* @see IMultiPart::getAllParts() to get an array of all parts with an
|
||||
* optional filter.
|
||||
* @return RecursiveIterator<IMessagePart>
|
||||
*/
|
||||
public function getChildIterator() : RecursiveIterator;
|
||||
|
||||
/**
|
||||
* Returns the part that has a content type matching the passed mime type at
|
||||
* the given index, or null if there are no matching parts.
|
||||
*
|
||||
* Creates a filter that looks at the return value of
|
||||
* {@see IMessagePart::getContentType()} for all parts (including the
|
||||
* current part) and returns a matching one at the given 0-based index.
|
||||
*
|
||||
* @see IMultiPart::getAllPartsByMimeType() to get all parts that match a
|
||||
* mime type.
|
||||
* @see IMultiPart::getCountOfPartsByMimeType() to get a count of parts with
|
||||
* a mime type.
|
||||
* @param string $mimeType The mime type to find.
|
||||
* @param int $index Optional 0-based index (defaulting to '0').
|
||||
* @return IMessagePart|null The part.
|
||||
*/
|
||||
public function getPartByMimeType(string $mimeType, int $index = 0) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Returns an array of all parts that have a content type matching the
|
||||
* passed mime type.
|
||||
*
|
||||
* Creates a filter that looks at the return value of
|
||||
* {@see IMessagePart::getContentType()} for all parts (including the
|
||||
* current part), returning an array of matching parts.
|
||||
*
|
||||
* @see IMultiPart::getPartByMimeType() to get a part by mime type.
|
||||
* @see IMultiPart::getCountOfPartsByMimeType() to get a count of parts with
|
||||
* a mime type.
|
||||
* @param string $mimeType The mime type to find.
|
||||
* @return IMessagePart[] An array of matching parts.
|
||||
*/
|
||||
public function getAllPartsByMimeType(string $mimeType) : array;
|
||||
|
||||
/**
|
||||
* Returns the number of parts that have content types matching the passed
|
||||
* mime type.
|
||||
*
|
||||
* @see IMultiPart::getPartByMimeType() to get a part by mime type.
|
||||
* @see IMultiPart::getAllPartsByMimeType() to get all parts that match a
|
||||
* mime type.
|
||||
* @param string $mimeType The mime type to find.
|
||||
* @return int The number of matching parts.
|
||||
*/
|
||||
public function getCountOfPartsByMimeType(string $mimeType) : int;
|
||||
|
||||
/**
|
||||
* Returns a part that has the given Content ID, or null if not found.
|
||||
*
|
||||
* Calls {@see IMessagePart::getContentId()} to find a matching part.
|
||||
*
|
||||
* @param string $contentId The content ID to find a part for.
|
||||
* @return IMessagePart|null The matching part.
|
||||
*/
|
||||
public function getPartByContentId(string $contentId) : ?IMessagePart;
|
||||
|
||||
/**
|
||||
* Registers the passed part as a child of the current part.
|
||||
*
|
||||
* If the $position parameter is non-null, adds the part at the passed
|
||||
* position index, otherwise adds it as the last child.
|
||||
*
|
||||
* @param MessagePart $part The part to add.
|
||||
* @param int $position Optional insertion position 0-based index.
|
||||
*/
|
||||
public function addChild(MessagePart $part, ?int $position = null) : static;
|
||||
|
||||
/**
|
||||
* Removes the child part from this part and returns its previous position
|
||||
* or null if it wasn't found.
|
||||
*
|
||||
* Note that if the part is not a direct child of this part, the returned
|
||||
* position is its index within its parent (calls removePart on its direct
|
||||
* parent).
|
||||
*
|
||||
* This also means that parts from unrelated parts/messages could be removed
|
||||
* by a call to removePart -- it will always remove the part from its parent
|
||||
* if it has one, essentially calling
|
||||
* ```php $part->getParent()->removePart(); ```.
|
||||
*
|
||||
* @param IMessagePart $part The part to remove
|
||||
* @return int|null The previous index position of the part within its old
|
||||
* parent.
|
||||
*/
|
||||
public function removePart(IMessagePart $part) : ?int;
|
||||
|
||||
/**
|
||||
* Removes all parts below the current part. If a callable filter is
|
||||
* passed, removes only those matching the passed filter. The number of
|
||||
* removed parts is returned.
|
||||
*
|
||||
* Note: the current part will not be removed. Although the function naming
|
||||
* matches getAllParts, which returns the current part, it also doesn't only
|
||||
* remove direct children like getChildParts. Internally this function uses
|
||||
* getAllParts but the current part is filtered out if returned.
|
||||
*
|
||||
* @param callable $fnFilter Optional function accepting an IMessagePart and
|
||||
* returning true if the part should be included.
|
||||
* @return int The number of removed parts.
|
||||
*/
|
||||
public function removeAllParts(?callable $fnFilter = null) : int;
|
||||
}
|
||||
45
plugins/vendor/zbateson/mail-mime-parser/src/Message/IUUEncodedPart.php
vendored
Normal file
45
plugins/vendor/zbateson/mail-mime-parser/src/Message/IUUEncodedPart.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
/**
|
||||
* An interface representing a non-mime uuencoded part.
|
||||
*
|
||||
* Prior to the MIME standard, a plain text email may have included attachments
|
||||
* below it surrounded by 'begin' and 'end' lines and uuencoded data between
|
||||
* them. Those attachments are captured as 'IUUEncodedPart' objects.
|
||||
*
|
||||
* The 'begin' line included a file name and unix file mode. IUUEncodedPart
|
||||
* allows reading/setting those parameters.
|
||||
*
|
||||
* IUUEncodedPart returns a Content-Transfer-Encoding of x-uuencode, a
|
||||
* Content-Type of application-octet-stream, and a Content-Disposition of
|
||||
* 'attachment'. It also expects a mode and filename to initialize it, and
|
||||
* adds 'filename' parts to the Content-Disposition and a 'name' parameter to
|
||||
* Content-Type.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IUUEncodedPart extends IMessagePart
|
||||
{
|
||||
/**
|
||||
* Sets the filename included in the uuencoded 'begin' line.
|
||||
*/
|
||||
public function setFilename(string $filename) : static;
|
||||
|
||||
/**
|
||||
* Returns the file mode included in the uuencoded 'begin' line for this
|
||||
* part.
|
||||
*/
|
||||
public function getUnixFileMode() : ?int;
|
||||
|
||||
/**
|
||||
* Sets the unix file mode for the uuencoded 'begin' line.
|
||||
*/
|
||||
public function setUnixFileMode(int $mode) : static;
|
||||
}
|
||||
253
plugins/vendor/zbateson/mail-mime-parser/src/Message/MessagePart.php
vendored
Normal file
253
plugins/vendor/zbateson/mail-mime-parser/src/Message/MessagePart.php
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use GuzzleHttp\Psr7\StreamWrapper;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use SplObjectStorage;
|
||||
use SplObserver;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
use ZBateson\MailMimeParser\Stream\MessagePartStreamDecorator;
|
||||
|
||||
/**
|
||||
* Most basic representation of a single part of an email.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class MessagePart extends ErrorBag implements IMessagePart
|
||||
{
|
||||
/**
|
||||
* @var ?IMimePart parent part
|
||||
*/
|
||||
protected ?IMimePart $parent;
|
||||
|
||||
/**
|
||||
* @var PartStreamContainer holds 'stream' and 'content stream'.
|
||||
*/
|
||||
protected PartStreamContainer $partStreamContainer;
|
||||
|
||||
/**
|
||||
* @var ?string can be used to set an override for content's charset in cases
|
||||
* where a user knows the charset on the content is not what it claims
|
||||
* to be.
|
||||
*/
|
||||
protected ?string $charsetOverride = null;
|
||||
|
||||
/**
|
||||
* @var bool set to true when a user attaches a stream manually, it's
|
||||
* assumed to already be decoded or to have relevant transfer encoding
|
||||
* decorators attached already.
|
||||
*/
|
||||
protected bool $ignoreTransferEncoding = false;
|
||||
|
||||
/**
|
||||
* @var SplObjectStorage attached observers that need to be notified of
|
||||
* modifications to this part.
|
||||
*/
|
||||
protected SplObjectStorage $observers;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
PartStreamContainer $streamContainer,
|
||||
?IMimePart $parent = null
|
||||
) {
|
||||
parent::__construct($logger);
|
||||
$this->partStreamContainer = $streamContainer;
|
||||
$this->parent = $parent;
|
||||
$this->observers = new SplObjectStorage();
|
||||
}
|
||||
|
||||
public function attach(SplObserver $observer) : void
|
||||
{
|
||||
$this->observers->offsetSet($observer);
|
||||
}
|
||||
|
||||
public function detach(SplObserver $observer) : void
|
||||
{
|
||||
$this->observers->offsetUnset($observer);
|
||||
}
|
||||
|
||||
public function notify() : void
|
||||
{
|
||||
foreach ($this->observers as $observer) {
|
||||
$observer->update($this);
|
||||
}
|
||||
if ($this->parent !== null) {
|
||||
$this->parent->notify();
|
||||
}
|
||||
}
|
||||
|
||||
public function getParent() : ?IMimePart
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function hasContent() : bool
|
||||
{
|
||||
return $this->partStreamContainer->hasContent();
|
||||
}
|
||||
|
||||
public function getFilename() : ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setCharsetOverride(string $charsetOverride, bool $onlyIfNoCharset = false) : static
|
||||
{
|
||||
if (!$onlyIfNoCharset || $this->getCharset() === null) {
|
||||
$this->charsetOverride = $charsetOverride;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContentStream(string $charset = MailMimeParser::DEFAULT_CHARSET) : ?MessagePartStreamDecorator
|
||||
{
|
||||
if ($this->hasContent()) {
|
||||
$tr = ($this->ignoreTransferEncoding) ? '' : $this->getContentTransferEncoding();
|
||||
$ch = $this->charsetOverride ?? $this->getCharset();
|
||||
return $this->partStreamContainer->getContentStream(
|
||||
$this,
|
||||
$tr,
|
||||
$ch,
|
||||
$charset
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getBinaryContentStream() : ?MessagePartStreamDecorator
|
||||
{
|
||||
if ($this->hasContent()) {
|
||||
$tr = ($this->ignoreTransferEncoding) ? '' : $this->getContentTransferEncoding();
|
||||
return $this->partStreamContainer->getBinaryContentStream($this, $tr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getBinaryContentResourceHandle() : mixed
|
||||
{
|
||||
$stream = $this->getBinaryContentStream();
|
||||
if ($stream !== null) {
|
||||
return StreamWrapper::getResource($stream);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function saveContent($filenameResourceOrStream) : static
|
||||
{
|
||||
$resourceOrStream = $filenameResourceOrStream;
|
||||
if (\is_string($filenameResourceOrStream)) {
|
||||
$resourceOrStream = \fopen($filenameResourceOrStream, 'w+');
|
||||
}
|
||||
|
||||
$stream = Utils::streamFor($resourceOrStream);
|
||||
Utils::copyToStream($this->getBinaryContentStream(), $stream);
|
||||
|
||||
if (!\is_string($filenameResourceOrStream)
|
||||
&& !($filenameResourceOrStream instanceof StreamInterface)) {
|
||||
// only detach if it wasn't a string or StreamInterface, so the
|
||||
// fopen call can be properly closed if it was
|
||||
$stream->detach();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(string $charset = MailMimeParser::DEFAULT_CHARSET) : ?string
|
||||
{
|
||||
$stream = $this->getContentStream($charset);
|
||||
if ($stream !== null) {
|
||||
return $stream->getContents();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function attachContentStream(StreamInterface $stream, string $streamCharset = MailMimeParser::DEFAULT_CHARSET) : static
|
||||
{
|
||||
$ch = $this->charsetOverride ?? $this->getCharset();
|
||||
if ($ch !== null && $streamCharset !== $ch) {
|
||||
$this->charsetOverride = $streamCharset;
|
||||
}
|
||||
$this->ignoreTransferEncoding = true;
|
||||
$this->partStreamContainer->setContentStream($stream);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function detachContentStream() : static
|
||||
{
|
||||
$this->partStreamContainer->setContentStream(null);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setContent($resource, string $charset = MailMimeParser::DEFAULT_CHARSET) : static
|
||||
{
|
||||
$stream = Utils::streamFor($resource);
|
||||
$this->attachContentStream($stream, $charset);
|
||||
// this->notify() called in attachContentStream
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getResourceHandle() : mixed
|
||||
{
|
||||
return StreamWrapper::getResource($this->getStream());
|
||||
}
|
||||
|
||||
public function getStream() : StreamInterface
|
||||
{
|
||||
return $this->partStreamContainer->getStream();
|
||||
}
|
||||
|
||||
public function save($filenameResourceOrStream, string $filemode = 'w+') : static
|
||||
{
|
||||
$resourceOrStream = $filenameResourceOrStream;
|
||||
if (\is_string($filenameResourceOrStream)) {
|
||||
$resourceOrStream = \fopen($filenameResourceOrStream, $filemode);
|
||||
}
|
||||
|
||||
$partStream = $this->getStream();
|
||||
$partStream->rewind();
|
||||
$stream = Utils::streamFor($resourceOrStream);
|
||||
Utils::copyToStream($partStream, $stream);
|
||||
|
||||
if (!\is_string($filenameResourceOrStream)
|
||||
&& !($filenameResourceOrStream instanceof StreamInterface)) {
|
||||
// only detach if it wasn't a string or StreamInterface, so the
|
||||
// fopen call can be properly closed if it was
|
||||
$stream->detach();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->getStream()->getContents();
|
||||
}
|
||||
|
||||
public function getErrorLoggingContextName() : string
|
||||
{
|
||||
$params = '';
|
||||
if (!empty($this->getContentId())) {
|
||||
$params .= ', content-id=' . $this->getContentId();
|
||||
}
|
||||
$params .= ', content-type=' . $this->getContentType();
|
||||
$nsClass = static::class;
|
||||
$class = \substr($nsClass, (\strrpos($nsClass, '\\') ?? -1) + 1);
|
||||
return $class . '(' . \spl_object_id($this) . $params . ')';
|
||||
}
|
||||
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return [
|
||||
$this->partStreamContainer
|
||||
];
|
||||
}
|
||||
}
|
||||
302
plugins/vendor/zbateson/mail-mime-parser/src/Message/MimePart.php
vendored
Normal file
302
plugins/vendor/zbateson/mail-mime-parser/src/Message/MimePart.php
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Traversable;
|
||||
use ZBateson\MailMimeParser\Header\HeaderConsts;
|
||||
use ZBateson\MailMimeParser\Header\IHeader;
|
||||
use ZBateson\MailMimeParser\Header\ParameterHeader;
|
||||
use ZBateson\MailMimeParser\IMessage;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* A mime email message part.
|
||||
*
|
||||
* A MIME part may contain any combination of headers, content and children.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class MimePart extends MultiPart implements IMimePart
|
||||
{
|
||||
/**
|
||||
* @var PartHeaderContainer Container for this part's headers.
|
||||
*/
|
||||
protected PartHeaderContainer $headerContainer;
|
||||
|
||||
public function __construct(
|
||||
?IMimePart $parent = null,
|
||||
?LoggerInterface $logger = null,
|
||||
?PartStreamContainer $streamContainer = null,
|
||||
?PartHeaderContainer $headerContainer = null,
|
||||
?PartChildrenContainer $partChildrenContainer = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$streamContainer ?? $di->get(PartStreamContainer::class),
|
||||
$partChildrenContainer ?? $di->get(PartChildrenContainer::class),
|
||||
$parent
|
||||
);
|
||||
$this->headerContainer = $headerContainer ?? $di->get(PartHeaderContainer::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filename for the part if one is defined, or null otherwise.
|
||||
*
|
||||
* Uses the 'filename' parameter of the Content-Disposition header if it
|
||||
* exists, or the 'name' parameter of the 'Content-Type' header if it
|
||||
* doesn't.
|
||||
*
|
||||
* @return string|null the file name of the part or null.
|
||||
*/
|
||||
public function getFilename() : ?string
|
||||
{
|
||||
return $this->getHeaderParameter(
|
||||
HeaderConsts::CONTENT_DISPOSITION,
|
||||
'filename',
|
||||
$this->getHeaderParameter(
|
||||
HeaderConsts::CONTENT_TYPE,
|
||||
'name'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true.
|
||||
*
|
||||
*/
|
||||
public function isMime() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isMultiPart() : bool
|
||||
{
|
||||
// casting to bool, preg_match returns 1 for true
|
||||
return (bool) (\preg_match(
|
||||
'~multipart/.*~i',
|
||||
$this->getContentType()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this part has a defined 'charset' on its Content-Type
|
||||
* header.
|
||||
*
|
||||
* This may result in some false positives if charset is set on a part that
|
||||
* is not plain text which has been seen. If a part is known to be binary,
|
||||
* it's better to use {@see IMessagePart::getBinaryContentStream()} to
|
||||
* avoid issues, or to call {@see IMessagePart::saveContent()} directly if
|
||||
* saving a part's content.
|
||||
*
|
||||
*/
|
||||
public function isTextPart() : bool
|
||||
{
|
||||
return ($this->getCharset() !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime type of the content, or $default if one is not set.
|
||||
*
|
||||
* Looks at the part's Content-Type header and returns its value if set, or
|
||||
* defaults to 'text/plain'.
|
||||
*
|
||||
* Note that the returned value is converted to lower case, and may not be
|
||||
* identical to calling {@see MimePart::getHeaderValue('Content-Type')} in
|
||||
* some cases.
|
||||
*
|
||||
* @param string $default Optional default value to specify a default other
|
||||
* than text/plain if needed.
|
||||
* @return string the mime type
|
||||
*/
|
||||
public function getContentType(string $default = 'text/plain') : ?string
|
||||
{
|
||||
return \strtolower($this->getHeaderValue(HeaderConsts::CONTENT_TYPE, $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset of the content, or null if not applicable/defined.
|
||||
*
|
||||
* Looks for a 'charset' parameter under the 'Content-Type' header of this
|
||||
* part and returns it if set, defaulting to 'ISO-8859-1' if the
|
||||
* Content-Type header exists and is of type text/plain or text/html.
|
||||
*
|
||||
* Note that the returned value is also converted to upper case.
|
||||
*
|
||||
* @return string|null the charset
|
||||
*/
|
||||
public function getCharset() : ?string
|
||||
{
|
||||
$charset = $this->getHeaderParameter(HeaderConsts::CONTENT_TYPE, 'charset');
|
||||
if ($charset === null || \strcasecmp($charset, 'binary') === 0) {
|
||||
$contentType = $this->getContentType();
|
||||
if ($contentType === 'text/plain' || $contentType === 'text/html') {
|
||||
return 'ISO-8859-1';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return \strtoupper($charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content's disposition, or returns the value of $default if
|
||||
* not defined.
|
||||
*
|
||||
* Looks at the 'Content-Disposition' header, which should only contain
|
||||
* either 'inline' or 'attachment'. If the header is not one of those
|
||||
* values, $default is returned, which defaults to 'inline' unless passed
|
||||
* something else.
|
||||
*
|
||||
* @param string $default Optional default value if not set or does not
|
||||
* match 'inline' or 'attachment'.
|
||||
* @return string the content disposition
|
||||
*/
|
||||
public function getContentDisposition(?string $default = 'inline') : ?string
|
||||
{
|
||||
$value = $this->getHeaderValue(HeaderConsts::CONTENT_DISPOSITION);
|
||||
if ($value === null || !\in_array($value, ['inline', 'attachment'])) {
|
||||
return $default;
|
||||
}
|
||||
return \strtolower($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content transfer encoding used to encode the content on this
|
||||
* part, or the value of $default if not defined.
|
||||
*
|
||||
* Looks up and returns the value of the 'Content-Transfer-Encoding' header
|
||||
* if set, defaulting to '7bit' if an alternate $default param is not
|
||||
* passed.
|
||||
*
|
||||
* The returned value is always lowercase, and header values of 'x-uue',
|
||||
* 'uue' and 'uuencode' will return 'x-uuencode' instead.
|
||||
*
|
||||
* @param string $default Optional default value to return if the header
|
||||
* isn't set.
|
||||
* @return string the content transfer encoding.
|
||||
*/
|
||||
public function getContentTransferEncoding(?string $default = '7bit') : ?string
|
||||
{
|
||||
static $translated = [
|
||||
'x-uue' => 'x-uuencode',
|
||||
'uue' => 'x-uuencode',
|
||||
'uuencode' => 'x-uuencode'
|
||||
];
|
||||
$type = \strtolower($this->getHeaderValue(HeaderConsts::CONTENT_TRANSFER_ENCODING, $default));
|
||||
if (isset($translated[$type])) {
|
||||
return $translated[$type];
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Content ID of the part, or null if not defined.
|
||||
*
|
||||
* Looks up and returns the value of the 'Content-ID' header.
|
||||
*
|
||||
* @return string|null the content ID or null if not defined.
|
||||
*/
|
||||
public function getContentId() : ?string
|
||||
{
|
||||
return $this->getHeaderValue(HeaderConsts::CONTENT_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this part's parent is an IMessage, and is the same part
|
||||
* returned by {@see IMessage::getSignaturePart()}.
|
||||
*/
|
||||
public function isSignaturePart() : bool
|
||||
{
|
||||
if ($this->parent === null || !$this->parent instanceof IMessage) {
|
||||
return false;
|
||||
}
|
||||
return $this->parent->getSignaturePart() === $this;
|
||||
}
|
||||
|
||||
public function getHeader(string $name, int $offset = 0) : ?IHeader
|
||||
{
|
||||
return $this->headerContainer->get($name, $offset);
|
||||
}
|
||||
|
||||
public function getHeaderAs(string $name, string $iHeaderClass, int $offset = 0) : ?IHeader
|
||||
{
|
||||
return $this->headerContainer->getAs($name, $iHeaderClass, $offset);
|
||||
}
|
||||
|
||||
public function getAllHeaders() : array
|
||||
{
|
||||
return $this->headerContainer->getHeaderObjects();
|
||||
}
|
||||
|
||||
public function getAllHeadersByName(string $name) : array
|
||||
{
|
||||
return $this->headerContainer->getAll($name);
|
||||
}
|
||||
|
||||
public function getRawHeaders() : array
|
||||
{
|
||||
return $this->headerContainer->getHeaders();
|
||||
}
|
||||
|
||||
public function getRawHeaderIterator() : Traversable
|
||||
{
|
||||
return $this->headerContainer->getIterator();
|
||||
}
|
||||
|
||||
public function getHeaderValue(string $name, ?string $defaultValue = null) : ?string
|
||||
{
|
||||
$header = $this->getHeader($name);
|
||||
if ($header !== null) {
|
||||
return $header->getValue() ?: $defaultValue;
|
||||
}
|
||||
return $defaultValue;
|
||||
}
|
||||
|
||||
public function getHeaderParameter(string $header, string $param, ?string $defaultValue = null) : ?string
|
||||
{
|
||||
$obj = $this->getHeader($header);
|
||||
if ($obj && $obj instanceof ParameterHeader) {
|
||||
return $obj->getValueFor($param, $defaultValue);
|
||||
}
|
||||
return $defaultValue;
|
||||
}
|
||||
|
||||
public function setRawHeader(string $name, ?string $value, int $offset = 0) : static
|
||||
{
|
||||
$this->headerContainer->set($name, $value, $offset);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addRawHeader(string $name, string $value) : static
|
||||
{
|
||||
$this->headerContainer->add($name, $value);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeHeader(string $name) : static
|
||||
{
|
||||
$this->headerContainer->removeAll($name);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeSingleHeader(string $name, int $offset = 0) : static
|
||||
{
|
||||
$this->headerContainer->remove($name, $offset);
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getErrorBagChildren() : array
|
||||
{
|
||||
return \array_merge(parent::getErrorBagChildren(), [$this->headerContainer]);
|
||||
}
|
||||
}
|
||||
178
plugins/vendor/zbateson/mail-mime-parser/src/Message/MultiPart.php
vendored
Normal file
178
plugins/vendor/zbateson/mail-mime-parser/src/Message/MultiPart.php
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use AppendIterator;
|
||||
use ArrayIterator;
|
||||
use Iterator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RecursiveIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
/**
|
||||
* A message part that contains children.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class MultiPart extends MessagePart implements IMultiPart
|
||||
{
|
||||
/**
|
||||
* @var PartChildrenContainer child part container
|
||||
*/
|
||||
protected PartChildrenContainer $partChildrenContainer;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
PartStreamContainer $streamContainer,
|
||||
PartChildrenContainer $partChildrenContainer,
|
||||
?IMimePart $parent = null
|
||||
) {
|
||||
parent::__construct($logger, $streamContainer, $parent);
|
||||
$this->partChildrenContainer = $partChildrenContainer;
|
||||
}
|
||||
|
||||
private function getAllPartsIterator() : AppendIterator
|
||||
{
|
||||
$iter = new AppendIterator();
|
||||
$iter->append(new ArrayIterator([$this]));
|
||||
$iter->append(new RecursiveIteratorIterator($this->partChildrenContainer, RecursiveIteratorIterator::SELF_FIRST));
|
||||
return $iter;
|
||||
}
|
||||
|
||||
private function iteratorFindAt(Iterator $iter, int $index, ?callable $fnFilter = null) : ?IMessagePart
|
||||
{
|
||||
$pos = 0;
|
||||
foreach ($iter as $part) {
|
||||
if (($fnFilter === null || $fnFilter($part))) {
|
||||
if ($index === $pos) {
|
||||
return $part;
|
||||
}
|
||||
++$pos;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPart(int $index, ?callable $fnFilter = null) : ?IMessagePart
|
||||
{
|
||||
return $this->iteratorFindAt(
|
||||
$this->getAllPartsIterator(),
|
||||
$index,
|
||||
$fnFilter
|
||||
);
|
||||
}
|
||||
|
||||
public function getAllParts(?callable $fnFilter = null) : array
|
||||
{
|
||||
$array = \iterator_to_array($this->getAllPartsIterator(), false);
|
||||
if ($fnFilter !== null) {
|
||||
return \array_values(\array_filter($array, $fnFilter));
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function getPartCount(?callable $fnFilter = null) : int
|
||||
{
|
||||
return \count($this->getAllParts($fnFilter));
|
||||
}
|
||||
|
||||
public function getChild(int $index, ?callable $fnFilter = null) : ?IMessagePart
|
||||
{
|
||||
return $this->iteratorFindAt(
|
||||
$this->partChildrenContainer,
|
||||
$index,
|
||||
$fnFilter
|
||||
);
|
||||
}
|
||||
|
||||
public function getChildIterator() : RecursiveIterator
|
||||
{
|
||||
return $this->partChildrenContainer;
|
||||
}
|
||||
|
||||
public function getChildParts(?callable $fnFilter = null) : array
|
||||
{
|
||||
$array = \iterator_to_array($this->partChildrenContainer, false);
|
||||
if ($fnFilter !== null) {
|
||||
return \array_values(\array_filter($array, $fnFilter));
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function getChildCount(?callable $fnFilter = null) : int
|
||||
{
|
||||
return \count($this->getChildParts($fnFilter));
|
||||
}
|
||||
|
||||
public function getPartByMimeType(string $mimeType, int $index = 0) : ?IMessagePart
|
||||
{
|
||||
return $this->getPart($index, PartFilter::fromContentType($mimeType));
|
||||
}
|
||||
|
||||
public function getAllPartsByMimeType(string $mimeType) : array
|
||||
{
|
||||
return $this->getAllParts(PartFilter::fromContentType($mimeType));
|
||||
}
|
||||
|
||||
public function getCountOfPartsByMimeType(string $mimeType) : int
|
||||
{
|
||||
return $this->getPartCount(PartFilter::fromContentType($mimeType));
|
||||
}
|
||||
|
||||
public function getPartByContentId(string $contentId) : ?IMessagePart
|
||||
{
|
||||
$sanitized = \preg_replace('/^\s*<|>\s*$/', '', $contentId);
|
||||
return $this->getPart(0, function(IMessagePart $part) use ($sanitized) {
|
||||
$cid = $part->getContentId();
|
||||
return ($cid !== null && \strcasecmp($cid, $sanitized) === 0);
|
||||
});
|
||||
}
|
||||
|
||||
public function addChild(MessagePart $part, ?int $position = null) : static
|
||||
{
|
||||
if ($part !== $this) {
|
||||
$part->parent = $this;
|
||||
$this->partChildrenContainer->add($part, $position);
|
||||
$this->notify();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removePart(IMessagePart $part) : ?int
|
||||
{
|
||||
$parent = $part->getParent();
|
||||
if ($this !== $parent && $parent !== null) {
|
||||
return $parent->removePart($part);
|
||||
}
|
||||
|
||||
$position = $this->partChildrenContainer->remove($part);
|
||||
if ($position !== null) {
|
||||
$this->notify();
|
||||
}
|
||||
return $position;
|
||||
}
|
||||
|
||||
public function removeAllParts(?callable $fnFilter = null) : int
|
||||
{
|
||||
$parts = $this->getAllParts($fnFilter);
|
||||
$count = \count($parts);
|
||||
foreach ($parts as $part) {
|
||||
if ($part === $this) {
|
||||
--$count;
|
||||
continue;
|
||||
}
|
||||
$this->removePart($part);
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return \array_merge(parent::getErrorBagChildren(), $this->getChildParts());
|
||||
}
|
||||
}
|
||||
77
plugins/vendor/zbateson/mail-mime-parser/src/Message/NonMimePart.php
vendored
Normal file
77
plugins/vendor/zbateson/mail-mime-parser/src/Message/NonMimePart.php
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
/**
|
||||
* Represents part of a non-mime message.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class NonMimePart extends MessagePart
|
||||
{
|
||||
/**
|
||||
* Returns true.
|
||||
*
|
||||
*/
|
||||
public function isTextPart() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns text/plain
|
||||
*/
|
||||
public function getContentType(string $default = 'text/plain') : ?string
|
||||
{
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ISO-8859-1
|
||||
*/
|
||||
public function getCharset() : ?string
|
||||
{
|
||||
return 'ISO-8859-1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'inline'.
|
||||
*/
|
||||
public function getContentDisposition(?string $default = 'inline') : ?string
|
||||
{
|
||||
return 'inline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns '7bit'.
|
||||
*/
|
||||
public function getContentTransferEncoding(?string $default = '7bit') : ?string
|
||||
{
|
||||
return '7bit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false.
|
||||
*
|
||||
*/
|
||||
public function isMime() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Content ID of the part.
|
||||
*
|
||||
* NonMimeParts do not have a Content ID, and so this simply returns null.
|
||||
*
|
||||
*/
|
||||
public function getContentId() : ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
174
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartChildrenContainer.php
vendored
Normal file
174
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartChildrenContainer.php
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use ArrayAccess;
|
||||
use InvalidArgumentException;
|
||||
use RecursiveIterator;
|
||||
|
||||
/**
|
||||
* Container of IMessagePart items for a parent IMultiPart.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartChildrenContainer implements ArrayAccess, RecursiveIterator
|
||||
{
|
||||
/**
|
||||
* @var IMessagePart[] array of child parts of the IMultiPart object that is
|
||||
* holding this container.
|
||||
*/
|
||||
protected array $children;
|
||||
|
||||
/**
|
||||
* @var int current key position within $children for iteration.
|
||||
*/
|
||||
protected $position = 0;
|
||||
|
||||
/**
|
||||
* @param IMessagePart[] $children
|
||||
*/
|
||||
public function __construct(array $children = [])
|
||||
{
|
||||
$this->children = $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current element is an IMultiPart. Note that the
|
||||
* iterator may still be empty.
|
||||
*/
|
||||
public function hasChildren() : bool
|
||||
{
|
||||
return ($this->current() instanceof IMultiPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current element points to an IMultiPart, its child iterator is
|
||||
* returned by calling {@see IMultiPart::getChildIterator()}.
|
||||
*
|
||||
* @return RecursiveIterator<IMessagePart>|null the iterator
|
||||
*/
|
||||
public function getChildren() : ?RecursiveIterator
|
||||
{
|
||||
if ($this->current() instanceof IMultiPart) {
|
||||
return $this->current()->getChildIterator();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IMessagePart
|
||||
*/
|
||||
public function current() : mixed
|
||||
{
|
||||
return $this->offsetGet($this->position);
|
||||
}
|
||||
|
||||
public function key() : int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function next() : void
|
||||
{
|
||||
++$this->position;
|
||||
}
|
||||
|
||||
public function rewind() : void
|
||||
{
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
public function valid() : bool
|
||||
{
|
||||
return $this->offsetExists($this->position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the passed IMessagePart to the container in the passed position.
|
||||
*
|
||||
* If position is not passed or null, the part is added to the end, as the
|
||||
* last child in the container.
|
||||
*
|
||||
* @param IMessagePart $part The part to add
|
||||
* @param int $position An optional index position (0-based) to add the
|
||||
* child at.
|
||||
*/
|
||||
public function add(IMessagePart $part, $position = null) : static
|
||||
{
|
||||
$index = $position ?? \count($this->children);
|
||||
\array_splice(
|
||||
$this->children,
|
||||
$index,
|
||||
0,
|
||||
[$part]
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the passed part, and returns the integer position it occupied.
|
||||
*
|
||||
* @param IMessagePart $part The part to remove.
|
||||
* @return int the 0-based position it previously occupied.
|
||||
*/
|
||||
public function remove(IMessagePart $part) : ?int
|
||||
{
|
||||
foreach ($this->children as $key => $child) {
|
||||
if ($child === $part) {
|
||||
$this->offsetUnset($key);
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*/
|
||||
public function offsetExists(mixed $offset) : bool
|
||||
{
|
||||
return isset($this->children[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*/
|
||||
public function offsetGet(mixed $offset) : mixed
|
||||
{
|
||||
return $this->offsetExists($offset) ? $this->children[$offset] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param IMessagePart $value
|
||||
*/
|
||||
public function offsetSet(mixed $offset, mixed $value) : void
|
||||
{
|
||||
if (!$value instanceof IMessagePart) {
|
||||
throw new InvalidArgumentException(
|
||||
\get_class($value) . ' is not a ZBateson\MailMimeParser\Message\IMessagePart'
|
||||
);
|
||||
}
|
||||
$index = $offset ?? \count($this->children);
|
||||
$this->children[$index] = $value;
|
||||
if ($index < $this->position) {
|
||||
++$this->position;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*/
|
||||
public function offsetUnset($offset) : void
|
||||
{
|
||||
\array_splice($this->children, $offset, 1);
|
||||
if ($this->position >= $offset) {
|
||||
--$this->position;
|
||||
}
|
||||
}
|
||||
}
|
||||
114
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartFilter.php
vendored
Normal file
114
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartFilter.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
/**
|
||||
* Collection of static methods that return callables for common IMultiPart
|
||||
* child filters.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class PartFilter
|
||||
{
|
||||
/**
|
||||
* Provides an 'attachment' filter used by Message::getAttachmentPart.
|
||||
*
|
||||
* The method filters out the following types of parts:
|
||||
* - text/plain and text/html parts that do not have an 'attachment'
|
||||
* disposition
|
||||
* - any part that returns true for isMultiPart()
|
||||
* - any part that returns true for isSignaturePart()
|
||||
*/
|
||||
public static function fromAttachmentFilter() : callable
|
||||
{
|
||||
return function(IMessagePart $part) {
|
||||
$type = $part->getContentType();
|
||||
$disp = $part->getContentDisposition();
|
||||
if (\in_array($type, ['text/plain', 'text/html']) && $disp !== null && \strcasecmp($disp, 'inline') === 0) {
|
||||
return false;
|
||||
}
|
||||
return !(($part instanceof IMimePart)
|
||||
&& ($part->isMultiPart() || $part->isSignaturePart()));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a filter that keeps parts that contain a header of $name with a
|
||||
* value that matches $value (case insensitive).
|
||||
*
|
||||
* By default signed parts are excluded. Pass FALSE to the third parameter
|
||||
* to include them.
|
||||
*
|
||||
* @param string $name The header name to look up
|
||||
* @param string $value The value to match
|
||||
* @param bool $excludeSignedParts Optional signed parts exclusion (defaults
|
||||
* to true).
|
||||
*/
|
||||
public static function fromHeaderValue(string $name, string $value, bool $excludeSignedParts = true) : callable
|
||||
{
|
||||
return function(IMessagePart $part) use ($name, $value, $excludeSignedParts) {
|
||||
if ($part instanceof IMimePart) {
|
||||
if ($excludeSignedParts && $part->isSignaturePart()) {
|
||||
return false;
|
||||
}
|
||||
return (\strcasecmp($part->getHeaderValue($name, ''), $value) === 0);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes only parts that match the passed $mimeType in the return value
|
||||
* of a call to 'getContentType()'.
|
||||
*
|
||||
* @param string $mimeType Mime type of parts to find.
|
||||
*/
|
||||
public static function fromContentType(string $mimeType) : callable
|
||||
{
|
||||
return function(IMessagePart $part) use ($mimeType) {
|
||||
return \strcasecmp($part->getContentType() ?: '', $mimeType) === 0;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parts matching $mimeType that do not have a Content-Disposition
|
||||
* set to 'attachment'.
|
||||
*
|
||||
* @param string $mimeType Mime type of parts to find.
|
||||
*/
|
||||
public static function fromInlineContentType(string $mimeType) : callable
|
||||
{
|
||||
return function(IMessagePart $part) use ($mimeType) {
|
||||
$disp = $part->getContentDisposition();
|
||||
return (\strcasecmp($part->getContentType() ?: '', $mimeType) === 0) && ($disp === null
|
||||
|| \strcasecmp($disp, 'attachment') !== 0);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds parts with the passed disposition (matching against
|
||||
* IMessagePart::getContentDisposition()), optionally including
|
||||
* multipart parts and signed parts.
|
||||
*
|
||||
* @param string $disposition The disposition to find.
|
||||
* @param bool $includeMultipart Optionally include multipart parts by
|
||||
* passing true (defaults to false).
|
||||
* @param bool $includeSignedParts Optionally include signed parts (defaults
|
||||
* to false).
|
||||
*/
|
||||
public static function fromDisposition(string $disposition, bool $includeMultipart = false, bool $includeSignedParts = false) : callable
|
||||
{
|
||||
return function(IMessagePart $part) use ($disposition, $includeMultipart, $includeSignedParts) {
|
||||
if (($part instanceof IMimePart) && ((!$includeMultipart && $part->isMultiPart()) || (!$includeSignedParts && $part->isSignaturePart()))) {
|
||||
return false;
|
||||
}
|
||||
$disp = $part->getContentDisposition();
|
||||
return ($disp !== null && \strcasecmp($disp, $disposition) === 0);
|
||||
};
|
||||
}
|
||||
}
|
||||
325
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartHeaderContainer.php
vendored
Normal file
325
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartHeaderContainer.php
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use ArrayIterator;
|
||||
use IteratorAggregate;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Traversable;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MailMimeParser\Header\HeaderFactory;
|
||||
use ZBateson\MailMimeParser\Header\IHeader;
|
||||
|
||||
/**
|
||||
* Maintains a collection of headers for a part.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartHeaderContainer extends ErrorBag implements IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var HeaderFactory the HeaderFactory object used for created headers
|
||||
*/
|
||||
protected $headerFactory;
|
||||
|
||||
/**
|
||||
* @var string[][] Each element in the array is an array with its first
|
||||
* element set to the header's name, and the second its value.
|
||||
*/
|
||||
private $headers = [];
|
||||
|
||||
/**
|
||||
* @var \ZBateson\MailMimeParser\Header\IHeader[] Each element is an IHeader
|
||||
* representing the header at the same index in the $headers array. If
|
||||
* an IHeader has not been constructed for the header at that index,
|
||||
* the element would be set to null.
|
||||
*/
|
||||
private $headerObjects = [];
|
||||
|
||||
/**
|
||||
* @var array Maps header names by their "normalized" (lower-cased,
|
||||
* non-alphanumeric characters stripped) name to an array of indexes in
|
||||
* the $headers array. For example:
|
||||
* $headerMap['contenttype'] = [ 1, 4 ]
|
||||
* would indicate that the headers in $headers[1] and $headers[4] are
|
||||
* both headers with the name 'Content-Type' or 'contENTtype'.
|
||||
*/
|
||||
private $headerMap = [];
|
||||
|
||||
/**
|
||||
* @var int the next index to use for $headers and $headerObjects.
|
||||
*/
|
||||
private $nextIndex = 0;
|
||||
|
||||
/**
|
||||
* Pass a PartHeaderContainer as the second parameter. This is useful when
|
||||
* creating a new MimePart with this PartHeaderContainer and the original
|
||||
* container is needed for parsing and changes to the header in the part
|
||||
* should not affect parsing.
|
||||
*
|
||||
* @param PartHeaderContainer $cloneSource the original container to clone
|
||||
* from
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
HeaderFactory $headerFactory,
|
||||
?PartHeaderContainer $cloneSource = null
|
||||
) {
|
||||
parent::__construct($logger);
|
||||
$this->headerFactory = $headerFactory;
|
||||
if ($cloneSource !== null) {
|
||||
$this->headers = $cloneSource->headers;
|
||||
$this->headerObjects = $cloneSource->headerObjects;
|
||||
$this->headerMap = $cloneSource->headerMap;
|
||||
$this->nextIndex = $cloneSource->nextIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed header exists in this collection.
|
||||
*/
|
||||
public function exists(string $name, int $offset = 0) : bool
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
return isset($this->headerMap[$s][$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of header indexes with names that more closely match
|
||||
* the passed $name if available: for instance if there are two headers in
|
||||
* an email, "Content-Type" and "ContentType", and the query is for a header
|
||||
* with the name "Content-Type", only headers that match exactly
|
||||
* "Content-Type" would be returned.
|
||||
*
|
||||
* @return int[]|null
|
||||
*/
|
||||
private function getAllWithOriginalHeaderNameIfSet(string $name) : ?array
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
if (isset($this->headerMap[$s])) {
|
||||
$self = $this;
|
||||
$filtered = \array_filter($this->headerMap[$s], function($h) use ($name, $self) {
|
||||
return (\strcasecmp($self->headers[$h][0], $name) === 0);
|
||||
});
|
||||
return (!empty($filtered)) ? $filtered : $this->headerMap[$s];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IHeader object for the header with the given $name, or null
|
||||
* if none exist.
|
||||
*
|
||||
* An optional offset can be provided, which defaults to the first header in
|
||||
* the collection when more than one header with the same name exists.
|
||||
*
|
||||
* Note that mime headers aren't case sensitive.
|
||||
*/
|
||||
public function get(string $name, int $offset = 0) : ?IHeader
|
||||
{
|
||||
$a = $this->getAllWithOriginalHeaderNameIfSet($name);
|
||||
if (!empty($a) && isset($a[$offset])) {
|
||||
return $this->getByIndex($a[$offset]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IHeader object for the header with the given $name, or null
|
||||
* if none exist, using the passed $iHeaderClass to construct it.
|
||||
*
|
||||
* An optional offset can be provided, which defaults to the first header in
|
||||
* the collection when more than one header with the same name exists.
|
||||
*
|
||||
* Note that mime headers aren't case sensitive.
|
||||
*/
|
||||
public function getAs(string $name, string $iHeaderClass, int $offset = 0) : ?IHeader
|
||||
{
|
||||
$a = $this->getAllWithOriginalHeaderNameIfSet($name);
|
||||
if (!empty($a) && isset($a[$offset])) {
|
||||
return $this->getByIndexAs($a[$offset], $iHeaderClass);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all headers with the passed name.
|
||||
*
|
||||
* @return IHeader[]
|
||||
*/
|
||||
public function getAll(string $name) : array
|
||||
{
|
||||
$a = $this->getAllWithOriginalHeaderNameIfSet($name);
|
||||
if (!empty($a)) {
|
||||
$self = $this;
|
||||
return \array_map(function($index) use ($self) {
|
||||
return $self->getByIndex($index);
|
||||
}, $a);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the header in the headers array at the passed 0-based integer
|
||||
* index or null if one doesn't exist.
|
||||
*/
|
||||
private function getByIndex(int $index) : ?IHeader
|
||||
{
|
||||
if (!isset($this->headers[$index])) {
|
||||
return null;
|
||||
}
|
||||
if ($this->headerObjects[$index] === null) {
|
||||
$this->headerObjects[$index] = $this->headerFactory->newInstance(
|
||||
$this->headers[$index][0],
|
||||
$this->headers[$index][1]
|
||||
);
|
||||
}
|
||||
return $this->headerObjects[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the header in the headers array at the passed 0-based integer
|
||||
* index or null if one doesn't exist, using the passed $iHeaderClass to
|
||||
* construct it.
|
||||
*/
|
||||
private function getByIndexAs(int $index, string $iHeaderClass) : ?IHeader
|
||||
{
|
||||
if (!isset($this->headers[$index])) {
|
||||
return null;
|
||||
}
|
||||
if ($this->headerObjects[$index] !== null && \get_class($this->headerObjects[$index]) === $iHeaderClass) {
|
||||
return $this->headerObjects[$index];
|
||||
}
|
||||
return $this->headerFactory->newInstanceOf(
|
||||
$this->headers[$index][0],
|
||||
$this->headers[$index][1],
|
||||
$iHeaderClass
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the header from the collection with the passed name. Defaults to
|
||||
* removing the first instance of the header for a collection that contains
|
||||
* more than one with the same passed name.
|
||||
*
|
||||
* @return bool true if a header was found and removed.
|
||||
*/
|
||||
public function remove(string $name, int $offset = 0) : bool
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
if (isset($this->headerMap[$s][$offset])) {
|
||||
$index = $this->headerMap[$s][$offset];
|
||||
\array_splice($this->headerMap[$s], $offset, 1);
|
||||
unset($this->headers[$index], $this->headerObjects[$index]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all headers that match the passed name.
|
||||
*
|
||||
* @return bool true if one or more headers were removed.
|
||||
*/
|
||||
public function removeAll(string $name) : bool
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
if (!empty($this->headerMap[$s])) {
|
||||
foreach ($this->headerMap[$s] as $i) {
|
||||
unset($this->headers[$i], $this->headerObjects[$i]);
|
||||
}
|
||||
$this->headerMap[$s] = [];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the header to the collection.
|
||||
*/
|
||||
public function add(string $name, string $value) : static
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
$this->headers[$this->nextIndex] = [$name, $value];
|
||||
$this->headerObjects[$this->nextIndex] = null;
|
||||
if (!isset($this->headerMap[$s])) {
|
||||
$this->headerMap[$s] = [];
|
||||
}
|
||||
$this->headerMap[$s][] = $this->nextIndex;
|
||||
$this->nextIndex++;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a header exists with the passed name, and at the passed offset if more
|
||||
* than one exists, its value is updated.
|
||||
*
|
||||
* If a header with the passed name doesn't exist at the passed offset, it
|
||||
* is created at the next available offset (offset is ignored when adding).
|
||||
*/
|
||||
public function set(string $name, string $value, int $offset = 0) : static
|
||||
{
|
||||
$s = $this->headerFactory->getNormalizedHeaderName($name);
|
||||
if (!isset($this->headerMap[$s][$offset])) {
|
||||
$this->add($name, $value);
|
||||
return $this;
|
||||
}
|
||||
$i = $this->headerMap[$s][$offset];
|
||||
$this->headers[$i] = [$name, $value];
|
||||
$this->headerObjects[$i] = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of IHeader objects representing all headers in this
|
||||
* collection.
|
||||
*
|
||||
* @return IHeader[]
|
||||
*/
|
||||
public function getHeaderObjects() : array
|
||||
{
|
||||
return \array_filter(\array_map([$this, 'getByIndex'], \array_keys($this->headers)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of headers in this collection. Each returned element in
|
||||
* the array is an array with the first element set to the name, and the
|
||||
* second its value:
|
||||
*
|
||||
* [
|
||||
* [ 'Header-Name', 'Header Value' ],
|
||||
* [ 'Second-Header-Name', 'Second-Header-Value' ],
|
||||
* // etc...
|
||||
* ]
|
||||
*
|
||||
* @return string[][]
|
||||
*/
|
||||
public function getHeaders() : array
|
||||
{
|
||||
return \array_values(\array_filter($this->headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to the headers in this collection. Each returned
|
||||
* element is an array with its first element set to the header's name, and
|
||||
* the second to its value:
|
||||
*
|
||||
* [ 'Header-Name', 'Header Value' ]
|
||||
*
|
||||
* return Traversable<array<string>>
|
||||
*/
|
||||
public function getIterator() : Traversable
|
||||
{
|
||||
return new ArrayIterator($this->getHeaders());
|
||||
}
|
||||
|
||||
public function getErrorBagChildren() : array
|
||||
{
|
||||
return \array_values(\array_filter($this->headerObjects));
|
||||
}
|
||||
}
|
||||
335
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartStreamContainer.php
vendored
Normal file
335
plugins/vendor/zbateson/mail-mime-parser/src/Message/PartStreamContainer.php
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use GuzzleHttp\Psr7\CachingStream;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use ZBateson\MailMimeParser\ErrorBag;
|
||||
use ZBateson\MailMimeParser\Stream\MessagePartStreamDecorator;
|
||||
use ZBateson\MailMimeParser\Stream\StreamFactory;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
use ZBateson\MbWrapper\UnsupportedCharsetException;
|
||||
|
||||
/**
|
||||
* Holds the stream and content stream objects for a part.
|
||||
*
|
||||
* Note that streams are not explicitly closed or detached on destruction of the
|
||||
* PartSreamContainer by design: the passed StreamInterfaces will be closed on
|
||||
* their destruction when no references to them remain, which is useful when the
|
||||
* streams are passed around.
|
||||
*
|
||||
* In addition, all the streams passed to PartStreamContainer should be wrapping
|
||||
* a ZBateson\StreamDecorators\NonClosingStream unless attached to a part by a
|
||||
* user, this is because MMP uses a single seekable stream for content and wraps
|
||||
* it in ZBateson\StreamDecorators\SeekingLimitStream objects for each part.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PartStreamContainer extends ErrorBag
|
||||
{
|
||||
/**
|
||||
* @var MbWrapper to test charsets and see if they're supported.
|
||||
*/
|
||||
protected MbWrapper $mbWrapper;
|
||||
|
||||
/**
|
||||
* @var bool if false, reading from a content stream with an unsupported
|
||||
* charset will be tried with the default charset, otherwise the stream
|
||||
* created with the unsupported charset, and an exception will be
|
||||
* thrown when read from.
|
||||
*/
|
||||
protected bool $throwExceptionReadingPartContentFromUnsupportedCharsets;
|
||||
|
||||
/**
|
||||
* @var StreamFactory used to apply psr7 stream decorators to the
|
||||
* attached StreamInterface based on encoding.
|
||||
*/
|
||||
protected StreamFactory $streamFactory;
|
||||
|
||||
/**
|
||||
* @var MessagePartStreamDecorator stream containing the part's headers,
|
||||
* content and children wrapped in a MessagePartStreamDecorator
|
||||
*/
|
||||
protected MessagePartStreamDecorator $stream;
|
||||
|
||||
/**
|
||||
* @var StreamInterface a stream containing this part's content
|
||||
*/
|
||||
protected ?StreamInterface $contentStream = null;
|
||||
|
||||
/**
|
||||
* @var StreamInterface the content stream after attaching transfer encoding
|
||||
* streams to $contentStream.
|
||||
*/
|
||||
protected ?StreamInterface $decodedStream = null;
|
||||
|
||||
/**
|
||||
* @var StreamInterface attached charset stream to $decodedStream
|
||||
*/
|
||||
protected ?StreamInterface $charsetStream = null;
|
||||
|
||||
/**
|
||||
* @var bool true if the stream should be detached when this container is
|
||||
* destroyed.
|
||||
*/
|
||||
protected bool $detachParsedStream = false;
|
||||
|
||||
/**
|
||||
* @var array<string, null> map of the active encoding filter on the current handle.
|
||||
*/
|
||||
private array $encoding = [
|
||||
'type' => null,
|
||||
'filter' => null
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<string, null> map of the active charset filter on the current handle.
|
||||
*/
|
||||
private array $charset = [
|
||||
'from' => null,
|
||||
'to' => null,
|
||||
'filter' => null
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
StreamFactory $streamFactory,
|
||||
MbWrapper $mbWrapper,
|
||||
bool $throwExceptionReadingPartContentFromUnsupportedCharsets
|
||||
) {
|
||||
parent::__construct($logger);
|
||||
$this->streamFactory = $streamFactory;
|
||||
$this->mbWrapper = $mbWrapper;
|
||||
$this->throwExceptionReadingPartContentFromUnsupportedCharsets = $throwExceptionReadingPartContentFromUnsupportedCharsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the part's stream containing the part's headers, content, and
|
||||
* children.
|
||||
*/
|
||||
public function setStream(MessagePartStreamDecorator $stream) : static
|
||||
{
|
||||
$this->stream = $stream;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part's stream containing the part's headers, content, and
|
||||
* children.
|
||||
*/
|
||||
public function getStream() : MessagePartStreamDecorator
|
||||
{
|
||||
// error out if called before setStream, getStream should never return
|
||||
// null.
|
||||
$this->stream->rewind();
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there's a content stream associated with the part.
|
||||
*/
|
||||
public function hasContent() : bool
|
||||
{
|
||||
return ($this->contentStream !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the passed stream as the content portion of this
|
||||
* StreamContainer.
|
||||
*
|
||||
* The content stream would represent the content portion of $this->stream.
|
||||
*
|
||||
* If the content is overridden, $this->stream should point to a dynamic
|
||||
* {@see ZBateson\Stream\MessagePartStream} that dynamically creates the
|
||||
* RFC822 formatted message based on the IMessagePart this
|
||||
* PartStreamContainer belongs to.
|
||||
*
|
||||
* setContentStream can be called with 'null' to indicate the IMessagePart
|
||||
* does not contain any content.
|
||||
*/
|
||||
public function setContentStream(?StreamInterface $contentStream = null) : static
|
||||
{
|
||||
$this->contentStream = $contentStream;
|
||||
$this->decodedStream = null;
|
||||
$this->charsetStream = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the attached stream filter used for decoding the content
|
||||
* on the current handle is different from the one passed as an argument.
|
||||
*/
|
||||
private function isTransferEncodingFilterChanged(?string $transferEncoding) : bool
|
||||
{
|
||||
return ($transferEncoding !== $this->encoding['type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the attached stream filter used for charset conversion on
|
||||
* the current handle is different from the one needed based on the passed
|
||||
* arguments.
|
||||
*
|
||||
*/
|
||||
private function isCharsetFilterChanged(string $fromCharset, string $toCharset) : bool
|
||||
{
|
||||
return ($fromCharset !== $this->charset['from']
|
||||
|| $toCharset !== $this->charset['to']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a decoding filter to the attached content handle, for the passed
|
||||
* $transferEncoding.
|
||||
*/
|
||||
protected function attachTransferEncodingFilter(?string $transferEncoding) : static
|
||||
{
|
||||
if ($this->decodedStream !== null) {
|
||||
$this->encoding['type'] = $transferEncoding;
|
||||
$this->decodedStream = new CachingStream($this->streamFactory->getTransferEncodingDecoratedStream(
|
||||
$this->decodedStream,
|
||||
$transferEncoding
|
||||
));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a charset conversion filter to the attached content handle, for
|
||||
* the passed arguments.
|
||||
*
|
||||
* @param string $fromCharset the character set the content is encoded in
|
||||
* @param string $toCharset the target encoding to return
|
||||
*/
|
||||
protected function attachCharsetFilter(string $fromCharset, string $toCharset) : static
|
||||
{
|
||||
if ($this->charsetStream !== null) {
|
||||
if (!$this->throwExceptionReadingPartContentFromUnsupportedCharsets) {
|
||||
try {
|
||||
$this->mbWrapper->convert('t', $fromCharset, $toCharset);
|
||||
$this->charsetStream = new CachingStream($this->streamFactory->newCharsetStream(
|
||||
$this->charsetStream,
|
||||
$fromCharset,
|
||||
$toCharset
|
||||
));
|
||||
} catch (UnsupportedCharsetException $ex) {
|
||||
$this->addError('Unsupported character set found', LogLevel::ERROR, $ex);
|
||||
$this->charsetStream = new CachingStream($this->charsetStream);
|
||||
}
|
||||
} else {
|
||||
$this->charsetStream = new CachingStream($this->streamFactory->newCharsetStream(
|
||||
$this->charsetStream,
|
||||
$fromCharset,
|
||||
$toCharset
|
||||
));
|
||||
}
|
||||
$this->charsetStream->rewind();
|
||||
$this->charset['from'] = $fromCharset;
|
||||
$this->charset['to'] = $toCharset;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets just the charset stream, and rewinds the decodedStream.
|
||||
*/
|
||||
private function resetCharsetStream() : static
|
||||
{
|
||||
$this->charset = [
|
||||
'from' => null,
|
||||
'to' => null,
|
||||
'filter' => null
|
||||
];
|
||||
$this->decodedStream->rewind();
|
||||
$this->charsetStream = $this->decodedStream;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets cached encoding and charset streams, and rewinds the stream.
|
||||
*/
|
||||
public function reset() : static
|
||||
{
|
||||
$this->encoding = [
|
||||
'type' => null,
|
||||
'filter' => null
|
||||
];
|
||||
$this->charset = [
|
||||
'from' => null,
|
||||
'to' => null,
|
||||
'filter' => null
|
||||
];
|
||||
$this->contentStream->rewind();
|
||||
$this->decodedStream = $this->contentStream;
|
||||
$this->charsetStream = $this->contentStream;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks what transfer-encoding decoder stream and charset conversion
|
||||
* stream are currently attached on the underlying contentStream, and resets
|
||||
* them if the requested arguments differ from the currently assigned ones.
|
||||
*
|
||||
* @param IMessagePart $part the part the stream belongs to
|
||||
* @param string $transferEncoding the transfer encoding
|
||||
* @param string $fromCharset the character set the content is encoded in
|
||||
* @param string $toCharset the target encoding to return
|
||||
*/
|
||||
public function getContentStream(
|
||||
IMessagePart $part,
|
||||
?string $transferEncoding,
|
||||
?string $fromCharset,
|
||||
?string $toCharset
|
||||
) : ?MessagePartStreamDecorator {
|
||||
if ($this->contentStream === null) {
|
||||
return null;
|
||||
}
|
||||
if (empty($fromCharset) || empty($toCharset)) {
|
||||
return $this->getBinaryContentStream($part, $transferEncoding);
|
||||
}
|
||||
if ($this->charsetStream === null
|
||||
|| $this->isTransferEncodingFilterChanged($transferEncoding)
|
||||
|| $this->isCharsetFilterChanged($fromCharset, $toCharset)) {
|
||||
if ($this->charsetStream === null
|
||||
|| $this->isTransferEncodingFilterChanged($transferEncoding)) {
|
||||
$this->reset();
|
||||
$this->attachTransferEncodingFilter($transferEncoding);
|
||||
}
|
||||
$this->resetCharsetStream();
|
||||
$this->attachCharsetFilter($fromCharset, $toCharset);
|
||||
}
|
||||
$this->charsetStream->rewind();
|
||||
return $this->streamFactory->newDecoratedMessagePartStream(
|
||||
$part,
|
||||
$this->charsetStream
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks what transfer-encoding decoder stream is attached on the
|
||||
* underlying stream, and resets it if the requested arguments differ.
|
||||
*/
|
||||
public function getBinaryContentStream(IMessagePart $part, ?string $transferEncoding = null) : ?MessagePartStreamDecorator
|
||||
{
|
||||
if ($this->contentStream === null) {
|
||||
return null;
|
||||
}
|
||||
if ($this->decodedStream === null
|
||||
|| $this->isTransferEncodingFilterChanged($transferEncoding)) {
|
||||
$this->reset();
|
||||
$this->attachTransferEncodingFilter($transferEncoding);
|
||||
}
|
||||
$this->decodedStream->rewind();
|
||||
return $this->streamFactory->newDecoratedMessagePartStream($part, $this->decodedStream);
|
||||
}
|
||||
|
||||
protected function getErrorBagChildren() : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
120
plugins/vendor/zbateson/mail-mime-parser/src/Message/UUEncodedPart.php
vendored
Normal file
120
plugins/vendor/zbateson/mail-mime-parser/src/Message/UUEncodedPart.php
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Message;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ZBateson\MailMimeParser\MailMimeParser;
|
||||
|
||||
/**
|
||||
* Implementation of a non-mime message's uuencoded attachment part.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class UUEncodedPart extends NonMimePart implements IUUEncodedPart
|
||||
{
|
||||
/**
|
||||
* @var int the unix file permission
|
||||
*/
|
||||
protected ?int $mode = null;
|
||||
|
||||
/**
|
||||
* @var string the name of the file in the uuencoding 'header'.
|
||||
*/
|
||||
protected ?string $filename = null;
|
||||
|
||||
public function __construct(
|
||||
?int $mode = null,
|
||||
?string $filename = null,
|
||||
?IMimePart $parent = null,
|
||||
?LoggerInterface $logger = null,
|
||||
?PartStreamContainer $streamContainer = null
|
||||
) {
|
||||
$di = MailMimeParser::getGlobalContainer();
|
||||
parent::__construct(
|
||||
$logger ?? $di->get(LoggerInterface::class),
|
||||
$streamContainer ?? $di->get(PartStreamContainer::class),
|
||||
$parent
|
||||
);
|
||||
$this->mode = $mode;
|
||||
$this->filename = $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename included in the uuencoded 'begin' line for this
|
||||
* part.
|
||||
*/
|
||||
public function getFilename() : ?string
|
||||
{
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
public function setFilename(string $filename) : static
|
||||
{
|
||||
$this->filename = $filename;
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false.
|
||||
*
|
||||
* Although the part may be plain text, there is no reliable way of
|
||||
* determining its type since uuencoded 'begin' lines only include a file
|
||||
* name and no mime type. The file name's extension may be a hint.
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public function isTextPart() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'application/octet-stream'.
|
||||
*/
|
||||
public function getContentType(string $default = 'application/octet-stream') : ?string
|
||||
{
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null
|
||||
*/
|
||||
public function getCharset() : ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'attachment'.
|
||||
*/
|
||||
public function getContentDisposition(?string $default = 'attachment') : ?string
|
||||
{
|
||||
return 'attachment';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'x-uuencode'.
|
||||
*/
|
||||
public function getContentTransferEncoding(?string $default = 'x-uuencode') : ?string
|
||||
{
|
||||
return 'x-uuencode';
|
||||
}
|
||||
|
||||
public function getUnixFileMode() : ?int
|
||||
{
|
||||
return $this->mode;
|
||||
}
|
||||
|
||||
public function setUnixFileMode(int $mode) : static
|
||||
{
|
||||
$this->mode = $mode;
|
||||
$this->notify();
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
75
plugins/vendor/zbateson/mail-mime-parser/src/Parser/AbstractParserService.php
vendored
Normal file
75
plugins/vendor/zbateson/mail-mime-parser/src/Parser/AbstractParserService.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Parser;
|
||||
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxyFactory;
|
||||
|
||||
/**
|
||||
* Provides basic implementations for:
|
||||
* - IParser::setParserManager
|
||||
* - IParser::getParserMessageProxyFactory (returns $this->parserMessageProxyFactory
|
||||
* which can be set via the default constructor)
|
||||
* - IParser::getParserPartProxyFactory (returns $this->parserPartProxyFactory
|
||||
* which can be set via the default constructor)
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
abstract class AbstractParserService implements IParserService
|
||||
{
|
||||
/**
|
||||
* @var ParserPartProxyFactory the parser's message proxy factory service
|
||||
* responsible for creating an IMessage part wrapped in a
|
||||
* ParserPartProxy.
|
||||
*/
|
||||
protected ParserPartProxyFactory $parserMessageProxyFactory;
|
||||
|
||||
/**
|
||||
* @var ParserPartProxyFactory the parser's part proxy factory service
|
||||
* responsible for creating IMessagePart parts wrapped in a
|
||||
* ParserPartProxy.
|
||||
*/
|
||||
protected ParserPartProxyFactory $parserPartProxyFactory;
|
||||
|
||||
/**
|
||||
* @var PartBuilderFactory Service for creating PartBuilder objects for new
|
||||
* children.
|
||||
*/
|
||||
protected PartBuilderFactory $partBuilderFactory;
|
||||
|
||||
/**
|
||||
* @var ParserManagerService the ParserManager, which should call setParserManager
|
||||
* when the parser is added.
|
||||
*/
|
||||
protected ParserManagerService $parserManager;
|
||||
|
||||
public function __construct(
|
||||
ParserPartProxyFactory $parserMessageProxyFactory,
|
||||
ParserPartProxyFactory $parserPartProxyFactory,
|
||||
PartBuilderFactory $partBuilderFactory
|
||||
) {
|
||||
$this->parserMessageProxyFactory = $parserMessageProxyFactory;
|
||||
$this->parserPartProxyFactory = $parserPartProxyFactory;
|
||||
$this->partBuilderFactory = $partBuilderFactory;
|
||||
}
|
||||
|
||||
public function setParserManager(ParserManagerService $pm) : static
|
||||
{
|
||||
$this->parserManager = $pm;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getParserMessageProxyFactory() : ParserPartProxyFactory
|
||||
{
|
||||
return $this->parserMessageProxyFactory;
|
||||
}
|
||||
|
||||
public function getParserPartProxyFactory() : ParserPartProxyFactory
|
||||
{
|
||||
return $this->parserPartProxyFactory;
|
||||
}
|
||||
}
|
||||
22
plugins/vendor/zbateson/mail-mime-parser/src/Parser/CompatibleParserNotFoundException.php
vendored
Normal file
22
plugins/vendor/zbateson/mail-mime-parser/src/Parser/CompatibleParserNotFoundException.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Parser;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Exception thrown if the ParserManagerService doesn't contain a parser that
|
||||
* can handle a given type of part. The default configuration of MailMimeParser
|
||||
* uses NonMimeParserService that is a 'catch-all', so this would indicate a
|
||||
* configuration error.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class CompatibleParserNotFoundException extends RuntimeException
|
||||
{
|
||||
}
|
||||
67
plugins/vendor/zbateson/mail-mime-parser/src/Parser/HeaderParserService.php
vendored
Normal file
67
plugins/vendor/zbateson/mail-mime-parser/src/Parser/HeaderParserService.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Parser;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
use ZBateson\MailMimeParser\Message\PartHeaderContainer;
|
||||
|
||||
/**
|
||||
* Reads headers from an input stream, adding them to a PartHeaderContainer.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class HeaderParserService
|
||||
{
|
||||
/**
|
||||
* Ensures the header isn't empty and contains a colon separator character,
|
||||
* then splits it and adds it to the passed PartHeaderContainer.
|
||||
*
|
||||
* @param int $offset read offset for error reporting
|
||||
* @param string $header the header line
|
||||
* @param PartHeaderContainer $headerContainer the container
|
||||
*/
|
||||
private function addRawHeaderToPart(int $offset, string $header, PartHeaderContainer $headerContainer) : static
|
||||
{
|
||||
if ($header !== '') {
|
||||
if (\strpos($header, ':') !== false) {
|
||||
$a = \explode(':', $header, 2);
|
||||
$headerContainer->add($a[0], \trim($a[1]));
|
||||
} else {
|
||||
$headerContainer->addError(
|
||||
"Invalid header found at offset: $offset",
|
||||
LogLevel::ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads header lines up to an empty line, adding them to the passed
|
||||
* PartHeaderContainer.
|
||||
*
|
||||
* @param resource $handle The resource handle to read from.
|
||||
* @param PartHeaderContainer $container the container to add headers to.
|
||||
*/
|
||||
public function parse($handle, PartHeaderContainer $container) : static
|
||||
{
|
||||
$header = '';
|
||||
do {
|
||||
$offset = \ftell($handle);
|
||||
$line = MessageParserService::readLine($handle);
|
||||
if ($line === false || $line === '' || $line[0] !== "\t" && $line[0] !== ' ') {
|
||||
$this->addRawHeaderToPart($offset, $header, $container);
|
||||
$header = '';
|
||||
} else {
|
||||
$line = "\r\n" . $line;
|
||||
}
|
||||
$header .= \rtrim($line, "\r\n");
|
||||
} while ($header !== '');
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
91
plugins/vendor/zbateson/mail-mime-parser/src/Parser/IParserService.php
vendored
Normal file
91
plugins/vendor/zbateson/mail-mime-parser/src/Parser/IParserService.php
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Parser;
|
||||
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserMimePartProxy;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxy;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxyFactory;
|
||||
|
||||
/**
|
||||
* Interface defining a message part parser.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
interface IParserService
|
||||
{
|
||||
/**
|
||||
* Sets up the passed ParserManager as the ParserManager for this part,
|
||||
* which should be used when a new part is created (after its headers are
|
||||
* read and a PartBuilder is created from it.)
|
||||
*
|
||||
* @param ParserManagerService $pm The ParserManager to set.
|
||||
*/
|
||||
public function setParserManager(ParserManagerService $pm) : static;
|
||||
|
||||
/**
|
||||
* Called by the ParserManager to determine if the passed PartBuilder is a
|
||||
* part handled by this IParser.
|
||||
*/
|
||||
public function canParse(PartBuilder $part) : bool;
|
||||
|
||||
/**
|
||||
* Returns the ParserPartProxyFactory responsible for creating IMessage
|
||||
* parts for this parser.
|
||||
*
|
||||
* This is called by ParserManager after 'canParse' if it returns true so
|
||||
* a ParserPartProxy can be created out of the PartBuilder.
|
||||
*/
|
||||
public function getParserMessageProxyFactory() : ParserPartProxyFactory;
|
||||
|
||||
/**
|
||||
* Returns the ParserPartProxyFactory responsible for creating IMessagePart
|
||||
* parts for this parser.
|
||||
*
|
||||
* This is called by ParserManager after 'canParse' if it returns true so
|
||||
* a ParserPartProxy can be created out of the PartBuilder.
|
||||
*/
|
||||
public function getParserPartProxyFactory() : ParserPartProxyFactory;
|
||||
|
||||
/**
|
||||
* Performs read operations for content from the stream of the passed
|
||||
* ParserPartProxy, and setting content bounds for the part in the passed
|
||||
* ParserPartProxy.
|
||||
*
|
||||
* The implementation should call $proxy->setStreamContentStartPos() and
|
||||
* $proxy->setStreamContentAndPartEndPos() so an IMessagePart can return
|
||||
* content from the raw message.
|
||||
*
|
||||
* Reading should stop once the end of the current part's content has been
|
||||
* reached or the end of the message has been reached. If the end of the
|
||||
* message has been reached $proxy->setEof() should be called in addition to
|
||||
* setStreamContentAndPartEndPos().
|
||||
*/
|
||||
public function parseContent(ParserPartProxy $proxy) : static;
|
||||
|
||||
/**
|
||||
* Performs read operations to read children from the passed $proxy, using
|
||||
* its stream, and reading up to (and not including) the beginning of the
|
||||
* child's content if another child exists.
|
||||
*
|
||||
* The implementation should:
|
||||
* 1. Return null if there are no more children.
|
||||
* 2. Read headers
|
||||
* 3. Create a PartBuilder (adding the passed $proxy as its parent)
|
||||
* 4. Call ParserManager::createParserProxyFor() on the ParserManager
|
||||
* previously set by a call to setParserManager(), which may determine
|
||||
* that a different parser is responsible for parts represented by
|
||||
* the headers and PartBuilder passed to it.
|
||||
*
|
||||
* The method should then return the ParserPartProxy returned by the
|
||||
* ParserManager, or null if there are no more children to read.
|
||||
*
|
||||
* @return ParserPartProxy|null The child ParserPartProxy or null if there
|
||||
* are no more children under $proxy.
|
||||
*/
|
||||
public function parseNextChild(ParserMimePartProxy $proxy) : ?ParserPartProxy;
|
||||
}
|
||||
95
plugins/vendor/zbateson/mail-mime-parser/src/Parser/MessageParserService.php
vendored
Normal file
95
plugins/vendor/zbateson/mail-mime-parser/src/Parser/MessageParserService.php
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Parser;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use ZBateson\MailMimeParser\IMessage;
|
||||
use ZBateson\MailMimeParser\Message\Factory\PartHeaderContainerFactory;
|
||||
|
||||
/**
|
||||
* Parses a mail mime message into its component parts. To invoke, call
|
||||
* {@see MailMimeParser::parse()}.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class MessageParserService
|
||||
{
|
||||
/**
|
||||
* @var PartHeaderContainerFactory To create a container to read the
|
||||
* message's headers into.
|
||||
*/
|
||||
protected PartHeaderContainerFactory $partHeaderContainerFactory;
|
||||
|
||||
/**
|
||||
* @var ParserManagerService To figure out what parser is responsible for parsing a
|
||||
* message.
|
||||
*/
|
||||
protected ParserManagerService $parserManager;
|
||||
|
||||
/**
|
||||
* @var PartBuilderFactory To create a PartBuilder representing this
|
||||
* message, and to pass it to ParserManager.
|
||||
*/
|
||||
protected PartBuilderFactory $partBuilderFactory;
|
||||
|
||||
/**
|
||||
* @var HeaderParserService To parse the headers into a PartHeaderContainer.
|
||||
*/
|
||||
protected HeaderParserService $headerParser;
|
||||
|
||||
public function __construct(
|
||||
PartBuilderFactory $pbf,
|
||||
PartHeaderContainerFactory $phcf,
|
||||
ParserManagerService $pm,
|
||||
HeaderParserService $hp
|
||||
) {
|
||||
$this->partBuilderFactory = $pbf;
|
||||
$this->partHeaderContainerFactory = $phcf;
|
||||
$this->parserManager = $pm;
|
||||
$this->headerParser = $hp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to read a line of up to 4096 characters from the
|
||||
* passed resource handle.
|
||||
*
|
||||
* If the line is larger than 4096 characters, the remaining characters in
|
||||
* the line are read and discarded, and only the first 4096 characters are
|
||||
* returned.
|
||||
*
|
||||
* @param resource $handle
|
||||
* @return string|false the read line or false on EOF or on error.
|
||||
*/
|
||||
public static function readLine($handle) : string|false
|
||||
{
|
||||
$size = 4096;
|
||||
$ret = $line = \fgets($handle, $size);
|
||||
while (\strlen($line) === $size - 1 && \substr($line, -1) !== "\n") {
|
||||
$line = \fgets($handle, $size);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the passed stream into an {@see ZBateson\MailMimeParser\IMessage}
|
||||
* object and returns it.
|
||||
*
|
||||
* @param StreamInterface $stream the stream to parse the message from
|
||||
*/
|
||||
public function parse(StreamInterface $stream) : IMessage
|
||||
{
|
||||
$headerContainer = $this->partHeaderContainerFactory->newInstance();
|
||||
$partBuilder = $this->partBuilderFactory->newPartBuilder($headerContainer, $stream);
|
||||
$this->headerParser->parse(
|
||||
$partBuilder->getMessageResourceHandle(),
|
||||
$headerContainer
|
||||
);
|
||||
$proxy = $this->parserManager->createParserProxyFor($partBuilder);
|
||||
return $proxy->getPart();
|
||||
}
|
||||
}
|
||||
167
plugins/vendor/zbateson/mail-mime-parser/src/Parser/MimeParserService.php
vendored
Normal file
167
plugins/vendor/zbateson/mail-mime-parser/src/Parser/MimeParserService.php
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Parser;
|
||||
|
||||
use ZBateson\MailMimeParser\Message\Factory\PartHeaderContainerFactory;
|
||||
use ZBateson\MailMimeParser\Message\PartHeaderContainer;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserMessageProxyFactory;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserMimePartProxy;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserMimePartProxyFactory;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxy;
|
||||
|
||||
/**
|
||||
* Parses content and children of MIME parts.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class MimeParserService extends AbstractParserService
|
||||
{
|
||||
/**
|
||||
* @var PartHeaderContainerFactory Factory service for creating
|
||||
* PartHeaderContainers for headers.
|
||||
*/
|
||||
protected PartHeaderContainerFactory $partHeaderContainerFactory;
|
||||
|
||||
/**
|
||||
* @var HeaderParserService The HeaderParser service.
|
||||
*/
|
||||
protected HeaderParserService $headerParser;
|
||||
|
||||
public function __construct(
|
||||
ParserMessageProxyFactory $parserMessageProxyFactory,
|
||||
ParserMimePartProxyFactory $parserMimePartProxyFactory,
|
||||
PartBuilderFactory $partBuilderFactory,
|
||||
PartHeaderContainerFactory $partHeaderContainerFactory,
|
||||
HeaderParserService $headerParser
|
||||
) {
|
||||
parent::__construct($parserMessageProxyFactory, $parserMimePartProxyFactory, $partBuilderFactory);
|
||||
$this->partHeaderContainerFactory = $partHeaderContainerFactory;
|
||||
$this->headerParser = $headerParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed PartBuilder::isMime() method returns true.
|
||||
*
|
||||
*/
|
||||
public function canParse(PartBuilder $part) : bool
|
||||
{
|
||||
return $part->isMime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to 2048 bytes of input from the passed resource handle,
|
||||
* discarding portions of a line that are longer than that, and returning
|
||||
* the read portions of the line.
|
||||
*
|
||||
* The method also calls $proxy->setLastLineEndingLength which is used in
|
||||
* findContentBoundary() to set the exact end byte of a part.
|
||||
*
|
||||
* @param resource $handle
|
||||
*/
|
||||
private function readBoundaryLine($handle, ParserMimePartProxy $proxy) : string
|
||||
{
|
||||
$size = 2048;
|
||||
$isCut = false;
|
||||
$line = \fgets($handle, $size);
|
||||
while (\strlen($line) === $size - 1 && \substr($line, -1) !== "\n") {
|
||||
$line = \fgets($handle, $size);
|
||||
$isCut = true;
|
||||
}
|
||||
$ret = \rtrim($line, "\r\n");
|
||||
$proxy->setLastLineEndingLength(\strlen($line) - \strlen($ret));
|
||||
return ($isCut) ? '' : $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads 2048-byte lines from the passed $handle, calling
|
||||
* $partBuilder->setEndBoundaryFound with the passed line until it returns
|
||||
* true or the stream is at EOF.
|
||||
*
|
||||
* setEndBoundaryFound returns true if the passed line matches a boundary
|
||||
* for the $partBuilder itself or any of its parents.
|
||||
*
|
||||
* Lines longer than 2048 bytes are returned as single lines of 2048 bytes,
|
||||
* the longer line is not returned separately but is simply discarded.
|
||||
*
|
||||
* Once a boundary is found, setStreamPartAndContentEndPos is called with
|
||||
* the passed $handle's read pos before the boundary and its line separator
|
||||
* were read.
|
||||
*/
|
||||
private function findContentBoundary(ParserMimePartProxy $proxy) : static
|
||||
{
|
||||
$handle = $proxy->getMessageResourceHandle();
|
||||
// last separator before a boundary belongs to the boundary, and is not
|
||||
// part of the current part, if a part is immediately followed by a
|
||||
// boundary, this could result in a '-1' or '-2' content length
|
||||
while (!\feof($handle)) {
|
||||
$endPos = \ftell($handle) - $proxy->getLastLineEndingLength();
|
||||
$line = $this->readBoundaryLine($handle, $proxy);
|
||||
if (\substr($line, 0, 2) === '--' && $proxy->setEndBoundaryFound($line)) {
|
||||
$proxy->setStreamPartAndContentEndPos($endPos);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
$proxy->setStreamPartAndContentEndPos(\ftell($handle));
|
||||
$proxy->setEof();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function parseContent(ParserPartProxy $proxy) : static
|
||||
{
|
||||
$proxy->setStreamContentStartPos($proxy->getMessageResourceHandlePos());
|
||||
$this->findContentBoundary($proxy);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the header parser to fill the passed $headerContainer, then calls
|
||||
* $this->parserManager->createParserProxyFor($child);
|
||||
*
|
||||
* The method first checks though if the 'part' represents hidden content
|
||||
* past a MIME end boundary, which some messages like to include, for
|
||||
* instance:
|
||||
*
|
||||
* ```
|
||||
* --outer-boundary--
|
||||
* --boundary
|
||||
* content
|
||||
* --boundary--
|
||||
* some hidden information
|
||||
* --outer-boundary--
|
||||
* ```
|
||||
*
|
||||
* In this case, $this->parserPartProxyFactory is called directly to create
|
||||
* a part, $this->parseContent is called immediately to parse it and discard
|
||||
* it, and null is returned.
|
||||
*/
|
||||
private function createPart(ParserMimePartProxy $parent, PartHeaderContainer $headerContainer, PartBuilder $child) : ?ParserPartProxy
|
||||
{
|
||||
if (!$parent->isEndBoundaryFound()) {
|
||||
$this->headerParser->parse(
|
||||
$child->getMessageResourceHandle(),
|
||||
$headerContainer
|
||||
);
|
||||
$parserProxy = $this->parserManager->createParserProxyFor($child);
|
||||
return $parserProxy;
|
||||
}
|
||||
// reads content past an end boundary if there is any
|
||||
$parserProxy = $this->parserPartProxyFactory->newInstance($child, $this);
|
||||
$this->parseContent($parserProxy);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function parseNextChild(ParserMimePartProxy $proxy) : ?ParserPartProxy
|
||||
{
|
||||
if ($proxy->isParentBoundaryFound()) {
|
||||
return null;
|
||||
}
|
||||
$headerContainer = $this->partHeaderContainerFactory->newInstance();
|
||||
$child = $this->partBuilderFactory->newChildPartBuilder($headerContainer, $proxy);
|
||||
return $this->createPart($proxy, $headerContainer, $child);
|
||||
}
|
||||
}
|
||||
111
plugins/vendor/zbateson/mail-mime-parser/src/Parser/NonMimeParserService.php
vendored
Normal file
111
plugins/vendor/zbateson/mail-mime-parser/src/Parser/NonMimeParserService.php
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Parser;
|
||||
|
||||
use ZBateson\MailMimeParser\Parser\Part\UUEncodedPartHeaderContainerFactory;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserMimePartProxy;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserNonMimeMessageProxy;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserNonMimeMessageProxyFactory;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxy;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserUUEncodedPartProxy;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserUUEncodedPartProxyFactory;
|
||||
|
||||
/**
|
||||
* Parses content for non-mime messages and uu-encoded child parts.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class NonMimeParserService extends AbstractParserService
|
||||
{
|
||||
protected UUEncodedPartHeaderContainerFactory $partHeaderContainerFactory;
|
||||
|
||||
public function __construct(
|
||||
ParserNonMimeMessageProxyFactory $parserNonMimeMessageProxyFactory,
|
||||
ParserUUEncodedPartProxyFactory $parserUuEncodedPartProxyFactory,
|
||||
PartBuilderFactory $partBuilderFactory,
|
||||
UUEncodedPartHeaderContainerFactory $uuEncodedPartHeaderContainerFactory
|
||||
) {
|
||||
parent::__construct($parserNonMimeMessageProxyFactory, $parserUuEncodedPartProxyFactory, $partBuilderFactory);
|
||||
$this->partHeaderContainerFactory = $uuEncodedPartHeaderContainerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns true, and should therefore be the last parser reached by
|
||||
* a ParserManager.
|
||||
*/
|
||||
public function canParse(PartBuilder $part) : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a UUEncodedPartHeaderContainer attached to a PartBuilder, and
|
||||
* calls $this->parserManager->createParserProxyFor().
|
||||
*
|
||||
* It also sets the PartBuilder's stream part start pos and content start
|
||||
* pos to that of $parent->getNextParStart() (since a 'begin' line is read
|
||||
* prior to another child being created, see parseNextPart()).
|
||||
*/
|
||||
private function createPart(ParserNonMimeMessageProxy $parent) : ParserPartProxy
|
||||
{
|
||||
$hc = $this->partHeaderContainerFactory->newInstance($parent->getNextPartMode(), $parent->getNextPartFilename());
|
||||
$pb = $this->partBuilderFactory->newChildPartBuilder($hc, $parent);
|
||||
$proxy = $this->parserManager->createParserProxyFor($pb);
|
||||
$pb->setStreamPartStartPos($parent->getNextPartStart());
|
||||
$pb->setStreamContentStartPos($parent->getNextPartStart());
|
||||
return $proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads content from the passed ParserPartProxy's stream till a uu-encoded
|
||||
* 'begin' line is found, setting $proxy->setStreamPartContentAndEndPos() to
|
||||
* the last byte read before the begin line.
|
||||
*
|
||||
* @param ParserNonMimeMessageProxy|ParserUUEncodedPartProxy $proxy
|
||||
*/
|
||||
private function parseNextPart(ParserPartProxy $proxy) : static
|
||||
{
|
||||
$handle = $proxy->getMessageResourceHandle();
|
||||
while (!\feof($handle)) {
|
||||
$start = \ftell($handle);
|
||||
$line = \trim(MessageParserService::readLine($handle));
|
||||
if (\preg_match('/^begin ([0-7]{3}) (.*)$/', $line, $matches)) {
|
||||
$proxy->setNextPartStart($start);
|
||||
$proxy->setNextPartMode((int) $matches[1]);
|
||||
$proxy->setNextPartFilename($matches[2]);
|
||||
return $this;
|
||||
}
|
||||
$proxy->setStreamPartAndContentEndPos(\ftell($handle));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function parseContent(ParserPartProxy $proxy) : static
|
||||
{
|
||||
$handle = $proxy->getMessageResourceHandle();
|
||||
if ($proxy->getNextPartStart() !== null || \feof($handle)) {
|
||||
return $this;
|
||||
}
|
||||
if ($proxy->getStreamContentStartPos() === null) {
|
||||
$proxy->setStreamContentStartPos(\ftell($handle));
|
||||
}
|
||||
$this->parseNextPart($proxy);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function parseNextChild(ParserMimePartProxy $proxy) : ?ParserPartProxy
|
||||
{
|
||||
$handle = $proxy->getMessageResourceHandle();
|
||||
if ($proxy->getNextPartStart() === null || \feof($handle)) {
|
||||
return null;
|
||||
}
|
||||
$child = $this->createPart($proxy);
|
||||
$proxy->clearNextPart();
|
||||
return $child;
|
||||
}
|
||||
}
|
||||
92
plugins/vendor/zbateson/mail-mime-parser/src/Parser/ParserManagerService.php
vendored
Normal file
92
plugins/vendor/zbateson/mail-mime-parser/src/Parser/ParserManagerService.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Parser;
|
||||
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxy;
|
||||
|
||||
/**
|
||||
* Manages a prioritized list of IParser objects for parsing messages and parts
|
||||
* and creating proxied parts.
|
||||
*
|
||||
* The default ParserManager sets up a MimeParser in priority 0, and a
|
||||
* NonMimeParser in priority 1.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ParserManagerService
|
||||
{
|
||||
/**
|
||||
* @var IParserService[] List of parsers in order of priority (0 is highest
|
||||
* priority).
|
||||
*/
|
||||
protected array $parsers = [];
|
||||
|
||||
public function __construct(MimeParserService $mimeParser, NonMimeParserService $nonMimeParser)
|
||||
{
|
||||
$this->setParsers([$mimeParser, $nonMimeParser]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the internal prioritized list of parses with the passed list,
|
||||
* calling $parser->setParserManager($this) on each one.
|
||||
*
|
||||
* @param IParserService[] $parsers
|
||||
*/
|
||||
public function setParsers(array $parsers) : static
|
||||
{
|
||||
foreach ($parsers as $parser) {
|
||||
$parser->setParserManager($this);
|
||||
}
|
||||
$this->parsers = $parsers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an IParser at the highest priority (up front), calling
|
||||
* $parser->setParserManager($this) on it.
|
||||
*
|
||||
* @param IParserService $parser The parser to add.
|
||||
*/
|
||||
public function prependParser(IParserService $parser) : static
|
||||
{
|
||||
$parser->setParserManager($this);
|
||||
\array_unshift($this->parsers, $parser);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ParserPartProxy for the passed $partBuilder using a compatible
|
||||
* IParser.
|
||||
*
|
||||
* Loops through registered IParsers calling 'canParse()' on each with the
|
||||
* passed PartBuilder, then calling either 'getParserMessageProxyFactory()'
|
||||
* or 'getParserPartProxyFactory()' depending on if the PartBuilder has a
|
||||
* parent, and finally calling 'newInstance' on the returned
|
||||
* ParserPartProxyFactory passing it the IParser, and returning the new
|
||||
* ParserPartProxy instance that was created.
|
||||
*
|
||||
* @param PartBuilder $partBuilder The PartBuilder to wrap in a proxy with
|
||||
* an IParser
|
||||
* @throws CompatibleParserNotFoundException if a compatible parser for the
|
||||
* type is not configured.
|
||||
* @return ParserPartProxy The created ParserPartProxy tied to a new
|
||||
* IMessagePart and associated IParser.
|
||||
*/
|
||||
public function createParserProxyFor(PartBuilder $partBuilder) : ParserPartProxy
|
||||
{
|
||||
foreach ($this->parsers as $parser) {
|
||||
if ($parser->canParse($partBuilder)) {
|
||||
$factory = ($partBuilder->getParent() === null) ?
|
||||
$parser->getParserMessageProxyFactory() :
|
||||
$parser->getParserPartProxyFactory();
|
||||
return $factory->newInstance($partBuilder, $parser);
|
||||
}
|
||||
}
|
||||
throw new CompatibleParserNotFoundException('Compatible parser for a part cannot be found with content-type: ' . $partBuilder->getHeaderContainer()->get('Content-Type'));
|
||||
}
|
||||
}
|
||||
53
plugins/vendor/zbateson/mail-mime-parser/src/Parser/Part/ParserPartChildrenContainer.php
vendored
Normal file
53
plugins/vendor/zbateson/mail-mime-parser/src/Parser/Part/ParserPartChildrenContainer.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\MailMimeParser project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\MailMimeParser\Parser\Part;
|
||||
|
||||
use ZBateson\MailMimeParser\Message\PartChildrenContainer;
|
||||
use ZBateson\MailMimeParser\Parser\Proxy\ParserMimePartProxy;
|
||||
|
||||
/**
|
||||
* A child container that proxies calls to a parser when attempting to access
|
||||
* child parts.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ParserPartChildrenContainer extends PartChildrenContainer
|
||||
{
|
||||
/**
|
||||
* @var ParserMimePartProxy The parser to proxy requests to when trying to
|
||||
* get child parts.
|
||||
*/
|
||||
protected ParserMimePartProxy $parserProxy;
|
||||
|
||||
/**
|
||||
* @var bool Set to true once all parts have been parsed, and requests to
|
||||
* the proxy won't result in any more child parts.
|
||||
*/
|
||||
private bool $allParsed = false;
|
||||
|
||||
public function __construct(ParserMimePartProxy $parserProxy)
|
||||
{
|
||||
parent::__construct([]);
|
||||
$this->parserProxy = $parserProxy;
|
||||
}
|
||||
|
||||
public function offsetExists($offset) : bool
|
||||
{
|
||||
$exists = parent::offsetExists($offset);
|
||||
while (!$exists && !$this->allParsed) {
|
||||
$child = $this->parserProxy->popNextChild();
|
||||
if ($child === null) {
|
||||
$this->allParsed = true;
|
||||
} else {
|
||||
$this->add($child);
|
||||
}
|
||||
$exists = parent::offsetExists($offset);
|
||||
}
|
||||
return $exists;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user