mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-10-24 22:25:09 +03:00
MailSo: keep the folding space before an encoded word that follows a plain word
HeaderCollection::Parse() trimmed the folding whitespace in front of every continuation line starting with an encoded word. RFC 2047 6.2 ignores only whitespace BETWEEN two adjacent encoded words; after a plain word, RFC 5322 unfolding keeps it. Symfony Mailer folds subjects exactly there, so "de vos\r\n =?utf-8?Q?=C3=A9quipements?=" was displayed "voséquipements". The message list (IMAP ENVELOPE) was fine; the opened message was not. Test: php test/header-unfold.php (fails before the fix).
This commit is contained in:
parent
61ebcb6ed4
commit
37fcdbe534
2 changed files with 56 additions and 6 deletions
|
|
@ -136,12 +136,12 @@ class HeaderCollection extends \MailSo\Base\Collection
|
||||||
$sHeadersValue = \rtrim($sHeadersValue);
|
$sHeadersValue = \rtrim($sHeadersValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2)) {
|
// RFC 2047 6.2: only whitespace between two encoded words is
|
||||||
$sHeadersValue = \ltrim($sHeadersValue);
|
// dropped; after a plain word the folding space is a real space.
|
||||||
}
|
if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2) && '?=' === \substr($sValue, -2)) {
|
||||||
|
$sValue .= \ltrim($sHeadersValue);
|
||||||
if ('=?' === \substr($sHeadersValue, 0, 2)) {
|
} else if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2)) {
|
||||||
$sValue .= $sHeadersValue;
|
$sValue .= ' '.\ltrim($sHeadersValue);
|
||||||
} else {
|
} else {
|
||||||
$sValue .= "\n".$sHeadersValue;
|
$sValue .= "\n".$sHeadersValue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
test/header-unfold.php
Normal file
50
test/header-unfold.php
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Run with: php test/header-unfold.php
|
||||||
|
// RFC 5322 unfolding keeps the folding whitespace; RFC 2047 drops only the
|
||||||
|
// whitespace BETWEEN two encoded words. A plain word followed by a folded
|
||||||
|
// encoded word lost its space: "de vos\r\n =?utf-8?Q?=C3=A9quipements?="
|
||||||
|
// was shown as "voséquipements" (Symfony Mailer folds subjects this way).
|
||||||
|
define('APP_VERSION', 'test');
|
||||||
|
spl_autoload_register(static function (string $class): void {
|
||||||
|
if (str_starts_with($class, 'SnappyMail\\')) {
|
||||||
|
$file = dirname(__DIR__).'/snappymail/v/0.0.0/app/libraries/snappymail/'.strtolower(str_replace('\\', '/', substr($class, 11))).'.php';
|
||||||
|
} else {
|
||||||
|
$file = dirname(__DIR__).'/snappymail/v/0.0.0/app/libraries/'.str_replace('\\', '/', $class).'.php';
|
||||||
|
}
|
||||||
|
if (is_file($file)) {
|
||||||
|
require_once $file;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function check(bool $condition, string $message): void
|
||||||
|
{
|
||||||
|
if (!$condition) {
|
||||||
|
throw new RuntimeException($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function subject(string $raw): string
|
||||||
|
{
|
||||||
|
$headers = new \MailSo\Mime\HeaderCollection("Subject: {$raw}\r\nX-Next: 1\r\n");
|
||||||
|
return (string) $headers->ValueByName('Subject');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cases = [
|
||||||
|
// plain word, then a folded encoded word: the space stays
|
||||||
|
"Traiter les =?utf-8?Q?vuln=C3=A9rabilit=C3=A9s?= de vos\r\n =?utf-8?Q?=C3=A9quipements?= : plan de =?utf-8?Q?rem=C3=A9diation?= et\r\n checklist =?utf-8?Q?sign=C3=A9e?="
|
||||||
|
=> 'Traiter les vulnérabilités de vos équipements : plan de remédiation et checklist signée',
|
||||||
|
// two encoded words split across lines: no space between them (RFC 2047 §6.2)
|
||||||
|
"=?utf-8?Q?r=C3=A9pon?=\r\n =?utf-8?Q?se?=" => 'réponse',
|
||||||
|
"=?utf-8?B?w6l0w6k=?=\r\n\t=?utf-8?B?IGZpbg==?=" => 'été fin',
|
||||||
|
// encoded word, then a folded plain word: the space stays
|
||||||
|
"=?utf-8?Q?r=C3=A9union?=\r\n demain" => 'réunion demain',
|
||||||
|
// no encoding at all
|
||||||
|
"Hello\r\n world" => 'Hello world',
|
||||||
|
];
|
||||||
|
foreach ($cases as $raw => $want) {
|
||||||
|
$got = preg_replace('/\s+/', ' ', subject($raw));
|
||||||
|
check($got === $want, "got [{$got}], want [{$want}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "header-unfold: ".count($cases)." checks OK\n";
|
||||||
Loading…
Add table
Add a link
Reference in a new issue