MimeMessageTest.java revision dfd53b0e821a6c48f128f62566066876a063fed6
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
1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.android.email.mail.internet;
1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
19d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport com.android.email.mail.Address;
207e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadlerimport com.android.email.mail.Flag;
2196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.mail.MessagingException;
22d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport com.android.email.mail.Message.RecipientType;
2396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
243b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Projectimport android.test.suitebuilder.annotation.SmallTest;
25a492673609111fe8c41ae152d62547b267346502Mihai Predaimport android.test.suitebuilder.annotation.MediumTest;
2696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
272517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Hornimport java.io.ByteArrayInputStream;
28a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaokaimport java.io.ByteArrayOutputStream;
292517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Hornimport java.io.IOException;
3096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.text.ParseException;
3196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.text.SimpleDateFormat;
3296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Date;
3396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Locale;
3496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
353b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Projectimport junit.framework.TestCase;
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
4296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class MimeMessageTest extends TestCase {
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
6496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
6596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Confirms that setSentDate() correctly set the "Date" header of a Mime message.
66961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     *
6796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * We tries a same test twice using two locales, Locale.US and the other, since
6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * MimeMessage depends on the date formatter, which may emit wrong date format
6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * in the locale other than Locale.US.
7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @throws MessagingException
7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @throws ParseException
7296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
73a492673609111fe8c41ae152d62547b267346502Mihai Preda    @MediumTest
7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void testSetSentDate() throws MessagingException, ParseException {
7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Locale savedLocale = Locale.getDefault();
7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Locale.setDefault(Locale.US);
77961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        doTestSetSentDate();
7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Locale.setDefault(Locale.JAPAN);
79961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        doTestSetSentDate();
8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Locale.setDefault(savedLocale);
8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
82961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private void doTestSetSentDate() throws MessagingException, ParseException {
84961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        // "Thu, 01 Jan 2009 09:00:00 +0000" => 1230800400000L
8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        long expectedTime = 1230800400000L;
8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Date date = new Date(expectedTime);
8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MimeMessage message = new MimeMessage();
8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        message.setSentDate(date);
8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String[] headers = message.getHeader("Date");
9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertEquals(1, headers.length);
9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // Explicitly specify the locale so that the object does not depend on the default
9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // locale.
9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
94961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Date result = format.parse(headers[0]);
9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        assertEquals(expectedTime, result.getTime());
9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
98961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
993b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    /**
1003b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project     * Simple tests of the new "Message-ID" header
1013b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project     */
1023b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    public void testMessageId() throws MessagingException {
103961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1043b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        // Test 1.  Every message gets a default and unique message-id
1053b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        MimeMessage message1 = new MimeMessage();
1063b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        MimeMessage message2 = new MimeMessage();
1073b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        String id1 = message1.getMessageId();
1083b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        String id2 = message2.getMessageId();
1093b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertNotNull(id1);
1103b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertNotNull(id2);
1113b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertFalse("Message-ID should be unique", id1.equals(id2));
112961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1133b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        // Test 2.  Set and get using API
1143b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        final String testId1 = "test-message-id-one";
1153b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        message1.setMessageId(testId1);
1163b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertEquals("set and get Message-ID", testId1, message1.getMessageId());
117961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1183b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        // Test 3.  Should only be one Message-ID per message
1193b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        final String testId2 = "test-message-id-two";
1203b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        message2.setMessageId(testId1);
1213b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        message2.setMessageId(testId2);
1223b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        assertEquals("set and get Message-ID", testId2, message2.getMessageId());
1233b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    }
1243469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1257dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /**
1263469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     * Confirm getContentID() correctly works.
1273469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     */
1283469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    public void testGetContentId() throws MessagingException {
1293469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        MimeMessage message = new MimeMessage();
1303469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1313469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        // no content-id
1323469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        assertNull(message.getContentId());
1333469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1343469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        // normal case
1353469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        final String cid1 = "cid.1@android.com";
1363469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        message.setHeader(MimeHeader.HEADER_CONTENT_ID, cid1);
1373469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        assertEquals(cid1, message.getContentId());
1383469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1393469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        // surrounded by optional bracket
1403469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        message.setHeader(MimeHeader.HEADER_CONTENT_ID, "<" + cid1 + ">");
1413469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        assertEquals(cid1, message.getContentId());
1423469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    }
143961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1447dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /**
1457dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     * Confirm that setSubject() works with plain strings
1467dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     */
1477dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    public void testSetSubjectPlain() throws MessagingException {
1487dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        MimeMessage message = new MimeMessage();
1497dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler
1507dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(SHORT_PLAIN);
151961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1527dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 1: readback
1537dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("plain subjects", SHORT_PLAIN, message.getSubject());
154961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1557dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 2: raw readback is not escaped
1567dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String rawHeader = message.getFirstHeader("Subject");
1577dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("plain subject not encoded", -1, rawHeader.indexOf("=?"));
158961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1597dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 3: long subject (shouldn't fold)
1607dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(LONG_PLAIN_64);
1617dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        rawHeader = message.getFirstHeader("Subject");
1627dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String[] split = rawHeader.split("\r\n");
1637dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("64 shouldn't fold", 1, split.length);
164961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1657dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 4: very long subject (should fold)
1667dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(LONG_PLAIN_256);
1677dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        rawHeader = message.getFirstHeader("Subject");
1687dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        split = rawHeader.split("\r\n");
1697dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertTrue("long subject should fold", split.length > 1);
1707dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        for (String s : split) {
1717dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            assertTrue("split lines max length 78", s.length() <= 76);  // 76+\r\n = 78
1727dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            String trimmed = s.trim();
1737dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            assertFalse("split lines are not encoded", trimmed.startsWith("=?"));
1747dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        }
1757dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    }
176961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1777dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /**
1787dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     * Confirm that setSubject() works with unicode strings
1797dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     */
1807dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    public void testSetSubject() throws MessagingException {
1817dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        MimeMessage message = new MimeMessage();
1827dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler
1837dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(SHORT_UNICODE);
184961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1857dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 1: readback in unicode
1867dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("unicode readback", SHORT_UNICODE, message.getSubject());
187961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1887dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 2: raw readback is escaped
1897dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String rawHeader = message.getFirstHeader("Subject");
1907dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("raw readback", SHORT_UNICODE_ENCODED, rawHeader);
1917dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    }
192961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1937dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    /**
1947dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     * Confirm folding operations on unicode subjects
1957dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler     */
1967dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    public void testSetLongSubject() throws MessagingException {
1977dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        MimeMessage message = new MimeMessage();
198961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
1997dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 1: long unicode - readback in unicode
2007dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(LONG_UNICODE_16);
2017dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("unicode readback 16", LONG_UNICODE_16, message.getSubject());
202961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
2037dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 2: longer unicode (will fold)
2047dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        message.setSubject(LONG_UNICODE_64);
2057dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertEquals("unicode readback 64", LONG_UNICODE_64, message.getSubject());
206961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
2077dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        // test 3: check folding & encoding
2087dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String rawHeader = message.getFirstHeader("Subject");
2097dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        String[] split = rawHeader.split("\r\n");
2107dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        assertTrue("long subject should fold", split.length > 1);
2117dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        for (String s : split) {
2127dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            assertTrue("split lines max length 78", s.length() <= 76);  // 76+\r\n = 78
2137dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler            String trimmed = s.trim();
214961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            assertTrue("split lines are encoded",
2157dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler                    trimmed.startsWith("=?") && trimmed.endsWith("?="));
2167dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        }
2177dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler    }
218961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
2197e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler    /**
220d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler     * Test for encoding address field.
221d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler     */
222d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    public void testEncodingAddressField() throws MessagingException {
223d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address noName1 = new Address("noname1@dom1.com");
224d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address noName2 = new Address("<noname2@dom2.com>", "");
225d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address simpleName = new Address("address3@dom3.org", "simple long and long long name");
226d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address dquoteName = new Address("address4@dom4.org", "name,4,long long name");
227d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address quotedName = new Address("bigG@dom5.net", "big \"G\"");
228d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address utf16Name = new Address("<address6@co.jp>", "\"\u65E5\u672C\u8A9E\"");
229d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address utf32Name = new Address("<address8@ne.jp>", "\uD834\uDF01\uD834\uDF46");
230961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
231d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        MimeMessage message = new MimeMessage();
232961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
233d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setFrom(noName1);
234d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setRecipient(RecipientType.TO, noName2);
235d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setRecipients(RecipientType.CC, new Address[] { simpleName, dquoteName });
236d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setReplyTo(new Address[] { quotedName, utf16Name, utf32Name });
237961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
238d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        String[] from = message.getHeader("From");
239d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        String[] to = message.getHeader("To");
240d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        String[] cc = message.getHeader("Cc");
241d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        String[] replyTo = message.getHeader("Reply-to");
242961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
243961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("from address count", 1, from.length);
244d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("no name 1", "noname1@dom1.com", from[0]);
245961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
246961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("to address count", 1, to.length);
247d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("no name 2", "noname2@dom2.com", to[0]);
248961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
249d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        // folded.
250961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("cc address count", 1, cc.length);
251d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("simple name & double quoted name",
252d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                "simple long and long long name <address3@dom3.org>, \"name,4,long long\r\n"
253d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " name\" <address4@dom4.org>",
254d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                cc[0]);
255961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
256d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        // folded and encoded.
257961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("reply-to address count", 1, replyTo.length);
258d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("quoted name & encoded name",
259d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                "\"big \\\"G\\\"\" <bigG@dom5.net>, =?UTF-8?B?5pel5pys6Kqe?=\r\n"
260d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " <address6@co.jp>, =?UTF-8?B?8J2MgfCdjYY=?= <address8@ne.jp>",
261d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                replyTo[0]);
262d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    }
263d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler
264d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    /**
265d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler     * Test for parsing address field.
266d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler     */
267d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    public void testParsingAddressField() throws MessagingException {
268d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        MimeMessage message = new MimeMessage();
269961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
270d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setHeader("From", "noname1@dom1.com");
271d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setHeader("To", "<noname2@dom2.com>");
272d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        // folded.
273d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        message.setHeader("Cc",
274d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                "simple name <address3@dom3.org>,\r\n"
275d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " \"name,4\" <address4@dom4.org>");
276d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        // folded and encoded.
277961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        message.setHeader("Reply-to",
278d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                "\"big \\\"G\\\"\" <bigG@dom5.net>,\r\n"
279d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " =?UTF-8?B?5pel5pys6Kqe?=\r\n"
280d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " <address6@co.jp>,\n"
281d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                + " \"=?UTF-8?B?8J2MgfCdjYY=?=\" <address8@ne.jp>");
282961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
283d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address[] from = message.getFrom();
284d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address[] to = message.getRecipients(RecipientType.TO);
285d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address[] cc = message.getRecipients(RecipientType.CC);
286d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        Address[] replyTo = message.getReplyTo();
287961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
288961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("from address count", 1, from.length);
289d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("no name 1 address", "noname1@dom1.com", from[0].getAddress());
290d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertNull("no name 1 name", from[0].getPersonal());
291961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
292961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("to address count", 1, to.length);
293d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("no name 2 address", "noname2@dom2.com", to[0].getAddress());
294d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertNull("no name 2 name", to[0].getPersonal());
295d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler
296961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("cc address count", 2, cc.length);
297d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("simple name address", "address3@dom3.org", cc[0].getAddress());
298d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("simple name name", "simple name", cc[0].getPersonal());
299d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("double quoted name address", "address4@dom4.org", cc[1].getAddress());
300d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("double quoted name name", "name,4", cc[1].getPersonal());
301d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler
302961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("reply-to address count", 3, replyTo.length);
303d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("quoted name address", "bigG@dom5.net", replyTo[0].getAddress());
304d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("quoted name name", "big \"G\"", replyTo[0].getPersonal());
305d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("utf-16 name address", "address6@co.jp", replyTo[1].getAddress());
306d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("utf-16 name name", "\u65E5\u672C\u8A9E", replyTo[1].getPersonal());
307d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("utf-32 name address", "address8@ne.jp", replyTo[2].getAddress());
308d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        assertEquals("utf-32 name name", "\uD834\uDF01\uD834\uDF46", replyTo[2].getPersonal());
309d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    }
310961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
311d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler    /*
3127e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler     * Test setting & getting store-specific flags
3137e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler     */
3147e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler    public void testStoreFlags() throws MessagingException {
3157e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        MimeMessage message = new MimeMessage();
3167e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3177e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        // Message should create with no flags
3187e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        Flag[] flags = message.getFlags();
3197e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertEquals(0, flags.length);
3207e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3217e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        // Set a store flag
3227e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        message.setFlag(Flag.X_STORE_1, true);
3237e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertTrue(message.isSet(Flag.X_STORE_1));
3247e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertFalse(message.isSet(Flag.X_STORE_2));
3257e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3267e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        // Set another
3277e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        message.setFlag(Flag.X_STORE_2, true);
3287e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertTrue(message.isSet(Flag.X_STORE_1));
3297e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertTrue(message.isSet(Flag.X_STORE_2));
3307e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3317e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        // Set some and clear some
3327e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        message.setFlag(Flag.X_STORE_1, false);
3337e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertFalse(message.isSet(Flag.X_STORE_1));
3347e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler        assertTrue(message.isSet(Flag.X_STORE_2));
3357e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler
3367e6df9c6aa616978efa9fc8288014735f9bf7eddAndy Stadler    }
3377dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler
338a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /*
339a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Test for setExtendedHeader() and getExtendedHeader()
340a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
341a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public void testExtendedHeader() throws MessagingException {
342a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        MimeMessage message = new MimeMessage();
343961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
344a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("non existent header", message.getExtendedHeader("X-Non-Existent"));
345961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
346a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header1", "value1");
347a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header2", "value2\n value3\r\n value4\r\n");
348a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("simple value", "value1",
349a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                message.getExtendedHeader("X-Header1"));
350a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("multi line value", "value2 value3 value4",
351a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                message.getExtendedHeader("X-Header2"));
352a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("non existent header 2", message.getExtendedHeader("X-Non-Existent"));
353961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
354a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header1", "value4");
355a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("over written value", "value4", message.getExtendedHeader("X-Header1"));
356961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
357a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header1", null);
358a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("remove header", message.getExtendedHeader("X-Header1"));
359a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
360961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
361a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /*
362a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Test for setExtendedHeaders() and getExtendedheaders()
363a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
364a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public void testExtendedHeaders() throws MessagingException {
365a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        MimeMessage message = new MimeMessage();
366a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka
367a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("new message", message.getExtendedHeaders());
368a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders(null);
369a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("null headers", message.getExtendedHeaders());
370a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders("");
371a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertNull("empty headers", message.getExtendedHeaders());
372961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
373a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders("X-Header1: value1\r\n");
374a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("header 1 value", "value1", message.getExtendedHeader("X-Header1"));
375a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("header 1", "X-Header1: value1\r\n", message.getExtendedHeaders());
376961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
377a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders(null);
378a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header2", "value2");
379a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header3",  "value3\n value4\r\n value5\r\n");
380a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("headers 2,3",
381a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header2: value2\r\n" +
382a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header3: value3 value4 value5\r\n",
383a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                message.getExtendedHeaders());
384a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka
385a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeaders(
386a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header3: value3 value4 value5\r\n" +
387a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header2: value2\r\n");
388a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("header 2", "value2", message.getExtendedHeader("X-Header2"));
389a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("header 3", "value3 value4 value5", message.getExtendedHeader("X-Header3"));
390a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("headers 3,2",
391a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header3: value3 value4 value5\r\n" +
392a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "X-Header2: value2\r\n",
393a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                message.getExtendedHeaders());
394a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
395961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
396a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /*
397a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Test for writeTo(), only for header part.
39844552da606048720de11f89321dc767ef291c391Andrew Stadler     * NOTE:  This test is fragile because it assumes headers will be written in a specific order
399a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
400a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public void testWriteToHeader() throws Exception {
401a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        MimeMessage message = new MimeMessage();
402961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
403a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setHeader("Header1", "value1");
404a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "value2");
405a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header3", "value3");
406a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setHeader("Header4", "value4");
407a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.setExtendedHeader("X-Header5", "value5");
408961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
409a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        ByteArrayOutputStream out = new ByteArrayOutputStream();
410a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        message.writeTo(out);
411a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        out.close();
41244552da606048720de11f89321dc767ef291c391Andrew Stadler        String expectedString =
413a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "Header1: value1\r\n" +
414a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "Header4: value4\r\n" +
41544552da606048720de11f89321dc767ef291c391Andrew Stadler                "Message-ID: " + message.getMessageId() + "\r\n" +
416a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                "\r\n";
417a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        byte[] expected = expectedString.getBytes();
418a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        byte[] actual = out.toByteArray();
419a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        assertEquals("output length", expected.length, actual.length);
420a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        for (int i = 0; i < actual.length; ++i) {
421a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            assertEquals("output byte["+i+"]", expected[i], actual[i]);
422a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        }
423a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
424961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
4252517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn    /**
4262517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     * Test for parsing headers with extra whitespace and commennts.
4272517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     *
4282517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     * The lines up to Content-Type were copied directly out of RFC 2822
4292517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     * "Section A.5. White space, comments, and other oddities"
4302517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn     */
4312517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn    public void testWhiteSpace() throws MessagingException, IOException {
4322517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        String entireMessage =
4332517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "From: Pete(A wonderful \\) chap) <pete(his account)@silly.test(his host)>\r\n"+
4342517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "To:A Group(Some people)\r\n"+
4352517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "     :Chris Jones <c@(Chris's host.)public.example>,\r\n"+
4362517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "         joe@example.org,\r\n"+
4372517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "  John <jdoe@one.test> (my dear friend); (the end of the group)\r\n"+
4382517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "Cc:(Empty list)(start)Undisclosed recipients  :(nobody(that I know))  ;\r\n"+
4392517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "Date: Thu,\r\n"+
4402517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "      13\r\n"+
4412517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "        Feb\r\n"+
4422517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "          1969\r\n"+
4432517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "      23:32\r\n"+
4442517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "               -0330 (Newfoundland Time)\r\n"+
4452517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "Message-ID:              <testabcd.1234@silly.test>\r\n"+
4462517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "Content-Type:                \r\n"+
4472517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "          TEXT/hTML \r\n"+
4482517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "       ; x-blah=\"y-blah\" ; \r\n"+
4492517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "       CHARSET=\"us-ascii\" ; (comment)\r\n"+
4502517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "\r\n"+
4512517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            "<html><body>Testing.</body></html>\r\n";
4522517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        MimeMessage mm = null;
4532517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        mm = new MimeMessage(new ByteArrayInputStream(
4542517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn            entireMessage.getBytes("us-ascii")));
4552517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertTrue(mm.getMimeType(), MimeUtility.mimeTypeMatches("text/html",mm.getMimeType()));
4562517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals(new Date(-27723480000L),mm.getSentDate());
4572517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals("<testabcd.1234@silly.test>",mm.getMessageId());
4582517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        Address[] toAddresses = mm.getRecipients(MimeMessage.RecipientType.TO);
4592517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals("joe@example.org", toAddresses[1].getAddress());
4602517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        assertEquals("jdoe@one.test", toAddresses[2].getAddress());
4612517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4622517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
4632517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        // Note: The parentheses in the middle of email addresses are not removed.
4642517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        //assertEquals("c@public.example", toAddresses[0].getAddress());
4652517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn        //assertEquals("pete@silly.test",mm.getFrom()[0].getAddress());
4662517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn    }
4672517a3dfd15a4bdb01677fd1ed6a63645eaad3f7Patrick Horn
468961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    /**
469961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     * Confirm parser doesn't crash when seeing "Undisclosed recipients:;".
470961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     */
471961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    public void testUndisclosedRecipients() throws MessagingException, IOException {
472961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        String entireMessage =
473961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "To:Undisclosed recipients:;\r\n"+
474961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Cc:Undisclosed recipients:;\r\n"+
475961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Bcc:Undisclosed recipients:;\r\n"+
476961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "\r\n";
477961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        MimeMessage mm = null;
478961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        mm = new MimeMessage(new ByteArrayInputStream(
479961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            entireMessage.getBytes("us-ascii")));
480961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
481961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.TO).length);
482961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.CC).length);
483961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.BCC).length);
484961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    }
485961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
486961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    /**
487961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     * Confirm parser doesn't crash when seeing invalid headers/addresses.
488961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki     */
489961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    public void testInvalidHeaders() throws MessagingException, IOException {
490961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        String entireMessage =
491961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "To:\r\n"+
492961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Cc:!invalid!address!, a@b.com\r\n"+
493961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Bcc:Undisclosed recipients;\r\n"+ // no colon at the end
494961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "invalid header\r\n"+
495961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Message-ID:<testabcd.1234@silly.test>\r\n"+
496961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "\r\n"+
497961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            "Testing\r\n";
498961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        MimeMessage mm = null;
499961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        mm = new MimeMessage(new ByteArrayInputStream(
500961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki            entireMessage.getBytes("us-ascii")));
501961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
502961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.TO).length);
503961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(1, mm.getRecipients(MimeMessage.RecipientType.CC).length);
504961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals("a@b.com", mm.getRecipients(MimeMessage.RecipientType.CC)[0].getAddress());
505961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki        assertEquals(0, mm.getRecipients(MimeMessage.RecipientType.BCC).length);
506dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        assertEquals("<testabcd.1234@silly.test>", mm.getMessageId());
507dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler    }
508dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler
509dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler    /**
510dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler     * Confirm parser w/o a message-id inhibits a local message-id from being generated
511dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler     */
512dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler    public void testParseNoMessageId() throws MessagingException, IOException {
513dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        String entireMessage =
514dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler            "To: user@domain.com\r\n" +
515dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler            "\r\n" +
516dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler            "Testing\r\n";
517dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        MimeMessage mm = null;
518dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        mm = new MimeMessage(new ByteArrayInputStream(entireMessage.getBytes("us-ascii")));
519dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler
520dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        assertNull(mm.getMessageId());
521961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki    }
522961ee151fcb7451cd17c79effdb356a5a35d547eMakoto Onuki
523a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    // TODO more test for writeTo()
524d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler}
525