1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email;
18
19import android.content.Context;
20import android.test.AndroidTestCase;
21import android.test.suitebuilder.annotation.SmallTest;
22
23import com.android.emailcommon.TempDirectory;
24import com.android.emailcommon.internet.MimeBodyPart;
25import com.android.emailcommon.internet.MimeMessage;
26import com.android.emailcommon.internet.MimeMultipart;
27import com.android.emailcommon.mail.Address;
28import com.android.emailcommon.mail.Message.RecipientType;
29import com.android.emailcommon.mail.MessagingException;
30import com.android.emailcommon.mail.Multipart;
31import com.android.emailcommon.mail.Part;
32import com.android.emailcommon.provider.EmailContent;
33import com.android.emailcommon.provider.EmailContent.Attachment;
34import com.android.emailcommon.utility.ConversionUtilities;
35import com.android.emailcommon.utility.ConversionUtilities.BodyFieldData;
36
37import java.io.File;
38import java.io.FileInputStream;
39import java.io.FileOutputStream;
40import java.io.InputStream;
41import java.io.OutputStream;
42import java.util.ArrayList;
43import java.util.Date;
44
45@SmallTest
46public class LegacyConversionsTest extends AndroidTestCase {
47
48    @Override
49    protected void setUp() throws Exception {
50        super.setUp();
51        TempDirectory.setTempDirectory(getContext());
52    }
53
54    /**
55     * Test basic fields conversion from Store message to Provider message.
56     */
57    public void testUpdateMessageFields_Basic() throws MessagingException {
58        final MimeMessage message = new MimeMessage();
59        message.setUid("UID.12345678");
60        message.setSentDate(new Date(1));
61        message.setMessageId("Test-Message-ID");
62        message.setSubject("This is the subject");
63
64        final EmailContent.Message localMessage = new EmailContent.Message();
65        final boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1);
66        assertTrue(result);
67
68        assertEquals(message.getUid(), localMessage.mServerId);
69        assertEquals(message.getSubject(), localMessage.mSubject);
70        assertEquals(message.getMessageId(), localMessage.mMessageId);
71        assertEquals(message.getSentDate().getTime(), localMessage.mTimeStamp);
72    }
73
74    /**
75     * Test the conversion of plain ASCII (not MIME-encoded) email addresses.
76     */
77    public void testUpdateMessageFields_PlainAddresses() throws MessagingException {
78        // create plain ASCII email addresses
79        final String fromList = "Sender <sender@droid.com>";
80        final String replyToList = "Reply1 <reply1@droid.com>,Reply2 <reply2@droid.com>";
81        final String toList = "ToA <toA@droid.com>,ToB <toB@droid.com>";
82        final String ccList = "CcA <ccA@droid.com>,CcB <ccB@droid.com>";
83        final String bccList = "BccA <bccA@droid.com>,Bcc2 <bccB@droid.com>";
84
85        // parse the addresses
86        final Address from = Address.fromHeader(fromList)[0];
87        final Address[] replies = Address.fromHeader(replyToList);
88        final Address[] tos = Address.fromHeader(toList);
89        final Address[] ccs = Address.fromHeader(ccList);
90        final Address[] bccs = Address.fromHeader(bccList);
91
92        // make a message with the email addresses
93        final MimeMessage message = new MimeMessage();
94        message.setFrom(from);
95        message.setReplyTo(replies);
96        message.setRecipients(RecipientType.TO, tos);
97        message.setRecipients(RecipientType.CC, ccs);
98        message.setRecipients(RecipientType.BCC, bccs);
99
100        // convert the message to a local message using the conversation method
101        final EmailContent.Message localMessage = new EmailContent.Message();
102        final boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1);
103        assertTrue(result);
104
105        // verify that we will store the email addresses in decoded form
106        assertEquals(fromList, localMessage.mFrom);
107        assertEquals(replyToList, localMessage.mReplyTo);
108        assertEquals(toList, localMessage.mTo);
109        assertEquals(ccList, localMessage.mCc);
110        assertEquals(bccList, localMessage.mBcc);
111    }
112
113    /**
114     * Test the conversion of MIME-encoded non-ASCII email addresses.
115     */
116    public void testUpdateMessageFields_EncodedAddresses() throws MessagingException {
117        final String e = "=?EUC-KR?B?uvG50Ln4yKO4pg==?="; // Mime Encoded value of 비밀번호를
118        final String d = "\uBE44\uBC00\uBC88\uD638\uB97C"; // Mime Decoded value of e
119
120        // create the email address in encoded form
121        String fromList = String.format("%s <sender@droid.com>", e);
122        String replyToList = String.format("%s <reply1@droid.com>,%s <reply2@droid.com>", e, e);
123        String toList = String.format("%s <toA@droid.com>,%s <toB@droid.com>", e, e);
124        String ccList = String.format("%s <ccA@droid.com>,%s <ccB@droid.com>", e, e);
125        String bccList = String.format("%s <bccA@droid.com>,%s <bccB@droid.com>", e, e);
126
127        // parse the encoded addresses
128        final Address from = Address.fromHeader(fromList)[0];
129        final Address[] replies = Address.fromHeader(replyToList);
130        final Address[] tos = Address.fromHeader(toList);
131        final Address[] ccs = Address.fromHeader(ccList);
132        final Address[] bccs = Address.fromHeader(bccList);
133
134        // make a message with the email addresses
135        final MimeMessage message = new MimeMessage();
136        message.setFrom(from);
137        message.setReplyTo(replies);
138        message.setRecipients(RecipientType.TO, tos);
139        message.setRecipients(RecipientType.CC, ccs);
140        message.setRecipients(RecipientType.BCC, bccs);
141
142        // convert the message to a local message using the conversion method
143        final EmailContent.Message localMessage = new EmailContent.Message();
144        final boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1);
145        assertTrue(result);
146
147        // verify that we will store the email addresses in decoded form
148        String decodedFrom = String.format("%s <sender@droid.com>", d);
149        String decodedReply = String.format("%s <reply1@droid.com>,%s <reply2@droid.com>", d, d);
150        String decodedTo = String.format("%s <toA@droid.com>,%s <toB@droid.com>", d, d);
151        String decodedCc = String.format("%s <ccA@droid.com>,%s <ccB@droid.com>", d, d);
152        String decodedBcc = String.format("%s <bccA@droid.com>,%s <bccB@droid.com>", d, d);
153
154        assertEquals(decodedFrom, localMessage.mFrom);
155        assertEquals(decodedReply, localMessage.mReplyTo);
156        assertEquals(decodedTo, localMessage.mTo);
157        assertEquals(decodedCc, localMessage.mCc);
158        assertEquals(decodedBcc, localMessage.mBcc);
159    }
160
161    /**
162     * Test basic conversion from Store message to Provider message, when the provider message
163     * does not have a proper message-id.
164     */
165    public void testUpdateMessageFields_NoMessageId() throws MessagingException {
166        final MimeMessage message = new MimeMessage();
167        // set, then remove the message id
168        message.setMessageId("Test-Message-ID");
169        message.removeHeader("Message-ID");
170
171        // create a local message with an ID
172        final EmailContent.Message localMessage = new EmailContent.Message();
173        localMessage.mMessageId = "Test-Message-ID-Second";
174
175        final boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1);
176        assertTrue(result);
177        assertEquals("Test-Message-ID-Second", localMessage.mMessageId);
178    }
179
180    /**
181     * Basic test of body parts conversion from Store message to Provider message.
182     * This tests that a null body part simply results in null text, and does not crash
183     * or return "null".
184     */
185    public void testUpdateBodyFieldsNullText() throws MessagingException {
186        ArrayList<Part> viewables = new ArrayList<Part>();
187        viewables.add(new MimeBodyPart(null, "text/plain"));
188
189        // a "null" body part of type text/plain should result in a null mTextContent
190        final BodyFieldData data = ConversionUtilities.parseBodyFields(viewables);
191        assertNull(data.textContent);
192    }
193
194    /**
195     * Test adding an attachment to a message, and then parsing it back out.
196     * @throws MessagingException
197     */
198    public void testAttachmentRoundTrip() throws Exception {
199        final Context context = getContext();
200        final MimeMultipart mp = new MimeMultipart();
201        mp.setSubType("mixed");
202
203        final long size;
204
205        final File tempDir = context.getCacheDir();
206        if (!tempDir.isDirectory() && !tempDir.mkdirs()) {
207            fail("Could not create temporary directory");
208        }
209
210        final File tempAttachmentFile = File.createTempFile("testAttachmentRoundTrip", ".txt",
211                tempDir);
212
213        try {
214            final OutputStream attOut = new FileOutputStream(tempAttachmentFile);
215            try {
216                attOut.write("TestData".getBytes());
217            } finally {
218                attOut.close();
219            }
220            size = tempAttachmentFile.length();
221            final InputStream attIn = new FileInputStream(tempAttachmentFile);
222            LegacyConversions.addAttachmentPart(mp, "text/plain", size, "test.txt",
223                    "testContentId", attIn);
224        } finally {
225            if (!tempAttachmentFile.delete()) {
226                fail("Setup failure: Could not clean up temp file");
227            }
228        }
229
230        final MimeMessage outMessage = new MimeMessage();
231        outMessage.setBody(mp);
232
233        final MimeMessage inMessage;
234
235        final File tempBodyFile = File.createTempFile("testAttachmentRoundTrip", ".eml",
236                context.getCacheDir());
237        try {
238            final OutputStream bodyOut = new FileOutputStream(tempBodyFile);
239            try {
240                outMessage.writeTo(bodyOut);
241            } finally {
242                bodyOut.close();
243            }
244            final InputStream bodyIn = new FileInputStream(tempBodyFile);
245            try {
246                inMessage = new MimeMessage(bodyIn);
247            } finally {
248                bodyIn.close();
249            }
250        } finally {
251            if (!tempBodyFile.delete()) {
252                fail("Setup failure: Could not clean up temp file");
253            }
254        }
255        final Multipart inBody = (Multipart) inMessage.getBody();
256        final Part attPart = inBody.getBodyPart(0);
257        final Attachment att = LegacyConversions.mimePartToAttachment(attPart);
258        assertEquals(att.mFileName, "test.txt");
259        assertEquals(att.mMimeType, "text/plain");
260        assertEquals(att.mSize, size);
261        assertEquals(att.mContentId, "testContentId");
262    }
263}
264