LegacyConversionsTests.java revision 515d830e8755d3674e04bcc60d7f85b4fa7fb202
13f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler/* 23f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * Copyright (C) 2009 The Android Open Source Project 33f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * 43f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * Licensed under the Apache License, Version 2.0 (the "License"); 53f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * you may not use this file except in compliance with the License. 63f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * You may obtain a copy of the License at 73f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * 83f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * http://www.apache.org/licenses/LICENSE-2.0 93f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * 103f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * Unless required by applicable law or agreed to in writing, software 113f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * distributed under the License is distributed on an "AS IS" BASIS, 123f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * See the License for the specific language governing permissions and 143f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * limitations under the License. 153f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler */ 163f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 173f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadlerpackage com.android.email; 183f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 19515d830e8755d3674e04bcc60d7f85b4fa7fb202Jerry Xieimport android.content.ContentUris; 20515d830e8755d3674e04bcc60d7f85b4fa7fb202Jerry Xieimport android.content.Context; 21515d830e8755d3674e04bcc60d7f85b4fa7fb202Jerry Xieimport android.database.Cursor; 22515d830e8755d3674e04bcc60d7f85b4fa7fb202Jerry Xieimport android.net.Uri; 23515d830e8755d3674e04bcc60d7f85b4fa7fb202Jerry Xieimport android.test.ProviderTestCase2; 24515d830e8755d3674e04bcc60d7f85b4fa7fb202Jerry Xie 2575a873be8420e50f0aeb5a77716358ee0ca66b01Marc Blankimport com.android.email.provider.EmailProvider; 2675a873be8420e50f0aeb5a77716358ee0ca66b01Marc Blankimport com.android.email.provider.ProviderTestUtils; 272193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.MimeBodyPart; 282193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.MimeHeader; 292193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.MimeMessage; 302193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.MimeUtility; 312193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.internet.TextBody; 322193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Address; 332193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.BodyPart; 342193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Flag; 352193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Message; 362193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Message.RecipientType; 3731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.mail.MessageTestUtils; 382193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessageTestUtils.MessageBuilder; 392193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessageTestUtils.MultipartBuilder; 4031d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.mail.MessagingException; 4131d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.mail.Part; 42a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent; 43a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Attachment; 448a574694606f0e5d781334d0d426fc379c51f3edMarc Blankimport com.android.emailcommon.utility.ConversionUtilities; 45515d830e8755d3674e04bcc60d7f85b4fa7fb202Jerry Xieimport com.android.emailcommon.utility.ConversionUtilities.BodyFieldData; 463f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 473f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadlerimport java.io.IOException; 483f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadlerimport java.util.ArrayList; 49eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadlerimport java.util.Date; 503f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 513f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler/** 523f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * Tests of the Legacy Conversions code (used by MessagingController). 530993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * 543f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * NOTE: It would probably make sense to rewrite this using a MockProvider, instead of the 553f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * ProviderTestCase (which is a real provider running on a temp database). This would be more of 563f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * a true "unit test". 570993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * 583f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * You can run this entire test case with: 593f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * runtest -c com.android.email.LegacyConversionsTests email 603f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler */ 613f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadlerpublic class LegacyConversionsTests extends ProviderTestCase2<EmailProvider> { 623f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 63eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private static final String UID = "UID.12345678"; 64eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private static final String SENDER = "sender@android.com"; 65eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private static final String RECIPIENT_TO = "recipient-to@android.com"; 66eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private static final String RECIPIENT_CC = "recipient-cc@android.com"; 67eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private static final String RECIPIENT_BCC = "recipient-bcc@android.com"; 68eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private static final String REPLY_TO = "reply-to@android.com"; 69eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private static final String SUBJECT = "This is the subject"; 70eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private static final String MESSAGE_ID = "Test-Message-ID"; 71eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private static final String MESSAGE_ID_2 = "Test-Message-ID-Second"; 72eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 733f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler EmailProvider mProvider; 743f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler Context mProviderContext; 753f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler Context mContext; 765e91cccd4b530eb2aeace5c5bf4f3328a5b5d69dAndrew Stadler Preferences mPreferences = null; 773f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 783f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler public LegacyConversionsTests() { 7931d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank super(EmailProvider.class, EmailContent.AUTHORITY); 803f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 813f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 823f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler @Override 833f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler public void setUp() throws Exception { 843f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler super.setUp(); 853f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler mProviderContext = getMockContext(); 863f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler mContext = getContext(); 873f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 883f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 893f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler /** 903f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * TODO: basic Legacy -> Provider Message conversions 913f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * TODO: basic Legacy -> Provider Body conversions 923f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * TODO: rainy day tests of all kinds 933f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler */ 943f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 953f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler /** 96eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * Test basic conversion from Store message to Provider message 97eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * 98eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * TODO: Not a complete test of all fields, and some fields need special tests (e.g. flags) 99eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * TODO: There are many special cases in the tested function, that need to be 100eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * tested here as well. 101eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler */ 102eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler public void testUpdateMessageFields() throws MessagingException { 103eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler MimeMessage message = buildTestMessage(RECIPIENT_TO, RECIPIENT_CC, RECIPIENT_BCC, 104eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler REPLY_TO, SENDER, SUBJECT, null); 105eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler EmailContent.Message localMessage = new EmailContent.Message(); 106eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 107eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1); 108eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertTrue(result); 109eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler checkProviderMessage("testUpdateMessageFields", message, localMessage); 110eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 111eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 112eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler /** 113eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * Test basic conversion from Store message to Provider message, when the provider message 114eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * does not have a proper message-id. 115eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler */ 116eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler public void testUpdateMessageFieldsNoMessageId() throws MessagingException { 117eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler MimeMessage message = buildTestMessage(RECIPIENT_TO, RECIPIENT_CC, RECIPIENT_BCC, 118eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler REPLY_TO, SENDER, SUBJECT, null); 119eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler EmailContent.Message localMessage = new EmailContent.Message(); 120eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 121eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler // If the source message-id is null, the target should be left as-is 122eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler localMessage.mMessageId = MESSAGE_ID_2; 123eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.removeHeader("Message-ID"); 124eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 125eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler boolean result = LegacyConversions.updateMessageFields(localMessage, message, 1, 1); 126eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertTrue(result); 127eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(MESSAGE_ID_2, localMessage.mMessageId); 128eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 129eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 130eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler /** 131eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * Build a lightweight Store message with simple field population 132eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler */ 133eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private MimeMessage buildTestMessage(String to, String cc, String bcc, String replyTo, 134eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler String sender, String subject, String content) throws MessagingException { 135eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler MimeMessage message = new MimeMessage(); 136eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 137eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler if (to != null) { 138eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler Address[] addresses = Address.parse(to); 139eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setRecipients(RecipientType.TO, addresses); 140eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 141eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler if (cc != null) { 142eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler Address[] addresses = Address.parse(cc); 143eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setRecipients(RecipientType.CC, addresses); 144eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 145eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler if (bcc != null) { 146eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler Address[] addresses = Address.parse(bcc); 147eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setRecipients(RecipientType.BCC, addresses); 148eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 149eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler if (replyTo != null) { 150eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler Address[] addresses = Address.parse(replyTo); 151eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setReplyTo(addresses); 152eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 153eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler if (sender != null) { 154eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler Address[] addresses = Address.parse(sender); 1555e91cccd4b530eb2aeace5c5bf4f3328a5b5d69dAndrew Stadler message.setFrom(addresses[0]); 156eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 157eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler if (subject != null) { 158eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setSubject(subject); 159eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 160eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler if (content != null) { 161eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler TextBody body = new TextBody(content); 162eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setBody(body); 163eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 164eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 165eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setUid(UID); 166eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setSentDate(new Date()); 167eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setInternalDate(new Date()); 168eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler message.setMessageId(MESSAGE_ID); 169eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler return message; 170eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 171eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 172eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler /** 173b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler * Basic test of body parts conversion from Store message to Provider message. 174b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler * This tests that a null body part simply results in null text, and does not crash 175b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler * or return "null". 176b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler * 177b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler * TODO very incomplete, there are many permutations to be explored 178b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler */ 179b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler public void testUpdateBodyFieldsNullText() throws MessagingException { 180b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler EmailContent.Body localBody = new EmailContent.Body(); 181b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler EmailContent.Message localMessage = new EmailContent.Message(); 182b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler ArrayList<Part> viewables = new ArrayList<Part>(); 183b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler Part emptyTextPart = new MimeBodyPart(null, "text/plain"); 184b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler viewables.add(emptyTextPart); 185b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler 186b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler // a "null" body part of type text/plain should result in a null mTextContent 1876be411edd0ef5a1fb357d90c7fee22de83632be5Andrew Sapperstein final BodyFieldData data = 1886be411edd0ef5a1fb357d90c7fee22de83632be5Andrew Sapperstein ConversionUtilities.parseBodyFields(viewables); 1896be411edd0ef5a1fb357d90c7fee22de83632be5Andrew Sapperstein assertNull(data.textContent); 190b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler } 191b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler 192b6756688b1bf07c50b999c9d30dd6cb224d3812bAndrew Stadler /** 1937d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler * Sunny day test of adding attachments from an IMAP/POP message. 1943f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler */ 1953f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler public void testAddAttachments() throws MessagingException, IOException { 1963f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler // Prepare a local message to add the attachments to 1973f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler final long accountId = 1; 1983f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler final long mailboxId = 1; 1997d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler 2007d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler // test 1: legacy message using content-type:name style for name 2013f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler final EmailContent.Message localMessage = ProviderTestUtils.setupMessage( 2023f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler "local-message", accountId, mailboxId, false, true, mProviderContext); 2037d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler final Message legacyMessage = prepareLegacyMessageWithAttachments(2, false); 2047d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler convertAndCheckcheckAddedAttachments(localMessage, legacyMessage); 2053f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 2067d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler // test 2: legacy message using content-disposition:filename style for name 2077d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler final EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage( 2087d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler "local-message", accountId, mailboxId, false, true, mProviderContext); 2097d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler final Message legacyMessage2 = prepareLegacyMessageWithAttachments(2, true); 2107d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler convertAndCheckcheckAddedAttachments(localMessage2, legacyMessage2); 2117d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler } 2123f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 2137d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler /** 2147d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler * Helper for testAddAttachments 2157d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler */ 2167d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler private void convertAndCheckcheckAddedAttachments(final EmailContent.Message localMessage, 2177d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler final Message legacyMessage) throws MessagingException, IOException { 2183f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler // Now, convert from legacy to provider and see what happens 2193f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler ArrayList<Part> viewables = new ArrayList<Part>(); 2203f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler ArrayList<Part> attachments = new ArrayList<Part>(); 2213f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler MimeUtility.collectParts(legacyMessage, viewables, attachments); 2227d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments); 2233f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 2243f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler // Read back all attachments for message and check field values 2253f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId); 2263f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler Cursor c = mProviderContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION, 2273f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler null, null, null); 2283f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler try { 2293f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler assertEquals(2, c.getCount()); 2303f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler while (c.moveToNext()) { 2313f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler Attachment attachment = Attachment.getContent(c, Attachment.class); 232e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler if ("100".equals(attachment.mLocation)) { 23375a873be8420e50f0aeb5a77716358ee0ca66b01Marc Blank checkAttachment("attachment1Part", attachments.get(0), attachment, 23475a873be8420e50f0aeb5a77716358ee0ca66b01Marc Blank localMessage.mAccountKey); 235e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler } else if ("101".equals(attachment.mLocation)) { 23675a873be8420e50f0aeb5a77716358ee0ca66b01Marc Blank checkAttachment("attachment2Part", attachments.get(1), attachment, 23775a873be8420e50f0aeb5a77716358ee0ca66b01Marc Blank localMessage.mAccountKey); 2383f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } else { 2393f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler fail("Unexpected attachment with location " + attachment.mLocation); 2403f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 2413f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 2423f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } finally { 2433f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler c.close(); 2443f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 2453f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 2463f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 2473f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler /** 248e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler * Test that only "attachment" or "inline" attachments are captured and added. 249e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler * @throws MessagingException 250e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler * @throws IOException 251e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler */ 252e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler public void testAttachmentDispositions() throws MessagingException, IOException { 253e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler // Prepare a local message to add the attachments to 254e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler final long accountId = 1; 255e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler final long mailboxId = 1; 256e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler 257e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler // Prepare the three attachments we want to test 258e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler BodyPart[] sourceAttachments = new BodyPart[3]; 259e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler BodyPart attachmentPart; 260e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler 261e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler // 1. Standard attachment 262e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart = MessageTestUtils.bodyPart("image/jpg", null); 263e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg"); 264e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 265e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, 266e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler "attachment;\n filename=\"file-1\";\n size=100"); 267e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "100"); 268e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler sourceAttachments[0] = attachmentPart; 269e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler 270e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler // 2. Inline attachment 271e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart = MessageTestUtils.bodyPart("image/gif", null); 272e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/gif"); 273e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 274e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, 275e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler "inline;\n filename=\"file-2\";\n size=200"); 276e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "101"); 277e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler sourceAttachments[1] = attachmentPart; 278e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler 279e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler // 3. Neither (use VCALENDAR) 280e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart = MessageTestUtils.bodyPart("text/calendar", null); 281e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, 282e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler "text/calendar; charset=UTF-8; method=REQUEST"); 283e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "7bit"); 284e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "102"); 285e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler sourceAttachments[2] = attachmentPart; 286e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler 287e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler // Prepare local message (destination) and legacy message w/attachments (source) 288e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler final EmailContent.Message localMessage = ProviderTestUtils.setupMessage( 289e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler "local-message", accountId, mailboxId, false, true, mProviderContext); 290e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler final Message legacyMessage = prepareLegacyMessageWithAttachments(sourceAttachments); 291e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler convertAndCheckcheckAddedAttachments(localMessage, legacyMessage); 292e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler 293e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler // Run the conversion and check for the converted attachments - this test asserts 294e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler // that there are two attachments numbered 100 & 101 (so will fail if it finds 102) 295e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler convertAndCheckcheckAddedAttachments(localMessage, legacyMessage); 296e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler } 297e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler 298e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler /** 2995b0a12c199198870161876996296b1262c17408eAndrew Stadler * Test that attachments aren't re-added in the DB. This supports the "partial download" 3005b0a12c199198870161876996296b1262c17408eAndrew Stadler * nature of POP messages. 3015b0a12c199198870161876996296b1262c17408eAndrew Stadler */ 3025b0a12c199198870161876996296b1262c17408eAndrew Stadler public void testAddDuplicateAttachments() throws MessagingException, IOException { 3035b0a12c199198870161876996296b1262c17408eAndrew Stadler // Prepare a local message to add the attachments to 3045b0a12c199198870161876996296b1262c17408eAndrew Stadler final long accountId = 1; 3055b0a12c199198870161876996296b1262c17408eAndrew Stadler final long mailboxId = 1; 3065b0a12c199198870161876996296b1262c17408eAndrew Stadler final EmailContent.Message localMessage = ProviderTestUtils.setupMessage( 3075b0a12c199198870161876996296b1262c17408eAndrew Stadler "local-message", accountId, mailboxId, false, true, mProviderContext); 3085b0a12c199198870161876996296b1262c17408eAndrew Stadler 3095b0a12c199198870161876996296b1262c17408eAndrew Stadler // Prepare a legacy message with attachments 3107d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler Message legacyMessage = prepareLegacyMessageWithAttachments(2, false); 3115b0a12c199198870161876996296b1262c17408eAndrew Stadler 3125b0a12c199198870161876996296b1262c17408eAndrew Stadler // Now, convert from legacy to provider and see what happens 3135b0a12c199198870161876996296b1262c17408eAndrew Stadler ArrayList<Part> viewables = new ArrayList<Part>(); 3145b0a12c199198870161876996296b1262c17408eAndrew Stadler ArrayList<Part> attachments = new ArrayList<Part>(); 3155b0a12c199198870161876996296b1262c17408eAndrew Stadler MimeUtility.collectParts(legacyMessage, viewables, attachments); 3167d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments); 3175b0a12c199198870161876996296b1262c17408eAndrew Stadler 3185b0a12c199198870161876996296b1262c17408eAndrew Stadler // Confirm two attachment objects created 3195b0a12c199198870161876996296b1262c17408eAndrew Stadler Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId); 3205b0a12c199198870161876996296b1262c17408eAndrew Stadler assertEquals(2, EmailContent.count(mProviderContext, uri, null, null)); 3215b0a12c199198870161876996296b1262c17408eAndrew Stadler 3225b0a12c199198870161876996296b1262c17408eAndrew Stadler // Now add the attachments again and confirm there are still only two 3237d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments); 3245b0a12c199198870161876996296b1262c17408eAndrew Stadler assertEquals(2, EmailContent.count(mProviderContext, uri, null, null)); 3255b0a12c199198870161876996296b1262c17408eAndrew Stadler 3265b0a12c199198870161876996296b1262c17408eAndrew Stadler // Now add a 3rd & 4th attachment and make sure the total is 4, not 2 or 6 3277d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler legacyMessage = prepareLegacyMessageWithAttachments(4, false); 3285b0a12c199198870161876996296b1262c17408eAndrew Stadler viewables = new ArrayList<Part>(); 3295b0a12c199198870161876996296b1262c17408eAndrew Stadler attachments = new ArrayList<Part>(); 3305b0a12c199198870161876996296b1262c17408eAndrew Stadler MimeUtility.collectParts(legacyMessage, viewables, attachments); 3317d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler LegacyConversions.updateAttachments(mProviderContext, localMessage, attachments); 3325b0a12c199198870161876996296b1262c17408eAndrew Stadler assertEquals(4, EmailContent.count(mProviderContext, uri, null, null)); 3335b0a12c199198870161876996296b1262c17408eAndrew Stadler } 3345b0a12c199198870161876996296b1262c17408eAndrew Stadler 3355b0a12c199198870161876996296b1262c17408eAndrew Stadler /** 3365b0a12c199198870161876996296b1262c17408eAndrew Stadler * Prepare a legacy message with 1+ attachments 337fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler * @param numAttachments how many attachments to add 3387d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler * @param filenameInDisposition False: attachment names are sent as content-type:name. True: 3397d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler * attachment names are sent as content-disposition:filename. 3405b0a12c199198870161876996296b1262c17408eAndrew Stadler */ 3417d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler private Message prepareLegacyMessageWithAttachments(int numAttachments, 3427d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler boolean filenameInDisposition) throws MessagingException { 343e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler BodyPart[] attachmentParts = new BodyPart[numAttachments]; 344e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler for (int i = 0; i < numAttachments; ++i) { 3457d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler // construct parameter parts for content-type:name or content-disposition:filename. 3467d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler String name = ""; 3477d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler String filename = ""; 3487d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler String quotedName = "\"test-attachment-" + i + "\""; 3497d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler if (filenameInDisposition) { 3507d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler filename = ";\n filename=" + quotedName; 3517d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler } else { 3527d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler name = ";\n name=" + quotedName; 3537d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler } 354fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler 3557d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler // generate an attachment that came from a server 3567d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler BodyPart attachmentPart = MessageTestUtils.bodyPart("image/jpg", null); 357fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler 3587d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler // name=attachmentN size=N00 location=10N 3597d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "image/jpg" + name); 3607d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 3617d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, 3627d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler "attachment" + filename + ";\n size=" + (i+1) + "00"); 3637d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler attachmentPart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "10" + i); 3647d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler 3657d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler attachmentParts[i] = attachmentPart; 3665b0a12c199198870161876996296b1262c17408eAndrew Stadler } 3675b0a12c199198870161876996296b1262c17408eAndrew Stadler 368e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler return prepareLegacyMessageWithAttachments(attachmentParts); 369e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler } 370e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler 371e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler /** 372e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler * Prepare a legacy message with 1+ attachments 373e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler * @param attachments array containing one or more attachments 374e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler */ 375e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler private Message prepareLegacyMessageWithAttachments(BodyPart[] attachments) 376e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler throws MessagingException { 377e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler // Build the multipart that holds the attachments 378e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler MultipartBuilder mpBuilder = new MultipartBuilder("multipart/mixed"); 379e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler for (int i = 0; i < attachments.length; ++i) { 380e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler mpBuilder.addBodyPart(attachments[i]); 381e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler } 382e3a17f1438e454518a58fc0841bb615344acf865Andy Stadler 3835b0a12c199198870161876996296b1262c17408eAndrew Stadler // Now build a message with them 3845b0a12c199198870161876996296b1262c17408eAndrew Stadler final Message legacyMessage = new MessageBuilder() 3855b0a12c199198870161876996296b1262c17408eAndrew Stadler .setBody(new MultipartBuilder("multipart/mixed") 3865b0a12c199198870161876996296b1262c17408eAndrew Stadler .addBodyPart(MessageTestUtils.bodyPart("text/html", null)) 3875b0a12c199198870161876996296b1262c17408eAndrew Stadler .addBodyPart(mpBuilder.buildBodyPart()) 3885b0a12c199198870161876996296b1262c17408eAndrew Stadler .build()) 3895b0a12c199198870161876996296b1262c17408eAndrew Stadler .build(); 3905b0a12c199198870161876996296b1262c17408eAndrew Stadler 3915b0a12c199198870161876996296b1262c17408eAndrew Stadler return legacyMessage; 3925b0a12c199198870161876996296b1262c17408eAndrew Stadler } 3935b0a12c199198870161876996296b1262c17408eAndrew Stadler 3945b0a12c199198870161876996296b1262c17408eAndrew Stadler /** 3955b0a12c199198870161876996296b1262c17408eAndrew Stadler * Test the stringInequal helper 3965b0a12c199198870161876996296b1262c17408eAndrew Stadler */ 3975b0a12c199198870161876996296b1262c17408eAndrew Stadler public void testStringInequal() { 3985b0a12c199198870161876996296b1262c17408eAndrew Stadler // Pairs that are "equal" 3995b0a12c199198870161876996296b1262c17408eAndrew Stadler assertFalse(LegacyConversions.stringNotEqual(null, null)); 4005b0a12c199198870161876996296b1262c17408eAndrew Stadler assertFalse(LegacyConversions.stringNotEqual(null, "")); 4015b0a12c199198870161876996296b1262c17408eAndrew Stadler assertFalse(LegacyConversions.stringNotEqual("", null)); 4025b0a12c199198870161876996296b1262c17408eAndrew Stadler assertFalse(LegacyConversions.stringNotEqual("", "")); 4035b0a12c199198870161876996296b1262c17408eAndrew Stadler assertFalse(LegacyConversions.stringNotEqual("string-equal", "string-equal")); 4045b0a12c199198870161876996296b1262c17408eAndrew Stadler // Pairs that are "inequal" 4055b0a12c199198870161876996296b1262c17408eAndrew Stadler assertTrue(LegacyConversions.stringNotEqual(null, "string-inequal")); 4065b0a12c199198870161876996296b1262c17408eAndrew Stadler assertTrue(LegacyConversions.stringNotEqual("", "string-inequal")); 4075b0a12c199198870161876996296b1262c17408eAndrew Stadler assertTrue(LegacyConversions.stringNotEqual("string-inequal", null)); 4085b0a12c199198870161876996296b1262c17408eAndrew Stadler assertTrue(LegacyConversions.stringNotEqual("string-inequal", "")); 4095b0a12c199198870161876996296b1262c17408eAndrew Stadler assertTrue(LegacyConversions.stringNotEqual("string-inequal-a", "string-inequal-b")); 4105b0a12c199198870161876996296b1262c17408eAndrew Stadler } 4115b0a12c199198870161876996296b1262c17408eAndrew Stadler 4125b0a12c199198870161876996296b1262c17408eAndrew Stadler /** 4133f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * Compare attachment that was converted from Part (expected) to Provider Attachment (actual) 414515d830e8755d3674e04bcc60d7f85b4fa7fb202Jerry Xie * 4153f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * TODO content URI should only be set if we also saved a file 4163f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * TODO other data encodings 4173f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler */ 41875a873be8420e50f0aeb5a77716358ee0ca66b01Marc Blank private void checkAttachment(String tag, Part expected, EmailContent.Attachment actual, 41975a873be8420e50f0aeb5a77716358ee0ca66b01Marc Blank long accountKey) throws MessagingException { 4203f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler String contentType = MimeUtility.unfoldAndDecode(expected.getContentType()); 4217d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler String contentTypeName = MimeUtility.getHeaderParameter(contentType, "name"); 4223f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler assertEquals(tag, expected.getMimeType(), actual.mMimeType); 4233f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler String disposition = expected.getDisposition(); 4243f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler String sizeString = MimeUtility.getHeaderParameter(disposition, "size"); 4257d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler String dispositionFilename = MimeUtility.getHeaderParameter(disposition, "filename"); 426fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler long expectedSize = (sizeString != null) ? Long.parseLong(sizeString) : 0; 4273f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler assertEquals(tag, expectedSize, actual.mSize); 4283f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler assertEquals(tag, expected.getContentId(), actual.mContentId); 429fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler 4307d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler // filename is either content-type:name or content-disposition:filename 4317d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler String expectedName = (contentTypeName != null) ? contentTypeName : dispositionFilename; 4327d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler assertEquals(tag, expectedName, actual.mFileName); 4337d738cb7e89353c51c567e466a135b54337f310dAndrew Stadler 4347d51b7a05ba07377e3df0b07c2aaa430a8b5bc42Andy Stadler // content URI should be null 435515d830e8755d3674e04bcc60d7f85b4fa7fb202Jerry Xie assertNull(tag, actual.getContentUri()); 436fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler 4373f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler assertTrue(tag, 0 != actual.mMessageKey); 438fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler 439fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler // location is either both null or both matching 440fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler String expectedPartId = null; 441fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler String[] storeData = expected.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); 442fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler if (storeData != null && storeData.length > 0) { 443fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler expectedPartId = storeData[0]; 444fd249f61dd9c5fd1e7e0abffcb09b9e285d82baeAndrew Stadler } 4453f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler assertEquals(tag, expectedPartId, actual.mLocation); 4463f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler assertEquals(tag, "B", actual.mEncoding); 44775a873be8420e50f0aeb5a77716358ee0ca66b01Marc Blank assertEquals(tag, accountKey, actual.mAccountKey); 4483f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 4493f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 4503f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler /** 4513f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * TODO: Sunny day test of adding attachments from a POP message. 4523f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler */ 4533f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 454c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler /** 455c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler * Sunny day tests of converting an original message to a legacy message 456c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler */ 457c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler public void testMakeLegacyMessage() throws MessagingException { 458c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // Set up and store a message in the provider 459c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler long account1Id = 1; 460c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler long mailbox1Id = 1; 461c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler 462c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // Test message 1: No body 463c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler EmailContent.Message localMessage1 = ProviderTestUtils.setupMessage("make-legacy", 464c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler account1Id, mailbox1Id, false, true, mProviderContext); 465c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler Message getMessage1 = LegacyConversions.makeMessage(mProviderContext, localMessage1); 466c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler checkLegacyMessage("no body", localMessage1, getMessage1); 467c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler 468c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // Test message 2: Simple body 469c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler EmailContent.Message localMessage2 = ProviderTestUtils.setupMessage("make-legacy", 470c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler account1Id, mailbox1Id, true, false, mProviderContext); 471c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage2.mTextReply = null; 472c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage2.mHtmlReply = null; 473c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage2.mIntroText = null; 474c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage2.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 475c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage2.save(mProviderContext); 476c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler Message getMessage2 = LegacyConversions.makeMessage(mProviderContext, localMessage2); 477c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler checkLegacyMessage("simple body", localMessage2, getMessage2); 478c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler 479c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // Test message 3: Body + replied-to text 480c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler EmailContent.Message localMessage3 = ProviderTestUtils.setupMessage("make-legacy", 481c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler account1Id, mailbox1Id, true, false, mProviderContext); 482c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage3.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 483c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage3.mFlags |= EmailContent.Message.FLAG_TYPE_REPLY; 484c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage3.save(mProviderContext); 485c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler Message getMessage3 = LegacyConversions.makeMessage(mProviderContext, localMessage3); 486c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler checkLegacyMessage("reply-to", localMessage3, getMessage3); 487c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler 488c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // Test message 4: Body + forwarded text 489c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler EmailContent.Message localMessage4 = ProviderTestUtils.setupMessage("make-legacy", 490c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler account1Id, mailbox1Id, true, false, mProviderContext); 491c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage4.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 492c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage4.mFlags |= EmailContent.Message.FLAG_TYPE_FORWARD; 493c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler localMessage4.save(mProviderContext); 494c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler Message getMessage4 = LegacyConversions.makeMessage(mProviderContext, localMessage4); 495c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler checkLegacyMessage("forwarding", localMessage4, getMessage4); 496c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 497c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler 498c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler /** 499eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * Check equality of a pair of converted messages 500eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler */ 501eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler private void checkProviderMessage(String tag, Message expect, EmailContent.Message actual) 502eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler throws MessagingException { 503eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, expect.getUid(), actual.mServerId); 504eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, expect.getSubject(), actual.mSubject); 505eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, Address.pack(expect.getFrom()), actual.mFrom); 506eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, expect.getSentDate().getTime(), actual.mTimeStamp); 507eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, Address.pack(expect.getRecipients(RecipientType.TO)), actual.mTo); 508eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, Address.pack(expect.getRecipients(RecipientType.CC)), actual.mCc); 509eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, ((MimeMessage)expect).getMessageId(), actual.mMessageId); 510eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, expect.isSet(Flag.SEEN), actual.mFlagRead); 511eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, expect.isSet(Flag.FLAGGED), actual.mFlagFavorite); 512eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler } 513eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler 5145b0a12c199198870161876996296b1262c17408eAndrew Stadler /** 515eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler * Check equality of a pair of converted messages 516c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler */ 517c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler private void checkLegacyMessage(String tag, EmailContent.Message expect, Message actual) 518c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler throws MessagingException { 519c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mServerId, actual.getUid()); 520eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, expect.mServerTimeStamp, actual.getInternalDate().getTime()); 521c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mSubject, actual.getSubject()); 522c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mFrom, Address.pack(actual.getFrom())); 523c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mTimeStamp, actual.getSentDate().getTime()); 524c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mTo, Address.pack(actual.getRecipients(RecipientType.TO))); 525c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mCc, Address.pack(actual.getRecipients(RecipientType.CC))); 526eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, expect.mBcc, Address.pack(actual.getRecipients(RecipientType.BCC))); 527eb7752bf695b2a93854e0bb89ddbbc2236bb9aeaAndrew Stadler assertEquals(tag, expect.mReplyTo, Address.pack(actual.getReplyTo())); 528c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mMessageId, ((MimeMessage)actual).getMessageId()); 529c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // check flags 530c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mFlagRead, actual.isSet(Flag.SEEN)); 531c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mFlagFavorite, actual.isSet(Flag.FLAGGED)); 532c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler 533c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // Check the body of the message 534c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler ArrayList<Part> viewables = new ArrayList<Part>(); 535c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler ArrayList<Part> attachments = new ArrayList<Part>(); 536c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler MimeUtility.collectParts(actual, viewables, attachments); 537c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler String get1Text = null; 538c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler String get1Html = null; 539c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler String get1TextReply = null; 540c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler String get1HtmlReply = null; 541c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler String get1TextIntro = null; 542c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler for (Part viewable : viewables) { 543c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler String text = MimeUtility.getTextFromPart(viewable); 544c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler boolean isHtml = viewable.getMimeType().equalsIgnoreCase("text/html"); 545c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler String[] headers = viewable.getHeader(MimeHeader.HEADER_ANDROID_BODY_QUOTED_PART); 546c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler if (headers != null) { 547c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler String header = headers[0]; 548c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler boolean isReply = LegacyConversions.BODY_QUOTED_PART_REPLY.equalsIgnoreCase(header); 549c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler boolean isFwd = LegacyConversions.BODY_QUOTED_PART_FORWARD.equalsIgnoreCase(header); 550c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler boolean isIntro = LegacyConversions.BODY_QUOTED_PART_INTRO.equalsIgnoreCase(header); 551c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler if (isReply || isFwd) { 552c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler if (isHtml) { 553c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler get1HtmlReply = text; 554c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } else { 555c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler get1TextReply = text; 556c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 557c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } else if (isIntro) { 558c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler get1TextIntro = text; 559c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 560c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // Check flags 561c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler int replyTypeFlags = expect.mFlags & EmailContent.Message.FLAG_TYPE_MASK; 562c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler if (isReply) { 563c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, EmailContent.Message.FLAG_TYPE_REPLY, replyTypeFlags); 564c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 565c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler if (isFwd) { 566c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, EmailContent.Message.FLAG_TYPE_FORWARD, replyTypeFlags); 567c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 568c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } else { 569c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler if (isHtml) { 570c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler get1Html = text; 571c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } else { 572c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler get1Text = text; 573c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 574c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 575c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 576c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mText, get1Text); 577c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mHtml, get1Html); 578c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mTextReply, get1TextReply); 579c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mHtmlReply, get1HtmlReply); 580c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler assertEquals(tag, expect.mIntroText, get1TextIntro); 581c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler 582c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler // TODO Check the attachments 583c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler 584c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler// cv.put("attachment_count", attachments.size()); 585c41c47fa07a22f8a7612fb0191f152a36d95b7a5Andrew Stadler } 5863f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler} 587