196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/*
296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License.
696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at
796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and
1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under the License.
1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
172193962ca2b3157e79f731736afa2a0c972e778aMarc Blankpackage com.android.emailcommon.internet;
1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
1931d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.TempDirectory;
202193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Address;
212193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Flag;
222193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Message.RecipientType;
2331d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.mail.MessagingException;
2496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
25128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onukiimport android.test.AndroidTestCase;
26a492673609111fe8c41ae152d62547b267346502Mihai Predaimport android.test.suitebuilder.annotation.MediumTest;
2731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport android.test.suitebuilder.annotation.SmallTest;
2896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
292517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Hornimport java.io.ByteArrayInputStream;
30a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaokaimport java.io.ByteArrayOutputStream;
312517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Hornimport java.io.IOException;
3296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.text.ParseException;
3396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.text.SimpleDateFormat;
3496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Date;
3596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Locale;
3696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
3796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/**
3896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is a series of unit tests for the MimeMessage class.  These tests must be locally
3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * complete - no server(s) required.
4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
4196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project@SmallTest
42128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onukipublic class MimeMessageTest extends AndroidTestCase {
43961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
447dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /** up arrow, down arrow, left arrow, right arrow */
457dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    private final String SHORT_UNICODE = "\u2191\u2193\u2190\u2192";
467dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    private final String SHORT_UNICODE_ENCODED = "=?UTF-8?B?4oaR4oaT4oaQ4oaS?=";
47961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
487dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /** a string without any unicode */
497dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    private final String SHORT_PLAIN = "abcd";
50961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
517dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /** longer unicode strings */
52961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    private final String LONG_UNICODE_16 = SHORT_UNICODE + SHORT_UNICODE +
537dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            SHORT_UNICODE + SHORT_UNICODE;
54961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    private final String LONG_UNICODE_64 = LONG_UNICODE_16 + LONG_UNICODE_16 +
557dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            LONG_UNICODE_16 + LONG_UNICODE_16;
567dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler
577dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /** longer plain strings (with fold points) */
587dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    private final String LONG_PLAIN_16 = "abcdefgh ijklmno";
59961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    private final String LONG_PLAIN_64 =
607dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        LONG_PLAIN_16 + LONG_PLAIN_16 + LONG_PLAIN_16 + LONG_PLAIN_16;
61961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    private final String LONG_PLAIN_256 =
627dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        LONG_PLAIN_64 + LONG_PLAIN_64 + LONG_PLAIN_64 + LONG_PLAIN_64;
6396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
64128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki    @Override
65128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki    protected void setUp() throws Exception {
66128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki        super.setUp();
6731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank        TempDirectory.setTempDirectory(getContext());
68128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki    }
69128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki
7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Confirms that setSentDate() correctly set the "Date" header of a Mime message.
72961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     *
7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * We tries a same test twice using two locales, Locale.US and the other, since
7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * MimeMessage depends on the date formatter, which may emit wrong date format
7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * in the locale other than Locale.US.
7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @throws MessagingException
7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @throws ParseException
7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
79a492673609111fe8c41ae152d62547b267346502Mihai Preda    @MediumTest
8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void testSetSentDate() throws MessagingException, ParseException {
8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Locale savedLocale = Locale.getDefault();
8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Locale.setDefault(Locale.US);
83961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        doTestSetSentDate();
8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Locale.setDefault(Locale.JAPAN);
85961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        doTestSetSentDate();
8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Locale.setDefault(savedLocale);
8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
88961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private void doTestSetSentDate() throws MessagingException, ParseException {
90961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        // "Thu, 01 Jan 2009 09:00:00 +0000" => 1230800400000L
9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        long expectedTime = 1230800400000L;
9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Date date = new Date(expectedTime);
9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MimeMessage message = new MimeMessage();
9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        message.setSentDate(date);
9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String[] headers = message.getHeader("Date");
9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertEquals(1, headers.length);
9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // Explicitly specify the locale so that the object does not depend on the default
9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // locale.
9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
100961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
10196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Date result = format.parse(headers[0]);
10296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertEquals(expectedTime, result.getTime());
10396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
104961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1053b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    /**
1063b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project     * Simple tests of the new "Message-ID" header
1073b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project     */
1083b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    public void testMessageId() throws MessagingException {
109961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1103b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        // Test 1.  Every message gets a default and unique message-id
1113b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        MimeMessage message1 = new MimeMessage();
1123b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        MimeMessage message2 = new MimeMessage();
1133b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        String id1 = message1.getMessageId();
1143b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        String id2 = message2.getMessageId();
1153b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertNotNull(id1);
1163b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertNotNull(id2);
1173b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertFalse("Message-ID should be unique", id1.equals(id2));
118961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1193b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        // Test 2.  Set and get using API
1203b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        final String testId1 = "test-message-id-one";
1213b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        message1.setMessageId(testId1);
1223b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertEquals("set and get Message-ID", testId1, message1.getMessageId());
123961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1243b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        // Test 3.  Should only be one Message-ID per message
1253b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        final String testId2 = "test-message-id-two";
1263b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        message2.setMessageId(testId1);
1273b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        message2.setMessageId(testId2);
1283b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertEquals("set and get Message-ID", testId2, message2.getMessageId());
1293b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    }
1303469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1317dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /**
1323469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     * Confirm getContentID() correctly works.
1333469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     */
1343469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    public void testGetContentId() throws MessagingException {
1353469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        MimeMessage message = new MimeMessage();
1363469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1373469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        // no content-id
1383469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        assertNull(message.getContentId());
1393469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1403469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        // normal case
1413469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        final String cid1 = "cid.1@android.com";
1423469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        message.setHeader(MimeHeader.HEADER_CONTENT_ID, cid1);
1433469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        assertEquals(cid1, message.getContentId());
1443469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1453469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        // surrounded by optional bracket
1463469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        message.setHeader(MimeHeader.HEADER_CONTENT_ID, "<" + cid1 + ">");
1473469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        assertEquals(cid1, message.getContentId());
1483469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    }
149961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1507dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /**
1517dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     * Confirm that setSubject() works with plain strings
1527dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     */
1537dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    public void testSetSubjectPlain() throws MessagingException {
1547dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        MimeMessage message = new MimeMessage();
1557dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler
1567dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(SHORT_PLAIN);
157961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1587dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 1: readback
1597dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("plain subjects", SHORT_PLAIN, message.getSubject());
160961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1617dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 2: raw readback is not escaped
1627dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String rawHeader = message.getFirstHeader("Subject");
1637dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("plain subject not encoded", -1, rawHeader.indexOf("=?"));
164961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1657dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 3: long subject (shouldn't fold)
1667dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(LONG_PLAIN_64);
1677dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        rawHeader = message.getFirstHeader("Subject");
1687dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String[] split = rawHeader.split("\r\n");
1697dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("64 shouldn't fold", 1, split.length);
170961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1717dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 4: very long subject (should fold)
1727dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(LONG_PLAIN_256);
1737dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        rawHeader = message.getFirstHeader("Subject");
1747dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        split = rawHeader.split("\r\n");
1757dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertTrue("long subject should fold", split.length > 1);
1767dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        for (String s : split) {
1777dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            assertTrue("split lines max length 78", s.length() <= 76);  // 76+\r\n = 78
1787dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            String trimmed = s.trim();
1797dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            assertFalse("split lines are not encoded", trimmed.startsWith("=?"));
1807dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        }
1817dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    }
182961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1837dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /**
1847dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     * Confirm that setSubject() works with unicode strings
1857dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     */
1867dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    public void testSetSubject() throws MessagingException {
1877dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        MimeMessage message = new MimeMessage();
1887dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler
1897dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(SHORT_UNICODE);
190961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1917dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 1: readback in unicode
1927dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("unicode readback", SHORT_UNICODE, message.getSubject());
193961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1947dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 2: raw readback is escaped
1957dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String rawHeader = message.getFirstHeader("Subject");
1967dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("raw readback", SHORT_UNICODE_ENCODED, rawHeader);
1977dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    }
198961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1997dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /**
2007dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     * Confirm folding operations on unicode subjects
2017dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     */
2027dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    public void testSetLongSubject() throws MessagingException {
2037dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        MimeMessage message = new MimeMessage();
204961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
2057dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 1: long unicode - readback in unicode
2067dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(LONG_UNICODE_16);
2077dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("unicode readback 16", LONG_UNICODE_16, message.getSubject());
208961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
2097dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 2: longer unicode (will fold)
2107dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(LONG_UNICODE_64);
2117dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("unicode readback 64", LONG_UNICODE_64, message.getSubject());
212961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
2137dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 3: check folding & encoding
2147dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String rawHeader = message.getFirstHeader("Subject");
2157dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String[] split = rawHeader.split("\r\n");
2167dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertTrue("long subject should fold", split.length > 1);
2177dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        for (String s : split) {
2187dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            assertTrue("split lines max length 78", s.length() <= 76);  // 76+\r\n = 78
2197dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            String trimmed = s.trim();
220961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            assertTrue("split lines are encoded",
2217dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler                    trimmed.startsWith("=?") && trimmed.endsWith("?="));
2227dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        }
2237dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    }
224961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
2257e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler    /**
226d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler     * Test for encoding address field.
227d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler     */
228d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    public void testEncodingAddressField() throws MessagingException {
229d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address noName1 = new Address("noname1@dom1.com");
230d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address noName2 = new Address("<noname2@dom2.com>", "");
231d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address simpleName = new Address("address3@dom3.org", "simple long and long long name");
232d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address dquoteName = new Address("address4@dom4.org", "name,4,long long name");
233d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address quotedName = new Address("bigG@dom5.net", "big \"G\"");
234d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address utf16Name = new Address("<address6@co.jp>", "\"\u65E5\u672C\u8A9E\"");
235d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address utf32Name = new Address("<address8@ne.jp>", "\uD834\uDF01\uD834\uDF46");
236961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
237d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        MimeMessage message = new MimeMessage();
238961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
239d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setFrom(noName1);
240d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setRecipient(RecipientType.TO, noName2);
241d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setRecipients(RecipientType.CC, new Address[] { simpleName, dquoteName });
242d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setReplyTo(new Address[] { quotedName, utf16Name, utf32Name });
243961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
244d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        String[] from = message.getHeader("From");
245d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        String[] to = message.getHeader("To");
246d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        String[] cc = message.getHeader("Cc");
247d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        String[] replyTo = message.getHeader("Reply-to");
248961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
249961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("from address count", 1, from.length);
250d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("no name 1", "noname1@dom1.com", from[0]);
251961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
252961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("to address count", 1, to.length);
253d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("no name 2", "noname2@dom2.com", to[0]);
254961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
255d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        // folded.
256961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("cc address count", 1, cc.length);
257d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("simple name & double quoted name",
258d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                "simple long and long long name <address3@dom3.org>, \"name,4,long long\r\n"
259d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " name\" <address4@dom4.org>",
260d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                cc[0]);
261961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
262d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        // folded and encoded.
263961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("reply-to address count", 1, replyTo.length);
264d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("quoted name & encoded name",
265d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                "\"big \\\"G\\\"\" <bigG@dom5.net>, =?UTF-8?B?5pel5pys6Kqe?=\r\n"
266d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " <address6@co.jp>, =?UTF-8?B?8J2MgfCdjYY=?= <address8@ne.jp>",
267d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                replyTo[0]);
268d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    }
269d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler
270d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    /**
271d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler     * Test for parsing address field.
272d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler     */
273d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    public void testParsingAddressField() throws MessagingException {
274d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        MimeMessage message = new MimeMessage();
275961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
276d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setHeader("From", "noname1@dom1.com");
277d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setHeader("To", "<noname2@dom2.com>");
278d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        // folded.
279d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setHeader("Cc",
280d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                "simple name <address3@dom3.org>,\r\n"
281d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " \"name,4\" <address4@dom4.org>");
282d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        // folded and encoded.
283961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        message.setHeader("Reply-to",
284d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                "\"big \\\"G\\\"\" <bigG@dom5.net>,\r\n"
285d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " =?UTF-8?B?5pel5pys6Kqe?=\r\n"
286d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " <address6@co.jp>,\n"
287d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " \"=?UTF-8?B?8J2MgfCdjYY=?=\" <address8@ne.jp>");
288961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
289d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address[] from = message.getFrom();
290d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address[] to = message.getRecipients(RecipientType.TO);
291d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address[] cc = message.getRecipients(RecipientType.CC);
292d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address[] replyTo = message.getReplyTo();
293961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
294961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("from address count", 1, from.length);
295d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("no name 1 address", "noname1@dom1.com", from[0].getAddress());
296d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertNull("no name 1 name", from[0].getPersonal());
297961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
298961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("to address count", 1, to.length);
299d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("no name 2 address", "noname2@dom2.com", to[0].getAddress());
300d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertNull("no name 2 name", to[0].getPersonal());
301d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler
302961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("cc address count", 2, cc.length);
303d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("simple name address", "address3@dom3.org", cc[0].getAddress());
304d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("simple name name", "simple name", cc[0].getPersonal());
305d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("double quoted name address", "address4@dom4.org", cc[1].getAddress());
306d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("double quoted name name", "name,4", cc[1].getPersonal());
307d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler
308961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("reply-to address count", 3, replyTo.length);
309d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("quoted name address", "bigG@dom5.net", replyTo[0].getAddress());
310d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("quoted name name", "big \"G\"", replyTo[0].getPersonal());
311d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("utf-16 name address", "address6@co.jp", replyTo[1].getAddress());
312d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("utf-16 name name", "\u65E5\u672C\u8A9E", replyTo[1].getPersonal());
313d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("utf-32 name address", "address8@ne.jp", replyTo[2].getAddress());
314d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("utf-32 name name", "\uD834\uDF01\uD834\uDF46", replyTo[2].getPersonal());
315d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    }
316961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
317d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    /*
3187e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler     * Test setting & getting store-specific flags
3197e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler     */
3207e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler    public void testStoreFlags() throws MessagingException {
3217e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        MimeMessage message = new MimeMessage();
3227e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3237e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        // Message should create with no flags
3247e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        Flag[] flags = message.getFlags();
3257e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertEquals(0, flags.length);
3267e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3277e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        // Set a store flag
3287e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        message.setFlag(Flag.X_STORE_1, true);
3297e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertTrue(message.isSet(Flag.X_STORE_1));
3307e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertFalse(message.isSet(Flag.X_STORE_2));
3317e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3327e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        // Set another
3337e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        message.setFlag(Flag.X_STORE_2, true);
3347e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertTrue(message.isSet(Flag.X_STORE_1));
3357e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertTrue(message.isSet(Flag.X_STORE_2));
3367e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3377e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        // Set some and clear some
3387e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        message.setFlag(Flag.X_STORE_1, false);
3397e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertFalse(message.isSet(Flag.X_STORE_1));
3407e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertTrue(message.isSet(Flag.X_STORE_2));
3417e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3427e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler    }
3437dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler
344a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /*
345a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Test for setExtendedHeader() and getExtendedHeader()
346a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
347a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public void testExtendedHeader() throws MessagingException {
348a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        MimeMessage message = new MimeMessage();
349961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
350a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("non existent header", message.getExtendedHeader("X-Non-Existent"));
351961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
352a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header1", "value1");
353a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header2", "value2\n value3\r\n value4\r\n");
354a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("simple value", "value1",
355a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                message.getExtendedHeader("X-Header1"));
356a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("multi line value", "value2 value3 value4",
357a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                message.getExtendedHeader("X-Header2"));
358a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("non existent header 2", message.getExtendedHeader("X-Non-Existent"));
359961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
360a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header1", "value4");
361a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("over written value", "value4", message.getExtendedHeader("X-Header1"));
362961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
363a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header1", null);
364a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("remove header", message.getExtendedHeader("X-Header1"));
365a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
366961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
367a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /*
368a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Test for setExtendedHeaders() and getExtendedheaders()
369a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
370a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public void testExtendedHeaders() throws MessagingException {
371a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        MimeMessage message = new MimeMessage();
372a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka
373a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("new message", message.getExtendedHeaders());
374a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders(null);
375a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("null headers", message.getExtendedHeaders());
376a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders("");
377a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("empty headers", message.getExtendedHeaders());
378961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
379a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders("X-Header1: value1\r\n");
380a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("header 1 value", "value1", message.getExtendedHeader("X-Header1"));
381a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("header 1", "X-Header1: value1\r\n", message.getExtendedHeaders());
382961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
383a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders(null);
384a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header2", "value2");
385a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header3",  "value3\n value4\r\n value5\r\n");
386a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("headers 2,3",
387a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header2: value2\r\n" +
388a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header3: value3 value4 value5\r\n",
389a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                message.getExtendedHeaders());
390a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka
391a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders(
392a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header3: value3 value4 value5\r\n" +
393a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header2: value2\r\n");
394a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("header 2", "value2", message.getExtendedHeader("X-Header2"));
395a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("header 3", "value3 value4 value5", message.getExtendedHeader("X-Header3"));
396a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("headers 3,2",
397a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header3: value3 value4 value5\r\n" +
398a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header2: value2\r\n",
399a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                message.getExtendedHeaders());
400a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
401961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
402a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /*
403a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Test for writeTo(), only for header part.
40444552da606048720de11f89321dc767ef291c391Andrew Stadler     * NOTE:  This test is fragile because it assumes headers will be written in a specific order
405a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
406a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public void testWriteToHeader() throws Exception {
407a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        MimeMessage message = new MimeMessage();
408961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
409a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setHeader("Header1", "value1");
410a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "value2");
411a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header3", "value3");
412a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setHeader("Header4", "value4");
413a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header5", "value5");
414961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
415a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        ByteArrayOutputStream out = new ByteArrayOutputStream();
416a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.writeTo(out);
417a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        out.close();
41844552da606048720de11f89321dc767ef291c391Andrew Stadler        String expectedString =
419a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "Header1: value1\r\n" +
420a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "Header4: value4\r\n" +
42144552da606048720de11f89321dc767ef291c391Andrew Stadler                "Message-ID: " + message.getMessageId() + "\r\n" +
422a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "\r\n";
423a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        byte[] expected = expectedString.getBytes();
424a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        byte[] actual = out.toByteArray();
425a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("output length", expected.length, actual.length);
426a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        for (int i = 0; i < actual.length; ++i) {
427a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            assertEquals("output byte["+i+"]", expected[i], actual[i]);
428a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        }
429a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
430961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
4312517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn    /**
4322517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     * Test for parsing headers with extra whitespace and commennts.
4332517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *
4342517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     * The lines up to Content-Type were copied directly out of RFC 2822
4352517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     * "Section A.5. White space, comments, and other oddities"
4362517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     */
4372517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn    public void testWhiteSpace() throws MessagingException, IOException {
4382517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        String entireMessage =
4392517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "From: Pete(A wonderful \\) chap) <pete(his account)@silly.test(his host)>\r\n"+
4402517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "To:A Group(Some people)\r\n"+
4412517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "     :Chris Jones <c@(Chris's host.)public.example>,\r\n"+
4422517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "         joe@example.org,\r\n"+
4432517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "  John <jdoe@one.test> (my dear friend); (the end of the group)\r\n"+
4442517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "Cc:(Empty list)(start)Undisclosed recipients  :(nobody(that I know))  ;\r\n"+
4452517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "Date: Thu,\r\n"+
4462517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "      13\r\n"+
4472517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "        Feb\r\n"+
4482517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "          1969\r\n"+
4492517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "      23:32\r\n"+
4502517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "               -0330 (Newfoundland Time)\r\n"+
4512517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "Message-ID:              <testabcd.1234@silly.test>\r\n"+
4522517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "Content-Type:                \r\n"+
4532517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "          TEXT/hTML \r\n"+
4542517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "       ; x-blah=\"y-blah\" ; \r\n"+
4552517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "       CHARSET=\"us-ascii\" ; (comment)\r\n"+
4562517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "\r\n"+
4572517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "<html><body>Testing.</body></html>\r\n";
4582517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        MimeMessage mm = null;
4592517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        mm = new MimeMessage(new ByteArrayInputStream(
4602517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            entireMessage.getBytes("us-ascii")));
4612517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(mm.getMimeType(), MimeUtility.mimeTypeMatches("text/html",mm.getMimeType()));
4622517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals(new Date(-27723480000L),mm.getSentDate());
4632517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals("<testabcd.1234@silly.test>",mm.getMessageId());
4642517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        Address[] toAddresses = mm.getRecipients(MimeMessage.RecipientType.TO);
4652517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals("joe@example.org", toAddresses[1].getAddress());
4662517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals("jdoe@one.test", toAddresses[2].getAddress());
4672517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4682517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4692517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // Note: The parentheses in the middle of email addresses are not removed.
4702517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        //assertEquals("c@public.example", toAddresses[0].getAddress());
4712517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        //assertEquals("pete@silly.test",mm.getFrom()[0].getAddress());
4722517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn    }
4732517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
474961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    /**
475961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     * Confirm parser doesn't crash when seeing "Undisclosed recipients:;".
476961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     */
477961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    public void testUndisclosedRecipients() throws MessagingException, IOException {
478961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        String entireMessage =
479961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "To:Undisclosed recipients:;\r\n"+
480961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Cc:Undisclosed recipients:;\r\n"+
481961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Bcc:Undisclosed recipients:;\r\n"+
482961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "\r\n";
483961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        MimeMessage mm = null;
484961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        mm = new MimeMessage(new ByteArrayInputStream(
485961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            entireMessage.getBytes("us-ascii")));
486961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
487961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.TO).length);
488961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.CC).length);
489961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.BCC).length);
490961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    }
491961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
492961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    /**
493961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     * Confirm parser doesn't crash when seeing invalid headers/addresses.
494961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     */
495961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    public void testInvalidHeaders() throws MessagingException, IOException {
496961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        String entireMessage =
497961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "To:\r\n"+
498961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Cc:!invalid!address!, a@b.com\r\n"+
499961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Bcc:Undisclosed recipients;\r\n"+ // no colon at the end
500961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "invalid header\r\n"+
501961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Message-ID:<testabcd.1234@silly.test>\r\n"+
502961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "\r\n"+
503961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Testing\r\n";
504961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        MimeMessage mm = null;
505961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        mm = new MimeMessage(new ByteArrayInputStream(
506961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            entireMessage.getBytes("us-ascii")));
507961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
508961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.TO).length);
509961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(1, mm.getRecipients(MimeMessage.RecipientType.CC).length);
510961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("a@b.com", mm.getRecipients(MimeMessage.RecipientType.CC)[0].getAddress());
511961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.BCC).length);
512dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        assertEquals("<testabcd.1234@silly.test>", mm.getMessageId());
513dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler    }
514dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler
515dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler    /**
516dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler     * Confirm parser w/o a message-id inhibits a local message-id from being generated
517dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler     */
518dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler    public void testParseNoMessageId() throws MessagingException, IOException {
519dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        String entireMessage =
520dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler            "To: user@domain.com\r\n" +
521dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler            "\r\n" +
522dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler            "Testing\r\n";
523dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        MimeMessage mm = null;
524dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        mm = new MimeMessage(new ByteArrayInputStream(entireMessage.getBytes("us-ascii")));
525dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler
526dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        assertNull(mm.getMessageId());
527961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    }
528961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
529128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki    /**
530128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki     * Make sure the parser accepts the "eBay style" date format.
531128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki     *
532128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki     * Messages from ebay have been seen that they use the wrong date format.
53331d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank     * @see com.android.emailcommon.utility.Utility#cleanUpMimeDate
534128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki     */
535128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki    public void testEbayDate() throws MessagingException, IOException {
536128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki        String entireMessage =
537128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki            "To:a@b.com\r\n" +
538128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki            "Date:Thu, 10 Dec 09 15:08:08 GMT-0700" +
539128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki            "\r\n" +
540128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki            "\r\n";
541128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki        MimeMessage mm = null;
542128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki        mm = new MimeMessage(new ByteArrayInputStream(entireMessage.getBytes("us-ascii")));
543128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki        Date actual = mm.getSentDate();
544128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki        Date expected = new Date(Date.UTC(109, 11, 10, 15, 8, 8) + 7 * 60 * 60 * 1000);
545128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki        assertEquals(expected, actual);
546128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki    }
547128fb393e8ed613c2ce283c0bd51684af2ba444dMakoto Onuki
548a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    // TODO more test for writeTo()
549d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler}
550