Skip to content

Commit 18cc837

Browse files
committed
Fix garbled non-MIME-encoded UTF-8 headers
1 parent 40437c7 commit 18cc837

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

program/lib/Roundcube/rcube_mime.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ public static function decode_mime_string($input, $fallback = null)
162162
{
163163
$default_charset = $fallback ?: self::get_charset();
164164

165+
// RFC 6532: detect raw UTF-8 in headers to avoid wrong charset conversion
166+
if ($fallback !== false && mb_check_encoding($input, 'UTF-8') && preg_match('/[\x80-\xFF]/', $input)) {
167+
$default_charset = RCUBE_CHARSET;
168+
}
169+
165170
// rfc: all line breaks or other characters not found
166171
// in the Base64 Alphabet must be ignored by decoding software
167172
// delete all blanks between MIME-lines, differently we can

tests/Framework/MimeTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,23 @@ public function test_header_decode_qp()
216216
}
217217
}
218218

219+
/**
220+
* Test decoding of raw UTF-8 headers (RFC 6532)
221+
* Uses rcube_mime::decode_mime_string()
222+
*/
223+
public function test_header_decode_raw_utf8()
224+
{
225+
// Raw UTF-8 Korean with wrong fallback charset - should be preserved
226+
$korean = "\xEC\x95\x88\xEB\x85\x95\xED\x95\x98\xEC\x84\xB8\xEC\x9A\x94"; // 안녕하세요
227+
$res = \rcube_mime::decode_mime_string($korean, 'ISO-8859-1');
228+
$this->assertSame($korean, $res, 'Raw UTF-8 header with Latin-1 fallback');
229+
230+
// Latin-1 high bytes (not valid UTF-8) - should still be converted
231+
$latin1 = "caf\xE9"; // café in ISO-8859-1
232+
$res = \rcube_mime::decode_mime_string($latin1, 'ISO-8859-1');
233+
$this->assertSame('café', $res, 'Latin-1 header should be converted');
234+
}
235+
219236
/**
220237
* Test headers parsing
221238
*/

0 commit comments

Comments
 (0)