Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

All original zend-mail changes #6

Open
wants to merge 20 commits into
base: laminas-update
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3d74c00
Small bugfixes from IMAP message parsing. These exist as PRs upstream…
mikegioia Dec 21, 2015
976ef00
Changed package name to hopefully resolve composer update.
mikegioia Dec 21, 2015
aff5b56
Updated mime dependency to use mikegioia's version
mikegioia Dec 21, 2015
9b3bf4d
Better handling for failed parsing of the Content-Type header. Remove…
mikegioia Dec 22, 2015
ebc66f3
Removed strict option from address validator.
mikegioia Dec 22, 2015
fe5da3b
Removed thrown exception during validation on email address. This isn…
mikegioia Dec 22, 2015
6388627
Changed project owner
mikegioia Dec 23, 2015
041d815
Removed stability lines from composer file
mikegioia Dec 23, 2015
b7e3dca
Added support for UID searching in the IMAP search method of the prot…
mikegioia Dec 24, 2015
c025e1a
Changed default behaviour in splitHeaderLine to not throw exceptions …
mikegioia Dec 25, 2015
d344510
Added param to throw exception when setting an invalid content type.
mikegioia Dec 26, 2015
3017baa
Formatting
mikegioia Dec 26, 2015
cae8191
Added a case for setting the headers to an empty Headers object if th…
mikegioia Dec 27, 2015
93f3c3e
Converted header and message fetching to use a peek by default.
mikegioia Dec 31, 2015
484c2ee
Fixed a bug with the headerwrap failing canBeEncoded.
mikegioia Feb 21, 2016
c47ec31
Merging upstream
mikegioia Feb 17, 2017
ed62fa4
Re-removed composer lines for stability
mikegioia Feb 17, 2017
96a8a4a
No longer throws exception for 'MimeVersion' header
mikegioia Feb 19, 2017
cf97276
Fixes some header name problems
mikegioia Feb 19, 2017
3df3edd
Removing duplicate < and > symbols from Message ID
mikegioia Feb 25, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "zendframework/zend-mail",
"name": "particlebits/zend-mail",
"description": "provides generalized functionality to compose and send both text and MIME-compliant multipart e-mail messages",
"license": "BSD-3-Clause",
"keywords": [
Expand All @@ -12,10 +12,16 @@
"Zend\\Mail\\": "src/"
}
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/particlebits/zend-mime"
}
],
"require": {
"php": "^5.5 || ^7.0",
"zendframework/zend-loader": "^2.5",
"zendframework/zend-mime": "^2.5",
"particlebits/zend-mime": "~2.5",
"zendframework/zend-stdlib": "^2.7 || ^3.0",
"zendframework/zend-validator": "^2.6"
},
Expand All @@ -30,8 +36,6 @@
"zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3 when using SMTP to deliver messages",
"zendframework/zend-crypt": "Crammd5 support in SMTP Auth"
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"branch-alias": {
"dev-master": "2.7-dev",
Expand Down
8 changes: 7 additions & 1 deletion src/Address.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ class Address implements Address\AddressInterface
*/
public function __construct($email, $name = null)
{
$emailAddressValidator = new EmailAddressValidator(Hostname::ALLOW_DNS | Hostname::ALLOW_LOCAL);
$emailAddressValidator = new EmailAddressValidator([
'allow' => Hostname::ALLOW_DNS | Hostname::ALLOW_LOCAL,
'strict' => false
]);

if (! is_string($email) || empty($email)) {
throw new Exception\InvalidArgumentException('Email must be a valid email address');
}
Expand All @@ -36,10 +40,12 @@ public function __construct($email, $name = null)
throw new Exception\InvalidArgumentException('CRLF injection detected');
}

/* Ignoring this check
if (! $emailAddressValidator->isValid($email)) {
$invalidMessages = $emailAddressValidator->getMessages();
throw new Exception\InvalidArgumentException(array_shift($invalidMessages));
}
*/

if (null !== $name) {
if (! is_string($name)) {
Expand Down
8 changes: 8 additions & 0 deletions src/Header/AbstractAddressList.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ abstract class AbstractAddressList implements HeaderInterface
public static function fromString($headerLine)
{
list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
// clean up acceptable values
$fieldName = static::cleanFieldName($fieldName);
if (strtolower($fieldName) !== static::$type) {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for "%s" string',
Expand Down Expand Up @@ -206,4 +208,10 @@ protected static function stripComments($value)
$value
);
}

// Implemented in sub-classes
protected static function cleanFieldName($fieldName)
{
return $fieldName;
}
}
2 changes: 2 additions & 0 deletions src/Header/ContentTransferEncoding.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ public function setTransferEncoding($transferEncoding)
{
// Per RFC 1521, the value of the header is not case sensitive
$transferEncoding = strtolower($transferEncoding);
// Remove trailing semicolon
$transferEncoding = rtrim($transferEncoding, ';');

if (! in_array($transferEncoding, static::$allowedTransferEncodings)) {
throw new Exception\InvalidArgumentException(sprintf(
Expand Down
11 changes: 8 additions & 3 deletions src/Header/ContentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ public static function fromString($headerLine)
$values = array_filter($values);

foreach ($values as $keyValuePair) {
list($key, $value) = explode('=', $keyValuePair, 2);
$parts = explode('=', $keyValuePair, 2);
$key = $parts[0];
$value = (count($parts) > 1) ? $parts[1] : "";
$value = trim($value, "'\" \t\n\r\0\x0B");
$header->addParameter($key, $value);
}
Expand Down Expand Up @@ -106,12 +108,15 @@ public function toString()
* Set the content type
*
* @param string $type
* @param bool $throwExceptionOnInvalid
* @throws Exception\InvalidArgumentException
* @return ContentType
*/
public function setType($type)
public function setType($type, $throwExceptionOnInvalid = false)
{
if (! preg_match('/^[a-z-]+\/[a-z0-9.+-]+$/i', $type)) {
if (! preg_match('/^[a-z-]+\/[a-z0-9.+-]+$/i', $type)
&& $throwExceptionOnInvalid === true)
{
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a value in the format "type/subtype"; received "%s"',
__METHOD__,
Expand Down
12 changes: 9 additions & 3 deletions src/Header/GenericHeader.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,25 @@ public static function fromString($headerLine)
* @return string[] `name` in the first index and `value` in the second.
* @throws Exception\InvalidArgumentException If header does not match with the format ``name:value``
*/
public static function splitHeaderLine($headerLine)
public static function splitHeaderLine($headerLine, $throwExceptionOnInvalid = false)
{
$parts = explode(':', $headerLine, 2);
if (count($parts) !== 2) {
throw new Exception\InvalidArgumentException('Header must match with the format "name:value"');
}

if (! HeaderName::isValid($parts[0])) {
throw new Exception\InvalidArgumentException('Invalid header name detected');
if ( $throwExceptionOnInvalid === true) {
throw new Exception\InvalidArgumentException('Invalid header name detected');
}
$parts[0] = HeaderName::filter($parts[0]);
}

if (! HeaderValue::isValid($parts[1])) {
throw new Exception\InvalidArgumentException('Invalid header value detected');
if ($throwExceptionOnInvalid === true) {
throw new Exception\InvalidArgumentException('Invalid header value detected');
}
$parts[1] = HeaderValue::filter($parts[1]);
}

$parts[0] = $parts[0];
Expand Down
7 changes: 5 additions & 2 deletions src/Header/HeaderWrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,16 @@ public static function canBeEncoded($value)
$lineLength = strlen($value) * 4 + strlen($charset) + 16;

$preferences = [
'scheme' => 'Q',
'scheme' => 'B',
'input-charset' => $charset,
'output-charset' => $charset,
'line-length' => $lineLength,
];

$encoded = iconv_mime_encode('x-test', $value, $preferences);
$encodedB = @iconv_mime_encode('x-test', $value, $preferences);
$preferences['scheme'] = 'Q';
$encodedQ = @iconv_mime_encode('x-test', $value, $preferences);
$encoded = $encodedB || $encodedQ;

return (false !== $encoded);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Header/MessageId.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function setId($id = null)
throw new Exception\InvalidArgumentException('Invalid ID detected');
}

$this->messageId = sprintf('<%s>', $id);
$this->messageId = sprintf('<%s>', trim($id, "<>"));
return $this;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Header/MimeVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static function fromString($headerLine)
$value = HeaderWrap::mimeDecodeValue($value);

// check to ensure proper header type for this factory
if (strtolower($name) !== 'mime-version') {
if (strtolower($name) !== 'mime-version' && strtolower($name) !== 'mimeversion') {
throw new Exception\InvalidArgumentException('Invalid header line for MIME-Version string');
}

Expand Down
15 changes: 15 additions & 0 deletions src/Header/ReplyTo.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,19 @@ class ReplyTo extends AbstractAddressList
{
protected $fieldName = 'Reply-To';
protected static $type = 'reply-to';

protected static function cleanFieldName($fieldName)
{
$allowed = [
'replyto', 'reply_to'
];

foreach ($allowed as $name) {
if (strtolower($fieldName) === $name) {
return static::$type;
}
}

return $fieldName;
}
}
14 changes: 10 additions & 4 deletions src/Protocol/Imap.php
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,9 @@ public function fetch($items, $from, $to = null, $uid = false)
$tag = null; // define $tag variable before first use
$this->sendRequest(($uid ? 'UID ' : '') . 'FETCH', [$set, $itemList], $tag);

// remove any peek lines since the response doesn't return this
$items[0] = str_replace('.PEEK', '', $items[0]);

$result = [];
$tokens = null; // define $tokens variable before first use
while (! $this->readLine($tokens, $tag)) {
Expand Down Expand Up @@ -808,13 +811,16 @@ public function noop()
*
* This method is currently marked as internal as the API might change and is not
* safe if you don't take precautions.
*
* If $uid is true then this will return UIDs instead of message IDs.
* @param array $params
* @return array message ids
* @param bool $uid
* @return array message ids|unique ids
*/
public function search(array $params)
public function search(array $params, $uid = true)
{
$response = $this->requestAndResponse('SEARCH', $params);
$command = ($uid) ? 'UID SEARCH' : 'SEARCH';
$response = $this->requestAndResponse($command, $params);

if (! $response) {
return $response;
}
Expand Down
19 changes: 14 additions & 5 deletions src/Storage/Imap.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,19 @@ public function getSize($id = 0)
* Fetch a message
*
* @param int $id number of message
* @param bool $peek true leaves the message unread
* @return Message
* @throws Protocol\Exception\RuntimeException
*/
public function getMessage($id)
public function getMessage($id, $peek = true)
{
$data = $this->protocol->fetch(['FLAGS', 'RFC822.HEADER'], $id);
$header = $data['RFC822.HEADER'];
//$data = $this->protocol->fetch(['FLAGS', 'RFC822.HEADER'], $id);
$data = ($peek)
? $this->protocol->fetch(['FLAGS', 'BODY.PEEK[HEADER]'], $id)
: $this->protocol->fetch(['FLAGS', 'RFC822.HEADER'], $id);
$header = ($peek)
? $data['BODY[HEADER]']
: $data['RFC822.HEADER'];

$flags = [];
foreach ($data['FLAGS'] as $flag) {
Expand Down Expand Up @@ -155,18 +161,21 @@ public function getRawHeader($id, $part = null, $topLines = 0)
*
* @param int $id number of message
* @param null|array|string $part path to part or null for message content
* @param bool $peek true leaves the message unread
* @return string raw content
* @throws Protocol\Exception\RuntimeException
* @throws Exception\RuntimeException
*/
public function getRawContent($id, $part = null)
public function getRawContent($id, $part = null, $peek = true)
{
if ($part !== null) {
// TODO: implement
throw new Exception\RuntimeException('not implemented');
}

return $this->protocol->fetch('RFC822.TEXT', $id);
return ($peek)
? $this->protocol->fetch('BODY.PEEK[TEXT]', $id)
: $this->protocol->fetch('RFC822.TEXT', $id);
}

/**
Expand Down
3 changes: 3 additions & 0 deletions src/Storage/Part.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ public function __construct(array $params)
} else {
$this->headers = Headers::fromString($params['headers']);
}
if (!$this->headers) {
$this->headers = new Headers();
}
}

if (isset($params['content'])) {
Expand Down