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 
17 package com.android.email;
18 
19 import android.content.Context;
20 import android.test.AndroidTestCase;
21 import android.test.suitebuilder.annotation.SmallTest;
22 
23 import com.android.emailcommon.TempDirectory;
24 import com.android.emailcommon.internet.MimeBodyPart;
25 import com.android.emailcommon.internet.MimeMessage;
26 import com.android.emailcommon.internet.MimeMultipart;
27 import com.android.emailcommon.mail.Address;
28 import com.android.emailcommon.mail.Message.RecipientType;
29 import com.android.emailcommon.mail.MessagingException;
30 import com.android.emailcommon.mail.Multipart;
31 import com.android.emailcommon.mail.Part;
32 import com.android.emailcommon.provider.EmailContent;
33 import com.android.emailcommon.provider.EmailContent.Attachment;
34 import com.android.emailcommon.utility.ConversionUtilities;
35 import com.android.emailcommon.utility.ConversionUtilities.BodyFieldData;
36 
37 import java.io.File;
38 import java.io.FileInputStream;
39 import java.io.FileOutputStream;
40 import java.io.InputStream;
41 import java.io.OutputStream;
42 import java.util.ArrayList;
43 import java.util.Date;
44 
45 @SmallTest
46 public class LegacyConversionsTest extends AndroidTestCase {
47 
48     @Override
setUp()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      */
testUpdateMessageFields_Basic()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      */
testUpdateMessageFields_PlainAddresses()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      */
testUpdateMessageFields_EncodedAddresses()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      */
testUpdateMessageFields_NoMessageId()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      */
testUpdateBodyFieldsNullText()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      */
testAttachmentRoundTrip()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