diff --git a/src/org/apache/james/mime4j/decoder/DecoderUtil.java b/src/org/apache/james/mime4j/decoder/DecoderUtil.java index f7b9fa8f8..7876ff700 100644 --- a/src/org/apache/james/mime4j/decoder/DecoderUtil.java +++ b/src/org/apache/james/mime4j/decoder/DecoderUtil.java @@ -166,7 +166,20 @@ public class DecoderUtil { while (true) { int begin = body.indexOf("=?", previousEnd); - int end = begin == -1 ? -1 : body.indexOf("?=", begin + 2); + + // ANDROID: The mime4j original version has an error here. It gets confused if + // the encoded string begins with an '=' (just after "?Q?"). This patch seeks forward + // to find the two '?' in the "header", before looking for the final "?=". + int endScan = begin + 2; + if (begin != -1) { + int qm1 = body.indexOf('?', endScan + 2); + int qm2 = body.indexOf('?', qm1 + 1); + if (qm2 != -1) { + endScan = qm2 + 1; + } + } + + int end = begin == -1 ? -1 : body.indexOf("?=", endScan); if (end == -1) { if (previousEnd == 0) return body; diff --git a/tests/src/com/android/email/mail/internet/MimeUtilityTest.java b/tests/src/com/android/email/mail/internet/MimeUtilityTest.java index b39e4cf0d..814774b3c 100644 --- a/tests/src/com/android/email/mail/internet/MimeUtilityTest.java +++ b/tests/src/com/android/email/mail/internet/MimeUtilityTest.java @@ -48,6 +48,31 @@ public class MimeUtilityTest extends TestCase { /** a typical multi-param header */ private final String HEADER_MULTI_PARAMETER = "header; Param1Name=Param1Value; Param2Name=Param2Value"; + + /** + * a string generated by google calendar that contains two interesting gotchas: + * 1. Uses windows-1252 encoding, and en-dash recoded appropriately (\u2013 / =96) + * 2. Because the first encoded char requires '=XX' encoding, we create an "internal" + * "?=" that the decoder must correctly skip over. + **/ + private final String CALENDAR_SUBJECT_UNICODE = + "=?windows-1252?Q?=5BReminder=5D_test_=40_Fri_Mar_20_10=3A30am_=96_11am_=28andro?=" + + "\r\n\t" + + "=?windows-1252?Q?id=2Etr=40gmail=2Ecom=29?="; + private final String CALENDAR_SUBJECT_PLAIN = + "[Reminder] test @ Fri Mar 20 10:30am \u2013 11am (android.tr@gmail.com)"; + + /** + * Some basic degenerate strings designed to exercise error handling in the decoder + */ + private final String CALENDAR_DEGENERATE_UNICODE_1 = + "=?windows-1252?Q=5B?="; + private final String CALENDAR_DEGENERATE_UNICODE_2 = + "=?windows-1252Q?=5B?="; + private final String CALENDAR_DEGENERATE_UNICODE_3 = + "=?windows-1252?="; + private final String CALENDAR_DEGENERATE_UNICODE_4 = + "=?windows-1252"; /** * Test that decode/unfold is efficient when it can be @@ -82,7 +107,26 @@ public class MimeUtilityTest extends TestCase { assertEquals(SHORT_UNICODE, result1); } - // TODO: tests for unfoldAndDecode(String s) + /** + * test decoding complex string from google calendar that has two gotchas for the decoder. + * also tests a couple of degenerate cases that should "fail" decoding and pass through. + */ + public void testComplexDecode() { + String result1 = MimeUtility.unfoldAndDecode(CALENDAR_SUBJECT_UNICODE); + assertEquals(CALENDAR_SUBJECT_PLAIN, result1); + + // These degenerate cases should "fail" and return the same string + String degenerate1 = MimeUtility.unfoldAndDecode(CALENDAR_DEGENERATE_UNICODE_1); + assertEquals("degenerate case 1", CALENDAR_DEGENERATE_UNICODE_1, degenerate1); + String degenerate2 = MimeUtility.unfoldAndDecode(CALENDAR_DEGENERATE_UNICODE_2); + assertEquals("degenerate case 2", CALENDAR_DEGENERATE_UNICODE_2, degenerate2); + String degenerate3 = MimeUtility.unfoldAndDecode(CALENDAR_DEGENERATE_UNICODE_3); + assertEquals("degenerate case 3", CALENDAR_DEGENERATE_UNICODE_3, degenerate3); + String degenerate4 = MimeUtility.unfoldAndDecode(CALENDAR_DEGENERATE_UNICODE_4); + assertEquals("degenerate case 4", CALENDAR_DEGENERATE_UNICODE_4, degenerate4); + } + + // TODO: more tests for unfoldAndDecode(String s) /** * Test that fold/encode is efficient when it can be