From a780e12db2dba2f4b4fe3ea878171bc34f26e962 Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Thu, 22 Apr 2010 18:03:00 -0700 Subject: [PATCH] DO NOT MERGE: Relax MIME date parser. Make the date parser accept invalid dates like "Thu, 10 Dec 09 15:08:08 GMT-0700" which was observed in an email from eBay. Per RFC, timezone must be either obs-zone (e.g. "GMT") or +/- with 4 digits. The GMT+/-digits format is not permitted. Bug 2367124 Backport of I59968274160aeadea70223208b463ee692660056 Change-Id: I3c80eee28d1dcf4c0c211f773a50de0f0839e4ad --- src/com/android/email/Utility.java | 23 +++++++++++++- .../james/mime4j/field/DateTimeField.java | 5 ++- .../com/android/email/UtilityUnitTests.java | 18 +++++++++++ .../email/mail/internet/MimeMessageTest.java | 31 +++++++++++++++++-- 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/com/android/email/Utility.java b/src/com/android/email/Utility.java index 343ff8aa3..a24b9a2db 100644 --- a/src/com/android/email/Utility.java +++ b/src/com/android/email/Utility.java @@ -35,6 +35,7 @@ import android.os.AsyncTask; import android.security.MessageDigest; import android.telephony.TelephonyManager; import android.text.Editable; +import android.text.TextUtils; import android.util.Base64; import android.util.Log; import android.widget.TextView; @@ -50,10 +51,15 @@ import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; +import java.util.regex.Pattern; public class Utility { public static final Charset UTF_8 = Charset.forName("UTF-8"); + // "GMT" + "+" or "-" + 4 digits + private static final Pattern DATE_CLEANUP_PATTERN_WRONG_TIMEZONE = + Pattern.compile("GMT([-+]\\d{4})$"); + public final static String readInputStream(InputStream in, String encoding) throws IOException { InputStreamReader reader = new InputStreamReader(in, encoding); StringBuffer sb = new StringBuffer(); @@ -96,7 +102,6 @@ public class Utility { } return sb.toString(); } - public static String base64Decode(String encoded) { if (encoded == null) { return null; @@ -572,4 +577,20 @@ public class Utility { | ((sha1[offset + 2] & 0xff) << 8) | ((sha1[offset + 3] & 0xff)); } + + /** + * Try to make a date MIME(RFC 2822/5322)-compliant. + * + * It fixes: + * - "Thu, 10 Dec 09 15:08:08 GMT-0700" to "Thu, 10 Dec 09 15:08:08 -0700" + * (4 digit zone value can't be preceded by "GMT") + * We got a report saying eBay sends a date in this format + */ + public static String cleanUpMimeDate(String date) { + if (TextUtils.isEmpty(date)) { + return date; + } + date = DATE_CLEANUP_PATTERN_WRONG_TIMEZONE.matcher(date).replaceFirst("$1"); + return date; + } } diff --git a/src/org/apache/james/mime4j/field/DateTimeField.java b/src/org/apache/james/mime4j/field/DateTimeField.java index 44028c40e..a3bc71126 100644 --- a/src/org/apache/james/mime4j/field/DateTimeField.java +++ b/src/org/apache/james/mime4j/field/DateTimeField.java @@ -49,9 +49,12 @@ public class DateTimeField extends Field { public static class Parser implements FieldParser { private static Log log = LogFactory.getLog(Parser.class); - public Field parse(final String name, final String body, final String raw) { + public Field parse(final String name, String body, final String raw) { Date date = null; ParseException parseException = null; + //BEGIN android-changed + body = com.android.email.Utility.cleanUpMimeDate(body); + //END android-changed try { date = DateTime.parse(body).getDate(); } diff --git a/tests/src/com/android/email/UtilityUnitTests.java b/tests/src/com/android/email/UtilityUnitTests.java index 94df04ae2..f90b7e3c2 100644 --- a/tests/src/com/android/email/UtilityUnitTests.java +++ b/tests/src/com/android/email/UtilityUnitTests.java @@ -205,4 +205,22 @@ public class UtilityUnitTests extends AndroidTestCase { Utility.getSmallHashFromSha1(sha1); } } + + public void testCleanUpMimeDate() { + assertNull(Utility.cleanUpMimeDate(null)); + assertEquals("", Utility.cleanUpMimeDate("")); + assertEquals("abc", Utility.cleanUpMimeDate("abc")); + assertEquals("GMT", Utility.cleanUpMimeDate("GMT")); + assertEquals("0000", Utility.cleanUpMimeDate("0000")); + assertEquals("-0000", Utility.cleanUpMimeDate("-0000")); + assertEquals("+1234", Utility.cleanUpMimeDate("GMT+1234")); + assertEquals("-1234", Utility.cleanUpMimeDate("GMT-1234")); + assertEquals("gmt-1234", Utility.cleanUpMimeDate("gmt-1234")); + assertEquals("GMT-123", Utility.cleanUpMimeDate("GMT-123")); + + assertEquals("Thu, 10 Dec 09 15:08:08 -0700", + Utility.cleanUpMimeDate("Thu, 10 Dec 09 15:08:08 GMT-0700")); + assertEquals("Thu, 10 Dec 09 15:08:08 -0700", + Utility.cleanUpMimeDate("Thu, 10 Dec 09 15:08:08 -0700")); + } } diff --git a/tests/src/com/android/email/mail/internet/MimeMessageTest.java b/tests/src/com/android/email/mail/internet/MimeMessageTest.java index a9e551b5a..5ddf6980d 100644 --- a/tests/src/com/android/email/mail/internet/MimeMessageTest.java +++ b/tests/src/com/android/email/mail/internet/MimeMessageTest.java @@ -16,11 +16,13 @@ package com.android.email.mail.internet; +import com.android.email.Email; import com.android.email.mail.Address; import com.android.email.mail.Flag; import com.android.email.mail.MessagingException; import com.android.email.mail.Message.RecipientType; +import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.MediumTest; @@ -32,14 +34,12 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import junit.framework.TestCase; - /** * This is a series of unit tests for the MimeMessage class. These tests must be locally * complete - no server(s) required. */ @SmallTest -public class MimeMessageTest extends TestCase { +public class MimeMessageTest extends AndroidTestCase { /** up arrow, down arrow, left arrow, right arrow */ private final String SHORT_UNICODE = "\u2191\u2193\u2190\u2192"; @@ -61,6 +61,12 @@ public class MimeMessageTest extends TestCase { private final String LONG_PLAIN_256 = LONG_PLAIN_64 + LONG_PLAIN_64 + LONG_PLAIN_64 + LONG_PLAIN_64; + @Override + protected void setUp() throws Exception { + super.setUp(); + Email.setTempDirectory(getContext()); + } + /** * Confirms that setSentDate() correctly set the "Date" header of a Mime message. * @@ -520,5 +526,24 @@ public class MimeMessageTest extends TestCase { assertNull(mm.getMessageId()); } + /** + * Make sure the parser accepts the "eBay style" date format. + * + * Messages from ebay have been seen that they use the wrong date format. + * @see com.android.email.Utility#cleanUpMimeDate + */ + public void testEbayDate() throws MessagingException, IOException { + String entireMessage = + "To:a@b.com\r\n" + + "Date:Thu, 10 Dec 09 15:08:08 GMT-0700" + + "\r\n" + + "\r\n"; + MimeMessage mm = null; + mm = new MimeMessage(new ByteArrayInputStream(entireMessage.getBytes("us-ascii"))); + Date actual = mm.getSentDate(); + Date expected = new Date(Date.UTC(109, 11, 10, 15, 8, 8) + 7 * 60 * 60 * 1000); + assertEquals(expected, actual); + } + // TODO more test for writeTo() }