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 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 (at) droid.com>"; 80 final String replyToList = "Reply1 <reply1 (at) droid.com>,Reply2 <reply2 (at) droid.com>"; 81 final String toList = "ToA <toA (at) droid.com>,ToB <toB (at) droid.com>"; 82 final String ccList = "CcA <ccA (at) droid.com>,CcB <ccB (at) droid.com>"; 83 final String bccList = "BccA <bccA (at) droid.com>,Bcc2 <bccB (at) 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 (at) droid.com>", e); 122 String replyToList = String.format("%s <reply1 (at) droid.com>,%s <reply2 (at) droid.com>", e, e); 123 String toList = String.format("%s <toA (at) droid.com>,%s <toB (at) droid.com>", e, e); 124 String ccList = String.format("%s <ccA (at) droid.com>,%s <ccB (at) droid.com>", e, e); 125 String bccList = String.format("%s <bccA (at) droid.com>,%s <bccB (at) 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 (at) droid.com>", d); 149 String decodedReply = String.format("%s <reply1 (at) droid.com>,%s <reply2 (at) droid.com>", d, d); 150 String decodedTo = String.format("%s <toA (at) droid.com>,%s <toB (at) droid.com>", d, d); 151 String decodedCc = String.format("%s <ccA (at) droid.com>,%s <ccB (at) droid.com>", d, d); 152 String decodedBcc = String.format("%s <bccA (at) droid.com>,%s <bccB (at) 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