diff --git a/src/Header/Part/QuotedLiteralPart.php b/src/Header/Part/QuotedLiteralPart.php index 2b1516fc..ad3a5de7 100644 --- a/src/Header/Part/QuotedLiteralPart.php +++ b/src/Header/Part/QuotedLiteralPart.php @@ -9,14 +9,38 @@ /** * A quoted literal header string part. The value of the part is stripped of CR - * and LF characters, but otherwise not transformed or changed in any way. + * 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 { - return $parts; + $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; } } diff --git a/tests/MailMimeParser/Header/Consumer/ParameterValueConsumerServiceTest.php b/tests/MailMimeParser/Header/Consumer/ParameterValueConsumerServiceTest.php index 237d6869..adc556a7 100644 --- a/tests/MailMimeParser/Header/Consumer/ParameterValueConsumerServiceTest.php +++ b/tests/MailMimeParser/Header/Consumer/ParameterValueConsumerServiceTest.php @@ -98,4 +98,16 @@ public function testWithQuotedHeaderEncodedValue() : void $ret = $this->consumer->__invoke('"=?US-ASCII?Q?value?="'); $this->assertEquals('value', $ret[0]->getValue()); } + + public function testWithQuotedHeaderMultipleEncodedValues() : void + { + $ret = $this->consumer->__invoke('"=?US-ASCII?Q?Kilgore?= =?US-ASCII?Q?Trout?="'); + $this->assertEquals('KilgoreTrout', $ret[0]->getValue()); + } + + public function testWithQuotedHeaderMultipleEncodedValuesAndLinesBetween() : void + { + $ret = $this->consumer->__invoke("\"=?US-ASCII?Q?Kilg?= \r\n =?US-ASCII?Q?or?= =?US-ASCII?Q?e_Trout?=\""); + $this->assertEquals('Kilgore Trout', $ret[0]->getValue()); + } } diff --git a/tests/MailMimeParser/Header/Consumer/QuotedStringMimeLiteralPartConsumerServiceTest.php b/tests/MailMimeParser/Header/Consumer/QuotedStringMimeLiteralPartConsumerServiceTest.php index 13e1ac42..70c96181 100644 --- a/tests/MailMimeParser/Header/Consumer/QuotedStringMimeLiteralPartConsumerServiceTest.php +++ b/tests/MailMimeParser/Header/Consumer/QuotedStringMimeLiteralPartConsumerServiceTest.php @@ -63,4 +63,20 @@ public function testConsumeMimeEncodedValue() : void $this->assertInstanceOf(QuotedLiteralPart::class, $ret[0]); $this->assertEquals('Kilgore Trout', $ret[0]->getValue()); } + + public function testWithQuotedHeaderMultipleEncodedValues() : void + { + $ret = $this->consumer->__invoke('=?US-ASCII?Q?Kilgore?= =?US-ASCII?Q?Trout?='); + $this->assertNotEmpty($ret); + $this->assertCount(1, $ret); + $this->assertEquals('KilgoreTrout', $ret[0]->getValue()); + } + + public function testWithQuotedHeaderMultipleEncodedValuesAndLinesBetween() : void + { + $ret = $this->consumer->__invoke("=?US-ASCII?Q?Kilg?= \r\n =?US-ASCII?Q?or?= =?US-ASCII?Q?e_Trout?="); + $this->assertNotEmpty($ret); + $this->assertCount(1, $ret); + $this->assertEquals('Kilgore Trout', $ret[0]->getValue()); + } }