summaryrefslogtreecommitdiff
path: root/vendor/symfony/mime/Header
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/symfony/mime/Header')
-rw-r--r--vendor/symfony/mime/Header/AbstractHeader.php281
-rw-r--r--vendor/symfony/mime/Header/DateHeader.php71
-rw-r--r--vendor/symfony/mime/Header/HeaderInterface.php67
-rw-r--r--vendor/symfony/mime/Header/Headers.php285
-rw-r--r--vendor/symfony/mime/Header/IdentificationHeader.php115
-rw-r--r--vendor/symfony/mime/Header/MailboxHeader.php93
-rw-r--r--vendor/symfony/mime/Header/MailboxListHeader.php139
-rw-r--r--vendor/symfony/mime/Header/ParameterizedHeader.php176
-rw-r--r--vendor/symfony/mime/Header/PathHeader.php67
-rw-r--r--vendor/symfony/mime/Header/UnstructuredHeader.php71
10 files changed, 1365 insertions, 0 deletions
diff --git a/vendor/symfony/mime/Header/AbstractHeader.php b/vendor/symfony/mime/Header/AbstractHeader.php
new file mode 100644
index 0000000000..517ee8dfb2
--- /dev/null
+++ b/vendor/symfony/mime/Header/AbstractHeader.php
@@ -0,0 +1,281 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+use Symfony\Component\Mime\Encoder\QpMimeHeaderEncoder;
+
+/**
+ * An abstract base MIME Header.
+ *
+ * @author Chris Corbyn
+ *
+ * @experimental in 4.3
+ */
+abstract class AbstractHeader implements HeaderInterface
+{
+ const PHRASE_PATTERN = '(?:(?:(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]+(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?)|(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?"((?:(?:[ \t]*(?:\r\n))?[ \t])?(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])))*(?:(?:[ \t]*(?:\r\n))?[ \t])?"(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?))+?)';
+
+ private static $encoder;
+
+ private $name;
+ private $lineLength = 76;
+ private $lang;
+ private $charset = 'utf-8';
+
+ public function __construct(string $name)
+ {
+ $this->name = $name;
+ }
+
+ public function setCharset(string $charset)
+ {
+ $this->charset = $charset;
+ }
+
+ public function getCharset(): ?string
+ {
+ return $this->charset;
+ }
+
+ /**
+ * Set the language used in this Header.
+ *
+ * For example, for US English, 'en-us'.
+ */
+ public function setLanguage(string $lang)
+ {
+ $this->lang = $lang;
+ }
+
+ public function getLanguage(): ?string
+ {
+ return $this->lang;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public function setMaxLineLength(int $lineLength)
+ {
+ $this->lineLength = $lineLength;
+ }
+
+ public function getMaxLineLength(): int
+ {
+ return $this->lineLength;
+ }
+
+ public function toString(): string
+ {
+ return $this->tokensToString($this->toTokens());
+ }
+
+ /**
+ * Produces a compliant, formatted RFC 2822 'phrase' based on the string given.
+ *
+ * @param string $string as displayed
+ * @param bool $shorten the first line to make remove for header name
+ */
+ protected function createPhrase(HeaderInterface $header, string $string, string $charset, bool $shorten = false): string
+ {
+ // Treat token as exactly what was given
+ $phraseStr = $string;
+
+ // If it's not valid
+ if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) {
+ // .. but it is just ascii text, try escaping some characters
+ // and make it a quoted-string
+ if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) {
+ foreach (['\\', '"'] as $char) {
+ $phraseStr = str_replace($char, '\\'.$char, $phraseStr);
+ }
+ $phraseStr = '"'.$phraseStr.'"';
+ } else {
+ // ... otherwise it needs encoding
+ // Determine space remaining on line if first line
+ if ($shorten) {
+ $usedLength = \strlen($header->getName().': ');
+ } else {
+ $usedLength = 0;
+ }
+ $phraseStr = $this->encodeWords($header, $string, $usedLength);
+ }
+ }
+
+ return $phraseStr;
+ }
+
+ /**
+ * Encode needed word tokens within a string of input.
+ */
+ protected function encodeWords(HeaderInterface $header, string $input, int $usedLength = -1): string
+ {
+ $value = '';
+ $tokens = $this->getEncodableWordTokens($input);
+ foreach ($tokens as $token) {
+ // See RFC 2822, Sect 2.2 (really 2.2 ??)
+ if ($this->tokenNeedsEncoding($token)) {
+ // Don't encode starting WSP
+ $firstChar = substr($token, 0, 1);
+ switch ($firstChar) {
+ case ' ':
+ case "\t":
+ $value .= $firstChar;
+ $token = substr($token, 1);
+ }
+
+ if (-1 == $usedLength) {
+ $usedLength = \strlen($header->getName().': ') + \strlen($value);
+ }
+ $value .= $this->getTokenAsEncodedWord($token, $usedLength);
+ } else {
+ $value .= $token;
+ }
+ }
+
+ return $value;
+ }
+
+ protected function tokenNeedsEncoding(string $token): bool
+ {
+ return (bool) preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token);
+ }
+
+ /**
+ * Splits a string into tokens in blocks of words which can be encoded quickly.
+ *
+ * @return string[]
+ */
+ protected function getEncodableWordTokens(string $string): array
+ {
+ $tokens = [];
+ $encodedToken = '';
+ // Split at all whitespace boundaries
+ foreach (preg_split('~(?=[\t ])~', $string) as $token) {
+ if ($this->tokenNeedsEncoding($token)) {
+ $encodedToken .= $token;
+ } else {
+ if (\strlen($encodedToken) > 0) {
+ $tokens[] = $encodedToken;
+ $encodedToken = '';
+ }
+ $tokens[] = $token;
+ }
+ }
+ if (\strlen($encodedToken)) {
+ $tokens[] = $encodedToken;
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Get a token as an encoded word for safe insertion into headers.
+ */
+ protected function getTokenAsEncodedWord(string $token, int $firstLineOffset = 0): string
+ {
+ if (null === self::$encoder) {
+ self::$encoder = new QpMimeHeaderEncoder();
+ }
+
+ // Adjust $firstLineOffset to account for space needed for syntax
+ $charsetDecl = $this->charset;
+ if (null !== $this->lang) {
+ $charsetDecl .= '*'.$this->lang;
+ }
+ $encodingWrapperLength = \strlen('=?'.$charsetDecl.'?'.self::$encoder->getName().'??=');
+
+ if ($firstLineOffset >= 75) {
+ //Does this logic need to be here?
+ $firstLineOffset = 0;
+ }
+
+ $encodedTextLines = explode("\r\n",
+ self::$encoder->encodeString($token, $this->charset, $firstLineOffset, 75 - $encodingWrapperLength)
+ );
+
+ if ('iso-2022-jp' !== strtolower($this->charset)) {
+ // special encoding for iso-2022-jp using mb_encode_mimeheader
+ foreach ($encodedTextLines as $lineNum => $line) {
+ $encodedTextLines[$lineNum] = '=?'.$charsetDecl.'?'.self::$encoder->getName().'?'.$line.'?=';
+ }
+ }
+
+ return implode("\r\n ", $encodedTextLines);
+ }
+
+ /**
+ * Generates tokens from the given string which include CRLF as individual tokens.
+ *
+ * @return string[]
+ */
+ protected function generateTokenLines(string $token): array
+ {
+ return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE);
+ }
+
+ /**
+ * Generate a list of all tokens in the final header.
+ */
+ protected function toTokens(string $string = null): array
+ {
+ if (null === $string) {
+ $string = $this->getBodyAsString();
+ }
+
+ $tokens = [];
+ // Generate atoms; split at all invisible boundaries followed by WSP
+ foreach (preg_split('~(?=[ \t])~', $string) as $token) {
+ $newTokens = $this->generateTokenLines($token);
+ foreach ($newTokens as $newToken) {
+ $tokens[] = $newToken;
+ }
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Takes an array of tokens which appear in the header and turns them into
+ * an RFC 2822 compliant string, adding FWSP where needed.
+ *
+ * @param string[] $tokens
+ */
+ private function tokensToString(array $tokens): string
+ {
+ $lineCount = 0;
+ $headerLines = [];
+ $headerLines[] = $this->name.': ';
+ $currentLine = &$headerLines[$lineCount++];
+
+ // Build all tokens back into compliant header
+ foreach ($tokens as $i => $token) {
+ // Line longer than specified maximum or token was just a new line
+ if (("\r\n" === $token) ||
+ ($i > 0 && \strlen($currentLine.$token) > $this->lineLength)
+ && 0 < \strlen($currentLine)) {
+ $headerLines[] = '';
+ $currentLine = &$headerLines[$lineCount++];
+ }
+
+ // Append token to the line
+ if ("\r\n" !== $token) {
+ $currentLine .= $token;
+ }
+ }
+
+ // Implode with FWS (RFC 2822, 2.2.3)
+ return implode("\r\n", $headerLines);
+ }
+}
diff --git a/vendor/symfony/mime/Header/DateHeader.php b/vendor/symfony/mime/Header/DateHeader.php
new file mode 100644
index 0000000000..1e1a979569
--- /dev/null
+++ b/vendor/symfony/mime/Header/DateHeader.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+/**
+ * A Date MIME Header.
+ *
+ * @author Chris Corbyn
+ *
+ * @experimental in 4.3
+ */
+final class DateHeader extends AbstractHeader
+{
+ private $dateTime;
+
+ public function __construct(string $name, \DateTimeInterface $date)
+ {
+ parent::__construct($name);
+
+ $this->setDateTime($date);
+ }
+
+ /**
+ * @param \DateTimeInterface $body
+ */
+ public function setBody($body)
+ {
+ $this->setDateTime($body);
+ }
+
+ /**
+ * @return \DateTimeImmutable
+ */
+ public function getBody()
+ {
+ return $this->getDateTime();
+ }
+
+ public function getDateTime(): \DateTimeImmutable
+ {
+ return $this->dateTime;
+ }
+
+ /**
+ * Set the date-time of the Date in this Header.
+ *
+ * If a DateTime instance is provided, it is converted to DateTimeImmutable.
+ */
+ public function setDateTime(\DateTimeInterface $dateTime)
+ {
+ if ($dateTime instanceof \DateTime) {
+ $immutable = new \DateTimeImmutable('@'.$dateTime->getTimestamp());
+ $dateTime = $immutable->setTimezone($dateTime->getTimezone());
+ }
+ $this->dateTime = $dateTime;
+ }
+
+ public function getBodyAsString(): string
+ {
+ return $this->dateTime->format(\DateTime::RFC2822);
+ }
+}
diff --git a/vendor/symfony/mime/Header/HeaderInterface.php b/vendor/symfony/mime/Header/HeaderInterface.php
new file mode 100644
index 0000000000..b0638bca40
--- /dev/null
+++ b/vendor/symfony/mime/Header/HeaderInterface.php
@@ -0,0 +1,67 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+/**
+ * A MIME Header.
+ *
+ * @author Chris Corbyn
+ *
+ * @experimental in 4.3
+ */
+interface HeaderInterface
+{
+ /**
+ * Sets the body.
+ *
+ * The type depends on the Header concrete class.
+ *
+ * @param mixed $body
+ */
+ public function setBody($body);
+
+ /**
+ * Gets the body.
+ *
+ * The return type depends on the Header concrete class.
+ *
+ * @return mixed
+ */
+ public function getBody();
+
+ public function setCharset(string $charset);
+
+ public function getCharset(): ?string;
+
+ public function setLanguage(string $lang);
+
+ public function getLanguage(): ?string;
+
+ public function getName(): string;
+
+ public function setMaxLineLength(int $lineLength);
+
+ public function getMaxLineLength(): int;
+
+ /**
+ * Gets this Header rendered as a compliant string.
+ */
+ public function toString(): string;
+
+ /**
+ * Gets the header's body, prepared for folding into a final header value.
+ *
+ * This is not necessarily RFC 2822 compliant since folding white space is
+ * not added at this stage (see {@link toString()} for that).
+ */
+ public function getBodyAsString(): string;
+}
diff --git a/vendor/symfony/mime/Header/Headers.php b/vendor/symfony/mime/Header/Headers.php
new file mode 100644
index 0000000000..c0e45e0d0a
--- /dev/null
+++ b/vendor/symfony/mime/Header/Headers.php
@@ -0,0 +1,285 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+use Symfony\Component\Mime\Address;
+use Symfony\Component\Mime\Exception\LogicException;
+use Symfony\Component\Mime\NamedAddress;
+
+/**
+ * A collection of headers.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+final class Headers
+{
+ private static $uniqueHeaders = [
+ 'date', 'from', 'sender', 'reply-to', 'to', 'cc', 'bcc',
+ 'message-id', 'in-reply-to', 'references', 'subject',
+ ];
+
+ private $headers = [];
+ private $lineLength = 76;
+
+ public function __construct(HeaderInterface ...$headers)
+ {
+ foreach ($headers as $header) {
+ $this->add($header);
+ }
+ }
+
+ public function __clone()
+ {
+ foreach ($this->headers as $name => $collection) {
+ foreach ($collection as $i => $header) {
+ $this->headers[$name][$i] = clone $header;
+ }
+ }
+ }
+
+ public function setMaxLineLength(int $lineLength)
+ {
+ $this->lineLength = $lineLength;
+ foreach ($this->getAll() as $header) {
+ $header->setMaxLineLength($lineLength);
+ }
+ }
+
+ public function getMaxLineLength(): int
+ {
+ return $this->lineLength;
+ }
+
+ /**
+ * @param (NamedAddress|Address|string)[] $addresses
+ *
+ * @return $this
+ */
+ public function addMailboxListHeader(string $name, array $addresses)
+ {
+ return $this->add(new MailboxListHeader($name, Address::createArray($addresses)));
+ }
+
+ /**
+ * @param NamedAddress|Address|string $address
+ *
+ * @return $this
+ */
+ public function addMailboxHeader(string $name, $address)
+ {
+ return $this->add(new MailboxHeader($name, Address::create($address)));
+ }
+
+ /**
+ * @param string|array $ids
+ *
+ * @return $this
+ */
+ public function addIdHeader(string $name, $ids)
+ {
+ return $this->add(new IdentificationHeader($name, $ids));
+ }
+
+ /**
+ * @param Address|string $path
+ *
+ * @return $this
+ */
+ public function addPathHeader(string $name, $path)
+ {
+ return $this->add(new PathHeader($name, $path instanceof Address ? $path : new Address($path)));
+ }
+
+ /**
+ * @return $this
+ */
+ public function addDateHeader(string $name, \DateTimeInterface $dateTime)
+ {
+ return $this->add(new DateHeader($name, $dateTime));
+ }
+
+ /**
+ * @return $this
+ */
+ public function addTextHeader(string $name, string $value)
+ {
+ return $this->add(new UnstructuredHeader($name, $value));
+ }
+
+ /**
+ * @return $this
+ */
+ public function addParameterizedHeader(string $name, string $value, array $params = [])
+ {
+ return $this->add(new ParameterizedHeader($name, $value, $params));
+ }
+
+ public function has(string $name): bool
+ {
+ return isset($this->headers[strtolower($name)]);
+ }
+
+ /**
+ * @return $this
+ */
+ public function add(HeaderInterface $header)
+ {
+ static $map = [
+ 'date' => DateHeader::class,
+ 'from' => MailboxListHeader::class,
+ 'sender' => MailboxHeader::class,
+ 'reply-to' => MailboxListHeader::class,
+ 'to' => MailboxListHeader::class,
+ 'cc' => MailboxListHeader::class,
+ 'bcc' => MailboxListHeader::class,
+ 'message-id' => IdentificationHeader::class,
+ 'in-reply-to' => IdentificationHeader::class,
+ 'references' => IdentificationHeader::class,
+ 'return-path' => PathHeader::class,
+ ];
+
+ $header->setMaxLineLength($this->lineLength);
+ $name = strtolower($header->getName());
+
+ if (isset($map[$name]) && !$header instanceof $map[$name]) {
+ throw new LogicException(sprintf('The "%s" header must be an instance of "%s" (got "%s").', $header->getName(), $map[$name], \get_class($header)));
+ }
+
+ if (\in_array($name, self::$uniqueHeaders, true) && isset($this->headers[$name]) && \count($this->headers[$name]) > 0) {
+ throw new LogicException(sprintf('Impossible to set header "%s" as it\'s already defined and must be unique.', $header->getName()));
+ }
+
+ $this->headers[$name][] = $header;
+
+ return $this;
+ }
+
+ public function get(string $name): ?HeaderInterface
+ {
+ $name = strtolower($name);
+ if (!isset($this->headers[$name])) {
+ return null;
+ }
+
+ $values = array_values($this->headers[$name]);
+
+ return array_shift($values);
+ }
+
+ public function getAll(string $name = null): iterable
+ {
+ if (null === $name) {
+ foreach ($this->headers as $name => $collection) {
+ foreach ($collection as $header) {
+ yield $name => $header;
+ }
+ }
+ } elseif (isset($this->headers[strtolower($name)])) {
+ foreach ($this->headers[strtolower($name)] as $header) {
+ yield $header;
+ }
+ }
+ }
+
+ public function getNames(): array
+ {
+ return array_keys($this->headers);
+ }
+
+ public function remove(string $name): void
+ {
+ unset($this->headers[strtolower($name)]);
+ }
+
+ public static function isUniqueHeader(string $name): bool
+ {
+ return \in_array($name, self::$uniqueHeaders, true);
+ }
+
+ public function toString(): string
+ {
+ $string = '';
+ foreach ($this->toArray() as $str) {
+ $string .= $str."\r\n";
+ }
+
+ return $string;
+ }
+
+ public function toArray(): array
+ {
+ $arr = [];
+ foreach ($this->getAll() as $header) {
+ if ('' !== $header->getBodyAsString()) {
+ $arr[] = $header->toString();
+ }
+ }
+
+ return $arr;
+ }
+
+ /**
+ * @internal
+ */
+ public function getHeaderBody($name)
+ {
+ return $this->has($name) ? $this->get($name)->getBody() : null;
+ }
+
+ /**
+ * @internal
+ */
+ public function setHeaderBody(string $type, string $name, $body): void
+ {
+ if ($this->has($name)) {
+ $this->get($name)->setBody($body);
+ } else {
+ $this->{'add'.$type.'Header'}($name, $body);
+ }
+ }
+
+ /**
+ * @internal
+ */
+ public function getHeaderParameter(string $name, string $parameter): ?string
+ {
+ if (!$this->has($name)) {
+ return null;
+ }
+
+ $header = $this->get($name);
+ if (!$header instanceof ParameterizedHeader) {
+ throw new LogicException(sprintf('Unable to get parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class));
+ }
+
+ return $header->getParameter($parameter);
+ }
+
+ /**
+ * @internal
+ */
+ public function setHeaderParameter(string $name, string $parameter, $value): void
+ {
+ if (!$this->has($name)) {
+ throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not defined.', $parameter, $name));
+ }
+
+ $header = $this->get($name);
+ if (!$header instanceof ParameterizedHeader) {
+ throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class));
+ }
+
+ $header->setParameter($parameter, $value);
+ }
+}
diff --git a/vendor/symfony/mime/Header/IdentificationHeader.php b/vendor/symfony/mime/Header/IdentificationHeader.php
new file mode 100644
index 0000000000..0695b688da
--- /dev/null
+++ b/vendor/symfony/mime/Header/IdentificationHeader.php
@@ -0,0 +1,115 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+use Symfony\Component\Mime\Address;
+use Symfony\Component\Mime\Exception\RfcComplianceException;
+
+/**
+ * An ID MIME Header for something like Message-ID or Content-ID (one or more addresses).
+ *
+ * @author Chris Corbyn
+ *
+ * @experimental in 4.3
+ */
+final class IdentificationHeader extends AbstractHeader
+{
+ private $ids = [];
+ private $idsAsAddresses = [];
+
+ /**
+ * @param string|array $ids
+ */
+ public function __construct(string $name, $ids)
+ {
+ parent::__construct($name);
+
+ $this->setId($ids);
+ }
+
+ /**
+ * @param string|array $body a string ID or an array of IDs
+ *
+ * @throws RfcComplianceException
+ */
+ public function setBody($body)
+ {
+ $this->setId($body);
+ }
+
+ /**
+ * @return array
+ */
+ public function getBody()
+ {
+ return $this->getIds();
+ }
+
+ /**
+ * Set the ID used in the value of this header.
+ *
+ * @param string|array $id
+ *
+ * @throws RfcComplianceException
+ */
+ public function setId($id)
+ {
+ $this->setIds(\is_array($id) ? $id : [$id]);
+ }
+
+ /**
+ * Get the ID used in the value of this Header.
+ *
+ * If multiple IDs are set only the first is returned.
+ */
+ public function getId(): ?string
+ {
+ return $this->ids[0] ?? null;
+ }
+
+ /**
+ * Set a collection of IDs to use in the value of this Header.
+ *
+ * @param string[] $ids
+ *
+ * @throws RfcComplianceException
+ */
+ public function setIds(array $ids)
+ {
+ $this->ids = [];
+ $this->idsAsAddresses = [];
+ foreach ($ids as $id) {
+ $this->idsAsAddresses[] = new Address($id);
+ $this->ids[] = $id;
+ }
+ }
+
+ /**
+ * Get the list of IDs used in this Header.
+ *
+ * @return string[]
+ */
+ public function getIds(): array
+ {
+ return $this->ids;
+ }
+
+ public function getBodyAsString(): string
+ {
+ $addrs = [];
+ foreach ($this->idsAsAddresses as $address) {
+ $addrs[] = '<'.$address->toString().'>';
+ }
+
+ return implode(' ', $addrs);
+ }
+}
diff --git a/vendor/symfony/mime/Header/MailboxHeader.php b/vendor/symfony/mime/Header/MailboxHeader.php
new file mode 100644
index 0000000000..c4f48f3e48
--- /dev/null
+++ b/vendor/symfony/mime/Header/MailboxHeader.php
@@ -0,0 +1,93 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+use Symfony\Component\Mime\Address;
+use Symfony\Component\Mime\Exception\RfcComplianceException;
+use Symfony\Component\Mime\NamedAddress;
+
+/**
+ * A Mailbox MIME Header for something like Sender (one named address).
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @experimental in 4.3
+ */
+final class MailboxHeader extends AbstractHeader
+{
+ private $address;
+
+ public function __construct(string $name, Address $address)
+ {
+ parent::__construct($name);
+
+ $this->setAddress($address);
+ }
+
+ /**
+ * @param Address $body
+ *
+ * @throws RfcComplianceException
+ */
+ public function setBody($body)
+ {
+ $this->setAddress($body);
+ }
+
+ /**
+ * @throws RfcComplianceException
+ *
+ * @return Address
+ */
+ public function getBody()
+ {
+ return $this->getAddress();
+ }
+
+ /**
+ * @throws RfcComplianceException
+ */
+ public function setAddress(Address $address)
+ {
+ $this->address = $address;
+ }
+
+ /**
+ * @return Address
+ */
+ public function getAddress(): Address
+ {
+ return $this->address;
+ }
+
+ public function getBodyAsString(): string
+ {
+ $str = $this->address->getEncodedAddress();
+ if ($this->address instanceof NamedAddress && $name = $this->address->getName()) {
+ $str = $this->createPhrase($this, $name, $this->getCharset(), true).' <'.$str.'>';
+ }
+
+ return $str;
+ }
+
+ /**
+ * Redefine the encoding requirements for an address.
+ *
+ * All "specials" must be encoded as the full header value will not be quoted
+ *
+ * @see RFC 2822 3.2.1
+ */
+ protected function tokenNeedsEncoding(string $token): bool
+ {
+ return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token);
+ }
+}
diff --git a/vendor/symfony/mime/Header/MailboxListHeader.php b/vendor/symfony/mime/Header/MailboxListHeader.php
new file mode 100644
index 0000000000..51af2da87c
--- /dev/null
+++ b/vendor/symfony/mime/Header/MailboxListHeader.php
@@ -0,0 +1,139 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+use Symfony\Component\Mime\Address;
+use Symfony\Component\Mime\Exception\RfcComplianceException;
+use Symfony\Component\Mime\NamedAddress;
+
+/**
+ * A Mailbox list MIME Header for something like From, To, Cc, and Bcc (one or more named addresses).
+ *
+ * @author Chris Corbyn
+ *
+ * @experimental in 4.3
+ */
+final class MailboxListHeader extends AbstractHeader
+{
+ private $addresses = [];
+
+ /**
+ * @param (NamedAddress|Address)[] $addresses
+ */
+ public function __construct(string $name, array $addresses)
+ {
+ parent::__construct($name);
+
+ $this->setAddresses($addresses);
+ }
+
+ /**
+ * @param (NamedAddress|Address)[] $body
+ *
+ * @throws RfcComplianceException
+ */
+ public function setBody($body)
+ {
+ $this->setAddresses($body);
+ }
+
+ /**
+ * @throws RfcComplianceException
+ *
+ * @return (NamedAddress|Address)[]
+ */
+ public function getBody()
+ {
+ return $this->getAddresses();
+ }
+
+ /**
+ * Sets a list of addresses to be shown in this Header.
+ *
+ * @param (NamedAddress|Address)[] $addresses
+ *
+ * @throws RfcComplianceException
+ */
+ public function setAddresses(array $addresses)
+ {
+ $this->addresses = [];
+ $this->addAddresses($addresses);
+ }
+
+ /**
+ * Sets a list of addresses to be shown in this Header.
+ *
+ * @param (NamedAddress|Address)[] $addresses
+ *
+ * @throws RfcComplianceException
+ */
+ public function addAddresses(array $addresses)
+ {
+ foreach ($addresses as $address) {
+ $this->addAddress($address);
+ }
+ }
+
+ /**
+ * @throws RfcComplianceException
+ */
+ public function addAddress(Address $address)
+ {
+ $this->addresses[] = $address;
+ }
+
+ /**
+ * @return (NamedAddress|Address)[]
+ */
+ public function getAddresses(): array
+ {
+ return $this->addresses;
+ }
+
+ /**
+ * Gets the full mailbox list of this Header as an array of valid RFC 2822 strings.
+ *
+ * @throws RfcComplianceException
+ *
+ * @return string[]
+ */
+ public function getAddressStrings(): array
+ {
+ $strings = [];
+ foreach ($this->addresses as $address) {
+ $str = $address->getEncodedAddress();
+ if ($address instanceof NamedAddress && $name = $address->getName()) {
+ $str = $this->createPhrase($this, $name, $this->getCharset(), empty($strings)).' <'.$str.'>';
+ }
+ $strings[] = $str;
+ }
+
+ return $strings;
+ }
+
+ public function getBodyAsString(): string
+ {
+ return implode(', ', $this->getAddressStrings());
+ }
+
+ /**
+ * Redefine the encoding requirements for addresses.
+ *
+ * All "specials" must be encoded as the full header value will not be quoted
+ *
+ * @see RFC 2822 3.2.1
+ */
+ protected function tokenNeedsEncoding(string $token): bool
+ {
+ return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token);
+ }
+}
diff --git a/vendor/symfony/mime/Header/ParameterizedHeader.php b/vendor/symfony/mime/Header/ParameterizedHeader.php
new file mode 100644
index 0000000000..5813dcf79f
--- /dev/null
+++ b/vendor/symfony/mime/Header/ParameterizedHeader.php
@@ -0,0 +1,176 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+use Symfony\Component\Mime\Encoder\Rfc2231Encoder;
+
+/**
+ * @author Chris Corbyn
+ *
+ * @experimental in 4.3
+ */
+final class ParameterizedHeader extends UnstructuredHeader
+{
+ /**
+ * RFC 2231's definition of a token.
+ *
+ * @var string
+ */
+ const TOKEN_REGEX = '(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+)';
+
+ private $encoder;
+ private $parameters = [];
+
+ public function __construct(string $name, string $value, array $parameters = [])
+ {
+ parent::__construct($name, $value);
+
+ foreach ($parameters as $k => $v) {
+ $this->setParameter($k, $v);
+ }
+
+ if ('content-disposition' === strtolower($name)) {
+ $this->encoder = new Rfc2231Encoder();
+ }
+ }
+
+ public function setParameter(string $parameter, ?string $value)
+ {
+ $this->setParameters(array_merge($this->getParameters(), [$parameter => $value]));
+ }
+
+ public function getParameter(string $parameter): string
+ {
+ return $this->getParameters()[$parameter] ?? '';
+ }
+
+ /**
+ * @param string[] $parameters
+ */
+ public function setParameters(array $parameters)
+ {
+ $this->parameters = $parameters;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getParameters(): array
+ {
+ return $this->parameters;
+ }
+
+ public function getBodyAsString(): string
+ {
+ $body = parent::getBodyAsString();
+ foreach ($this->parameters as $name => $value) {
+ if (null !== $value) {
+ $body .= '; '.$this->createParameter($name, $value);
+ }
+ }
+
+ return $body;
+ }
+
+ /**
+ * Generate a list of all tokens in the final header.
+ *
+ * This doesn't need to be overridden in theory, but it is for implementation
+ * reasons to prevent potential breakage of attributes.
+ */
+ protected function toTokens(string $string = null): array
+ {
+ $tokens = parent::toTokens(parent::getBodyAsString());
+
+ // Try creating any parameters
+ foreach ($this->parameters as $name => $value) {
+ if (null !== $value) {
+ // Add the semi-colon separator
+ $tokens[\count($tokens) - 1] .= ';';
+ $tokens = array_merge($tokens, $this->generateTokenLines(' '.$this->createParameter($name, $value)));
+ }
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Render a RFC 2047 compliant header parameter from the $name and $value.
+ */
+ private function createParameter(string $name, string $value): string
+ {
+ $origValue = $value;
+
+ $encoded = false;
+ // Allow room for parameter name, indices, "=" and DQUOTEs
+ $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1;
+ $firstLineOffset = 0;
+
+ // If it's not already a valid parameter value...
+ if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) {
+ // TODO: text, or something else??
+ // ... and it's not ascii
+ if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) {
+ $encoded = true;
+ // Allow space for the indices, charset and language
+ $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1;
+ $firstLineOffset = \strlen($this->getCharset()."'".$this->getLanguage()."'");
+ }
+ }
+
+ // Encode if we need to
+ if ($encoded || \strlen($value) > $maxValueLength) {
+ if (null !== $this->encoder) {
+ $value = $this->encoder->encodeString($origValue, $this->getCharset(), $firstLineOffset, $maxValueLength);
+ } else {
+ // We have to go against RFC 2183/2231 in some areas for interoperability
+ $value = $this->getTokenAsEncodedWord($origValue);
+ $encoded = false;
+ }
+ }
+
+ $valueLines = $this->encoder ? explode("\r\n", $value) : [$value];
+
+ // Need to add indices
+ if (\count($valueLines) > 1) {
+ $paramLines = [];
+ foreach ($valueLines as $i => $line) {
+ $paramLines[] = $name.'*'.$i.$this->getEndOfParameterValue($line, true, 0 === $i);
+ }
+
+ return implode(";\r\n ", $paramLines);
+ } else {
+ return $name.$this->getEndOfParameterValue($valueLines[0], $encoded, true);
+ }
+ }
+
+ /**
+ * Returns the parameter value from the "=" and beyond.
+ *
+ * @param string $value to append
+ */
+ private function getEndOfParameterValue(string $value, bool $encoded = false, bool $firstLine = false): string
+ {
+ if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) {
+ $value = '"'.$value.'"';
+ }
+ $prepend = '=';
+ if ($encoded) {
+ $prepend = '*=';
+ if ($firstLine) {
+ $prepend = '*='.$this->getCharset()."'".$this->getLanguage()."'";
+ }
+ }
+
+ return $prepend.$value;
+ }
+}
diff --git a/vendor/symfony/mime/Header/PathHeader.php b/vendor/symfony/mime/Header/PathHeader.php
new file mode 100644
index 0000000000..6d16500a18
--- /dev/null
+++ b/vendor/symfony/mime/Header/PathHeader.php
@@ -0,0 +1,67 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+use Symfony\Component\Mime\Address;
+use Symfony\Component\Mime\Exception\RfcComplianceException;
+
+/**
+ * A Path Header, such a Return-Path (one address).
+ *
+ * @author Chris Corbyn
+ *
+ * @experimental in 4.3
+ */
+final class PathHeader extends AbstractHeader
+{
+ private $address;
+
+ public function __construct(string $name, Address $address)
+ {
+ parent::__construct($name);
+
+ $this->setAddress($address);
+ }
+
+ /**
+ * @param Address $body
+ *
+ * @throws RfcComplianceException
+ */
+ public function setBody($body)
+ {
+ $this->setAddress($body);
+ }
+
+ /**
+ * @return Address
+ */
+ public function getBody()
+ {
+ return $this->getAddress();
+ }
+
+ public function setAddress(Address $address)
+ {
+ $this->address = $address;
+ }
+
+ public function getAddress(): Address
+ {
+ return $this->address;
+ }
+
+ public function getBodyAsString(): string
+ {
+ return '<'.$this->address->toString().'>';
+ }
+}
diff --git a/vendor/symfony/mime/Header/UnstructuredHeader.php b/vendor/symfony/mime/Header/UnstructuredHeader.php
new file mode 100644
index 0000000000..afb9615257
--- /dev/null
+++ b/vendor/symfony/mime/Header/UnstructuredHeader.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mime\Header;
+
+/**
+ * A Simple MIME Header.
+ *
+ * @author Chris Corbyn
+ *
+ * @experimental in 4.3
+ */
+class UnstructuredHeader extends AbstractHeader
+{
+ private $value;
+
+ public function __construct(string $name, string $value)
+ {
+ parent::__construct($name);
+
+ $this->setValue($value);
+ }
+
+ /**
+ * @param string $body
+ */
+ public function setBody($body)
+ {
+ $this->setValue($body);
+ }
+
+ /**
+ * @return string
+ */
+ public function getBody()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Get the (unencoded) value of this header.
+ */
+ public function getValue(): string
+ {
+ return $this->value;
+ }
+
+ /**
+ * Set the (unencoded) value of this header.
+ */
+ public function setValue(string $value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Get the value of this header prepared for rendering.
+ */
+ public function getBodyAsString(): string
+ {
+ return $this->encodeWords($this, $this->value);
+ }
+}