LegacyConversions.java revision 75a873be8420e50f0aeb5a77716358ee0ca66b01
1b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project/* 2b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project 3b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 4b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * you may not use this file except in compliance with the License. 6b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * You may obtain a copy of the License at 7b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 8b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 10b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * See the License for the specific language governing permissions and 14b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * limitations under the License. 15b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 16b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 17b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectpackage com.android.email; 18b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 19101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport com.android.email.mail.Address; 20101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport com.android.email.mail.Body; 21101d528d59f447847d5c6b7578642132c2b76f4fOwen Linimport com.android.email.mail.Flag; 22b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.Folder; 23b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.Message; 24b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.MessagingException; 25b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.Part; 26b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.Message.RecipientType; 27b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.internet.MimeBodyPart; 28b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.internet.MimeHeader; 29b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.internet.MimeMessage; 30095afa19556bf550262e3cccb9edacc04e6f726aOwen Linimport com.android.email.mail.internet.MimeMultipart; 31b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.internet.MimeUtility; 32b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.internet.TextBody; 33b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.mail.store.LocalStore; 34b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.provider.AttachmentProvider; 35b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.provider.EmailContent; 36b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.provider.EmailContent.Attachment; 37b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.provider.EmailContent.AttachmentColumns; 38b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport com.android.email.provider.EmailContent.Mailbox; 39b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 40b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport org.apache.commons.io.IOUtils; 41b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 42b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.ContentUris; 43b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.ContentValues; 44b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.content.Context; 45b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.database.Cursor; 46b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.net.Uri; 47b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.provider.OpenableColumns; 48b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.text.TextUtils; 49b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport android.util.Log; 50b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 51b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport java.io.File; 52b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport java.io.FileOutputStream; 53059daa36dc6e83ca24a16d9b99925e71010bccebOwen Linimport java.io.IOException; 54b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport java.io.InputStream; 55b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport java.util.ArrayList; 56b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport java.util.Date; 57b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectimport java.util.HashMap; 58b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 59b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Projectpublic class LegacyConversions { 60d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang 61d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang /** DO NOT CHECK IN "TRUE" */ 62d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang private static final boolean DEBUG_ATTACHMENTS = false; 63d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang 64d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang /** Used for mapping folder names to type codes (e.g. inbox, drafts, trash) */ 65d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang private static final HashMap<String, Integer> 66d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang sServerMailboxNames = new HashMap<String, Integer>(); 6723c51b794e95c201290e36737f379c4bb8eefeaeRay Chen 6823c51b794e95c201290e36737f379c4bb8eefeaeRay Chen /** 6923c51b794e95c201290e36737f379c4bb8eefeaeRay Chen * Values for HEADER_ANDROID_BODY_QUOTED_PART to tag body parts 70b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 71d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang /* package */ static final String BODY_QUOTED_PART_REPLY = "quoted-reply"; 72d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang /* package */ static final String BODY_QUOTED_PART_FORWARD = "quoted-forward"; 73b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /* package */ static final String BODY_QUOTED_PART_INTRO = "quoted-intro"; 74b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 75b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /** 76b128446b7ef264c33e91e119391045156a19439bWu-cheng Li * Standard columns for querying content providers 77b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 78b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project private static final String[] ATTACHMENT_META_COLUMNS_PROJECTION = { 79b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project OpenableColumns.DISPLAY_NAME, 80b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project OpenableColumns.SIZE 81b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project }; 82b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project private static final int ATTACHMENT_META_COLUMNS_SIZE = 1; 83b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 84b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /** 85b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Copy field-by-field from a "store" message to a "provider" message 869a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project * @param message The message we've just downloaded (must be a MimeMessage) 879a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project * @param localMessage The message we'd like to write into the DB 889a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project * @result true if dirty (changes were made) 899a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project */ 90b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project public static boolean updateMessageFields(EmailContent.Message localMessage, Message message, 91b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project long accountId, long mailboxId) throws MessagingException { 92b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 93b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Address[] from = message.getFrom(); 94b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Address[] to = message.getRecipients(Message.RecipientType.TO); 95b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Address[] cc = message.getRecipients(Message.RecipientType.CC); 96b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Address[] bcc = message.getRecipients(Message.RecipientType.BCC); 97b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Address[] replyTo = message.getReplyTo(); 98b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String subject = message.getSubject(); 99b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Date sentDate = message.getSentDate(); 100b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Date internalDate = message.getInternalDate(); 101b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 102b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (from != null && from.length > 0) { 103b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mDisplayName = from[0].toFriendly(); 1049bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang } 1059bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang if (sentDate != null) { 1069bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang localMessage.mTimeStamp = sentDate.getTime(); 1070a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang } 108de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project if (subject != null) { 1099bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang localMessage.mSubject = subject; 110b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 1119a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project localMessage.mFlagRead = message.isSet(Flag.SEEN); 1129a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project 113b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Keep the message in the "unloaded" state until it has (at least) a display name. 114b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // This prevents early flickering of empty messages in POP download. 115b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (localMessage.mFlagLoaded != EmailContent.Message.FLAG_LOADED_COMPLETE) { 116b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (localMessage.mDisplayName == null || "".equals(localMessage.mDisplayName)) { 117b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mFlagLoaded = EmailContent.Message.FLAG_LOADED_UNLOADED; 118b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } else { 119b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mFlagLoaded = EmailContent.Message.FLAG_LOADED_PARTIAL; 120b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 121b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 122b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mFlagFavorite = message.isSet(Flag.FLAGGED); 123b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project// public boolean mFlagAttachment = false; 124b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project// public int mFlags = 0; 125b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 126b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mServerId = message.getUid(); 127845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang if (internalDate != null) { 128845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang localMessage.mServerTimeStamp = internalDate.getTime(); 129845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang } 13082ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang// public String mClientId; 13182ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang 13282ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang // Only replace the local message-id if a new one was found. This is seen in some ISP's 133b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // which may deliver messages w/o a message-id header. 134ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li String messageId = ((MimeMessage)message).getMessageId(); 135b128446b7ef264c33e91e119391045156a19439bWu-cheng Li if (messageId != null) { 136b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mMessageId = messageId; 137d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang } 138b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 139b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project// public long mBodyKey; 140b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mMailboxKey = mailboxId; 1418d0dd0e2ee9a9f8d729ed96597102777cf14701fThe Android Open Source Project localMessage.mAccountKey = accountId; 142b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 143b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (from != null && from.length > 0) { 144b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mFrom = Address.pack(from); 145b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 146b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 147059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin localMessage.mTo = Address.pack(to); 148b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mCc = Address.pack(cc); 149d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang localMessage.mBcc = Address.pack(bcc); 150d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang localMessage.mReplyTo = Address.pack(replyTo); 151b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 152b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project// public String mText; 153b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project// public String mHtml; 154b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project// public String mTextReply; 155b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project// public String mHtmlReply; 156b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 157b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project// // Can be used while building messages, but is NOT saved by the Provider 158b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project// transient public ArrayList<Attachment> mAttachments = null; 159b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 160b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return true; 161b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 162d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang 163b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /** 164b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Copy body text (plain and/or HTML) from MimeMessage to provider Message 165b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 166b128446b7ef264c33e91e119391045156a19439bWu-cheng Li public static boolean updateBodyFields(EmailContent.Body body, 167b128446b7ef264c33e91e119391045156a19439bWu-cheng Li EmailContent.Message localMessage, ArrayList<Part> viewables) 168ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li throws MessagingException { 169ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li 170ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li body.mMessageKey = localMessage.mId; 171b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 172b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project StringBuffer sbHtml = null; 1730a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang StringBuffer sbText = null; 174b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project StringBuffer sbHtmlReply = null; 175b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project StringBuffer sbTextReply = null; 176937fc48b37fafe3ffc8f4b52bd9a171bbb4d3a37Owen Lin StringBuffer sbIntroText = null; 177b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 178b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project for (Part viewable : viewables) { 179b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String text = MimeUtility.getTextFromPart(viewable); 180b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String[] replyTags = viewable.getHeader(MimeHeader.HEADER_ANDROID_BODY_QUOTED_PART); 181b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String replyTag = null; 182b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (replyTags != null && replyTags.length > 0) { 1839a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project replyTag = replyTags[0]; 184b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 185b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Deploy text as marked by the various tags 1869a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project boolean isHtml = "text/html".equalsIgnoreCase(viewable.getMimeType()); 187b128446b7ef264c33e91e119391045156a19439bWu-cheng Li 188b128446b7ef264c33e91e119391045156a19439bWu-cheng Li if (replyTag != null) { 189b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project boolean isQuotedReply = BODY_QUOTED_PART_REPLY.equalsIgnoreCase(replyTag); 190b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project boolean isQuotedForward = BODY_QUOTED_PART_FORWARD.equalsIgnoreCase(replyTag); 1919a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project boolean isQuotedIntro = BODY_QUOTED_PART_INTRO.equalsIgnoreCase(replyTag); 192b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 193d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang if (isQuotedReply || isQuotedForward) { 194d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang if (isHtml) { 195b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project sbHtmlReply = appendTextPart(sbHtmlReply, text); 1969a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project } else { 197b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project sbTextReply = appendTextPart(sbTextReply, text); 198b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 199b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Set message flags as well 200b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mFlags &= ~EmailContent.Message.FLAG_TYPE_MASK; 201d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang localMessage.mFlags |= isQuotedReply 202b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project ? EmailContent.Message.FLAG_TYPE_REPLY 203b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project : EmailContent.Message.FLAG_TYPE_FORWARD; 204b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project continue; 205b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 206b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (isQuotedIntro) { 207b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project sbIntroText = appendTextPart(sbIntroText, text); 208b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project continue; 209b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 210ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li } 211ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li 212ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li // Most of the time, just process regular body parts 213ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li if (isHtml) { 214ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li sbHtml = appendTextPart(sbHtml, text); 215ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li } else { 216ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li sbText = appendTextPart(sbText, text); 217ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li } 218ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li } 219ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li 220ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li // write the combined data to the body part 221ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li if (!TextUtils.isEmpty(sbText)) { 222ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li String text = sbText.toString(); 223b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project body.mTextContent = text; 224b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mSnippet = Snippet.fromPlainText(text); 225b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 226b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (!TextUtils.isEmpty(sbHtml)) { 227b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String text = sbHtml.toString(); 228b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project body.mHtmlContent = text; 229b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (localMessage.mSnippet == null) { 230b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localMessage.mSnippet = Snippet.fromHtmlText(text); 231b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 232b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 233b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (sbHtmlReply != null && sbHtmlReply.length() != 0) { 234b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project body.mHtmlReply = sbHtmlReply.toString(); 235b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 236b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (sbTextReply != null && sbTextReply.length() != 0) { 237b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project body.mTextReply = sbTextReply.toString(); 238b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 239b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (sbIntroText != null && sbIntroText.length() != 0) { 240b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project body.mIntroText = sbIntroText.toString(); 241b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 242b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return true; 243b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 244b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 245b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /** 246b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Helper function to append text to a StringBuffer, creating it if necessary. 247059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin * Optimization: The majority of the time we are *not* appending - we should have a path 248059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin * that deals with single strings. 249b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 250059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin private static StringBuffer appendTextPart(StringBuffer sb, String newText) { 251059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin if (newText == null) { 252b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return sb; 253b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 2549bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang else if (sb == null) { 2559bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang sb = new StringBuffer(newText); 256059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin } else { 2579bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang if (sb.length() > 0) { 258059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin sb.append('\n'); 259059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin } 2609bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang sb.append(newText); 261059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin } 262059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin return sb; 263059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin } 264059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin 2659bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang /** 266ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li * Copy attachments from MimeMessage to provider Message. 267ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li * 268ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li * @param context a context for file operations 269ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li * @param localMessage the attachments will be built against this message 270ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li * @param attachments the attachments to add 271ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li * @param upgrading if true, we are upgrading a local account - handle attachments differently 272ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li * @throws IOException 273b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 274b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project public static void updateAttachments(Context context, EmailContent.Message localMessage, 275e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project ArrayList<Part> attachments, boolean upgrading) throws MessagingException, IOException { 276e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project localMessage.mAttachments = null; 277e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project for (Part attachmentPart : attachments) { 278e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project addOneAttachment(context, localMessage, attachmentPart, upgrading); 279e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project } 280e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project } 281d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang 282d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang /** 283e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project * Add a single attachment part to the message 284d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang * 285d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang * This will skip adding attachments if they are already found in the attachments table. 286e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project * The heuristic for this will fail (false-positive) if two identical attachments are 287e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project * included in a single POP3 message. 288e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project * TODO: Fix that, by (elsewhere) simulating an mLocation value based on the attachments 289b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * position within the list of multipart/mixed elements. This would make every POP3 attachment 290b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * unique, and might also simplify the code (since we could just look at the positions, and 291059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin * ignore the filename, etc.) 292059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin * 293059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin * TODO: Take a closer look at encoding and deal with it if necessary. 294b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 295b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param context a context for file operations 2960a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang * @param localMessage the attachments will be built against this message 297b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param part a single attachment part from POP or IMAP 298b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param upgrading true if upgrading a local account - handle attachments differently 299b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @throws IOException 300b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 301b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project private static void addOneAttachment(Context context, EmailContent.Message localMessage, 302b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Part part, boolean upgrading) throws MessagingException, IOException { 303b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 304b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Attachment localAttachment = new Attachment(); 305b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 306b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Transfer fields from mime format to provider format 307b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String contentType = MimeUtility.unfoldAndDecode(part.getContentType()); 3087638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen String name = MimeUtility.getHeaderParameter(contentType, "name"); 3097638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen if (name == null) { 310b128446b7ef264c33e91e119391045156a19439bWu-cheng Li String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition()); 3117638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen name = MimeUtility.getHeaderParameter(contentDisposition, "filename"); 3127638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen } 3137638a541959f3f371b9998844a0bbef2df4aa3eeRay Chen 314b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Select the URI for the new attachments. For attachments downloaded by the legacy 315b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // IMAP/POP code, this is not determined yet, so is null (it will be rewritten below, 316b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // or later, when the actual attachment file is created.) 317b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // 318e3f4516c2154539cb5778ef061abf8a0ccf90a5eThe Android Open Source Project // When upgrading older local accounts, the URI represents a local asset (e.g. a photo) 319b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // so we need to preserve the URI. 320b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // TODO This works for outgoing messages, where the URI does not change. May need 321b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // additional logic to handle the case of rewriting URI for received attachments. 322b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Uri contentUri = null; 323b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String contentUriString = null; 324b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (upgrading) { 325b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Body body = part.getBody(); 326de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project if (body instanceof LocalStore.LocalAttachmentBody) { 327059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin LocalStore.LocalAttachmentBody localBody = (LocalStore.LocalAttachmentBody) body; 3289bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang contentUri = localBody.getContentUri(); 329de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project if (contentUri != null) { 330de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project contentUriString = contentUri.toString(); 331b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 332b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 333b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 334b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 335de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project // Find size, if available, via a number of techniques: 336de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project long size = 0; 337de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project if (upgrading) { 338de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project // If upgrading a legacy account, the size must be recaptured from the data source 339b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (contentUri != null) { 340059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin Cursor metadataCursor = context.getContentResolver().query(contentUri, 341de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project ATTACHMENT_META_COLUMNS_PROJECTION, null, null, null); 3429bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang if (metadataCursor != null) { 343de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project try { 344b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (metadataCursor.moveToFirst()) { 3459bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang size = metadataCursor.getInt(ATTACHMENT_META_COLUMNS_SIZE); 346b128446b7ef264c33e91e119391045156a19439bWu-cheng Li } 347b128446b7ef264c33e91e119391045156a19439bWu-cheng Li } finally { 3489bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang metadataCursor.close(); 3499bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang } 3509bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang } 351b128446b7ef264c33e91e119391045156a19439bWu-cheng Li } 3529bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang // TODO: a downloaded legacy attachment - see if the above code works 353b128446b7ef264c33e91e119391045156a19439bWu-cheng Li } else { 354b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Incoming attachment: Try to pull size from disposition (if not downloaded yet) 355b128446b7ef264c33e91e119391045156a19439bWu-cheng Li String disposition = part.getDisposition(); 356b128446b7ef264c33e91e119391045156a19439bWu-cheng Li if (disposition != null) { 357b128446b7ef264c33e91e119391045156a19439bWu-cheng Li String s = MimeUtility.getHeaderParameter(disposition, "size"); 358b128446b7ef264c33e91e119391045156a19439bWu-cheng Li if (s != null) { 359b128446b7ef264c33e91e119391045156a19439bWu-cheng Li size = Long.parseLong(s); 360de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project } 361b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 362b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 363b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 364b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Get partId for unloaded IMAP attachments (if any) 365b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // This is only provided (and used) when we have structure but not the actual attachment 366b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String[] partIds = part.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); 3670a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang String partId = partIds != null ? partIds[0] : null; 368b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 369b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localAttachment.mFileName = name; 370b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localAttachment.mMimeType = part.getMimeType(); 371b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localAttachment.mSize = size; // May be reset below if file handled 372b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localAttachment.mContentId = part.getContentId(); 373b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localAttachment.mContentUri = contentUriString; 374b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localAttachment.mMessageKey = localMessage.mId; 375b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localAttachment.mLocation = partId; 376b128446b7ef264c33e91e119391045156a19439bWu-cheng Li localAttachment.mEncoding = "B"; // TODO - convert other known encodings 377b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localAttachment.mAccountKey = localMessage.mAccountKey; 378b128446b7ef264c33e91e119391045156a19439bWu-cheng Li 379b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (DEBUG_ATTACHMENTS) { 380b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Log.d(Email.LOG_TAG, "Add attachment " + localAttachment); 381b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 382b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 3839a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project // To prevent duplication - do we already have a matching attachment? 3849a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project // The fields we'll check for equality are: 3859a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project // mFileName, mMimeType, mContentId, mMessageKey, mLocation 3869a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project // NOTE: This will false-positive if you attach the exact same file, twice, to a POP3 3879a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project // message. We can live with that - you'll get one of the copies. 3889a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId); 389b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Cursor cursor = context.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION, 3909a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project null, null, null); 3919a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project boolean attachmentFoundInDb = false; 392b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project try { 3939a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project while (cursor.moveToNext()) { 3949a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project Attachment dbAttachment = new Attachment().restore(cursor); 395b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // We test each of the fields here (instead of in SQL) because they may be 396b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // null, or may be strings. 397b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (stringNotEqual(dbAttachment.mFileName, localAttachment.mFileName)) continue; 398b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (stringNotEqual(dbAttachment.mMimeType, localAttachment.mMimeType)) continue; 399b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (stringNotEqual(dbAttachment.mContentId, localAttachment.mContentId)) continue; 400b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (stringNotEqual(dbAttachment.mLocation, localAttachment.mLocation)) continue; 401b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // We found a match, so use the existing attachment id, and stop looking/looping 402b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project attachmentFoundInDb = true; 403b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project localAttachment.mId = dbAttachment.mId; 404b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (DEBUG_ATTACHMENTS) { 405b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Log.d(Email.LOG_TAG, "Skipped, found db attachment " + dbAttachment); 406b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 407b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project break; 408b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 409b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } finally { 4109a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project cursor.close(); 4119a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project } 4129a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project 4139a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project // Save the attachment (so far) in order to obtain an id 4149a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project if (!attachmentFoundInDb) { 4159a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project localAttachment.save(context); 4169a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project } 4179a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project 4189a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project // If an attachment body was actually provided, we need to write the file now 419845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang if (!upgrading) { 420845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang saveAttachmentBody(context, part, localAttachment, localMessage.mAccountKey); 421845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang } 422845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang 423845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang if (localMessage.mAttachments == null) { 42482ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang localMessage.mAttachments = new ArrayList<Attachment>(); 42582ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang } 42682ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang localMessage.mAttachments.add(localAttachment); 42782ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang localMessage.mFlagAttachment = true; 42882ded2070a47fff16e1de1c78b516eb25888b91eChih-Chung Chang } 429845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang 430845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang /** 431845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang * Helper for addOneAttachment that compares two strings, deals with nulls, and treats 432845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang * nulls and empty strings as equal. 433845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang */ 434845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang /* package */ static boolean stringNotEqual(String a, String b) { 435845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang if (a == null && b == null) return false; // fast exit for two null strings 436845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang if (a == null) a = ""; 437845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang if (b == null) b = ""; 438845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang return !a.equals(b); 439845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang } 440845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang 441845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang /** 442845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang * Save the body part of a single attachment, to a file in the attachments directory. 443845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang */ 444845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang public static void saveAttachmentBody(Context context, Part part, Attachment localAttachment, 445845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang long accountId) throws MessagingException, IOException { 446845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang if (part.getBody() != null) { 447b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project long attachmentId = localAttachment.mId; 448b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 449b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project InputStream in = part.getBody().getInputStream(); 450845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang 451b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project File saveIn = AttachmentProvider.getAttachmentDirectory(context, accountId); 452b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (!saveIn.exists()) { 453845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang saveIn.mkdirs(); 454b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 455b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project File saveAs = AttachmentProvider.getAttachmentFilename(context, accountId, 456d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang attachmentId); 457d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang saveAs.createNewFile(); 458b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project FileOutputStream out = new FileOutputStream(saveAs); 459b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project long copySize = IOUtils.copy(in, out); 460b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project in.close(); 461b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project out.close(); 462b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 463b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // update the attachment with the extra information we now know 4649a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project String contentUriString = AttachmentProvider.getAttachmentUri( 4659a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project accountId, attachmentId).toString(); 4669a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project 4679a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project localAttachment.mSize = copySize; 4689a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project localAttachment.mContentUri = contentUriString; 4699a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project 4709a379bd668227d3dcea30312025f304fd248f6e3The Android Open Source Project // update the attachment in the database as well 471b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project ContentValues cv = new ContentValues(); 472b128446b7ef264c33e91e119391045156a19439bWu-cheng Li cv.put(AttachmentColumns.SIZE, copySize); 473b128446b7ef264c33e91e119391045156a19439bWu-cheng Li cv.put(AttachmentColumns.CONTENT_URI, contentUriString); 474b128446b7ef264c33e91e119391045156a19439bWu-cheng Li Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachmentId); 475b128446b7ef264c33e91e119391045156a19439bWu-cheng Li context.getContentResolver().update(uri, cv, null, null); 476b128446b7ef264c33e91e119391045156a19439bWu-cheng Li } 477b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 478b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 479845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang /** 480845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang * Read a complete Provider message into a legacy message (for IMAP upload). This 481845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang * is basically the equivalent of LocalFolder.getMessages() + LocalFolder.fetch(). 482845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang */ 483845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang public static Message makeMessage(Context context, EmailContent.Message localMessage) 484845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang throws MessagingException { 485845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang MimeMessage message = new MimeMessage(); 486845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang 487acdd1d7d819d17f9690d9bfddb7a9aec9dd2210dChih-Chung Chang // LocalFolder.getMessages() equivalent: Copy message fields 488acdd1d7d819d17f9690d9bfddb7a9aec9dd2210dChih-Chung Chang message.setSubject(localMessage.mSubject == null ? "" : localMessage.mSubject); 489059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin Address[] from = Address.unpack(localMessage.mFrom); 490059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin if (from.length > 0) { 491059daa36dc6e83ca24a16d9b99925e71010bccebOwen Lin message.setFrom(from[0]); 492845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang } 493ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li message.setSentDate(new Date(localMessage.mTimeStamp)); 494d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang message.setUid(localMessage.mServerId); 495d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang message.setFlag(Flag.DELETED, 496d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang localMessage.mFlagLoaded == EmailContent.Message.FLAG_LOADED_DELETED); 497d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang message.setFlag(Flag.SEEN, localMessage.mFlagRead); 498d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang message.setFlag(Flag.FLAGGED, localMessage.mFlagFavorite); 499d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang// message.setFlag(Flag.DRAFT, localMessage.mMailboxKey == draftMailboxKey); 500acdd1d7d819d17f9690d9bfddb7a9aec9dd2210dChih-Chung Chang message.setRecipients(RecipientType.TO, Address.unpack(localMessage.mTo)); 501845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang message.setRecipients(RecipientType.CC, Address.unpack(localMessage.mCc)); 502ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li message.setRecipients(RecipientType.BCC, Address.unpack(localMessage.mBcc)); 503ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li message.setReplyTo(Address.unpack(localMessage.mReplyTo)); 504ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li message.setInternalDate(new Date(localMessage.mServerTimeStamp)); 505ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li message.setMessageId(localMessage.mMessageId); 506ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li 507ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li // LocalFolder.fetch() equivalent: build body parts 508ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li message.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "multipart/mixed"); 509845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang MimeMultipart mp = new MimeMultipart(); 510845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang mp.setSubType("mixed"); 511845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang message.setBody(mp); 512845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang 513845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang try { 514845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang addTextBodyPart(mp, "text/html", null, 515845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang EmailContent.Body.restoreBodyHtmlWithMessageId(context, localMessage.mId)); 516acdd1d7d819d17f9690d9bfddb7a9aec9dd2210dChih-Chung Chang } catch (RuntimeException rte) { 517845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang Log.d(Email.LOG_TAG, "Exception while reading html body " + rte.toString()); 518ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li } 519845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang 520845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang try { 521ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li addTextBodyPart(mp, "text/plain", null, 522845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang EmailContent.Body.restoreBodyTextWithMessageId(context, localMessage.mId)); 523845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang } catch (RuntimeException rte) { 524845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang Log.d(Email.LOG_TAG, "Exception while reading text body " + rte.toString()); 525845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang } 526845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang 527845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang boolean isReply = (localMessage.mFlags & EmailContent.Message.FLAG_TYPE_REPLY) != 0; 528845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang boolean isForward = (localMessage.mFlags & EmailContent.Message.FLAG_TYPE_FORWARD) != 0; 529acdd1d7d819d17f9690d9bfddb7a9aec9dd2210dChih-Chung Chang 530845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang // If there is a quoted part (forwarding or reply), add the intro first, and then the 531845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang // rest of it. If it is opened in some other viewer, it will (hopefully) be displayed in 532acdd1d7d819d17f9690d9bfddb7a9aec9dd2210dChih-Chung Chang // the same order as we've just set up the blocks: composed text, intro, replied text 533845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang if (isReply || isForward) { 534845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang try { 535d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang addTextBodyPart(mp, "text/plain", BODY_QUOTED_PART_INTRO, 536d55a5e92d6065bd36a60925221d8cc9a773572ebChih-Chung Chang EmailContent.Body.restoreIntroTextWithMessageId(context, localMessage.mId)); 537845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang } catch (RuntimeException rte) { 538845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang Log.d(Email.LOG_TAG, "Exception while reading text reply " + rte.toString()); 539845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang } 540845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang 541fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li String replyTag = isReply ? BODY_QUOTED_PART_REPLY : BODY_QUOTED_PART_FORWARD; 542fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li try { 543845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang addTextBodyPart(mp, "text/html", replyTag, 544845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang EmailContent.Body.restoreReplyHtmlWithMessageId(context, localMessage.mId)); 545ac3a8c8ae81482867daa897d5d763e777430de9eWu-cheng Li } catch (RuntimeException rte) { 546845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang Log.d(Email.LOG_TAG, "Exception while reading html reply " + rte.toString()); 547845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang } 548b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 549b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project try { 550b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project addTextBodyPart(mp, "text/plain", replyTag, 551b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project EmailContent.Body.restoreReplyTextWithMessageId(context, localMessage.mId)); 552b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } catch (RuntimeException rte) { 553b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Log.d(Email.LOG_TAG, "Exception while reading text reply " + rte.toString()); 554b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 555b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 556b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 557b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Attachments 558fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li // TODO: Make sure we deal with these as structures and don't accidentally upload files 559fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li// Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId); 5609bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang// Cursor attachments = context.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION, 5619bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang// null, null, null); 5629bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang// try { 5639bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang// 5649bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang// } finally { 5659bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang// attachments.close(); 5669bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang// } 5679bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang 5689bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang return message; 5699bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang } 5709bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang 571fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li /** 572b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Helper method to add a body part for a given type of text, if found 5739c9be2eb4a86fc3468dbba1ec5f7bfdb37d22c74The Android Open Source Project * 574b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param mp The text body part will be added to this multipart 575b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param contentType The content-type of the text being added 5769bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang * @param quotedPartTag If non-null, HEADER_ANDROID_BODY_QUOTED_PART will be set to this value 5779bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang * @param partText The text to add. If null, nothing happens 5789bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang */ 579095afa19556bf550262e3cccb9edacc04e6f726aOwen Lin private static void addTextBodyPart(MimeMultipart mp, String contentType, String quotedPartTag, 580b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String partText) throws MessagingException { 581b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (partText == null) { 582b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return; 583b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 584845acccf672f6b5f64381859cf932132ceaca0e1Chih-Chung Chang TextBody body = new TextBody(partText); 585b128446b7ef264c33e91e119391045156a19439bWu-cheng Li MimeBodyPart bp = new MimeBodyPart(body, contentType); 586b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (quotedPartTag != null) { 587b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project bp.addHeader(MimeHeader.HEADER_ANDROID_BODY_QUOTED_PART, quotedPartTag); 588b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 589b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project mp.addBodyPart(bp); 590fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li } 591fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li 592fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li /** 593fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li * Conversion from provider account to legacy account 594fbdbae6005e1720f2108d9bb345196cb87b22572Wu-cheng Li * 595b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Used for backup/restore. 596b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 597b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param context application context 598b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param fromAccount the provider account to be backed up (including transient hostauth's) 599b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @return a legacy Account object ready to be committed to preferences 600de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project */ 601b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /* package */ static Account makeLegacyAccount(Context context, 602d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang EmailContent.Account fromAccount) { 603b128446b7ef264c33e91e119391045156a19439bWu-cheng Li Account result = new Account(context); 604b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 605b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setDescription(fromAccount.getDisplayName()); 606b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setEmail(fromAccount.getEmailAddress()); 607b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // fromAccount.mSyncKey - assume lost if restoring 608b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setSyncWindow(fromAccount.getSyncLookback()); 609de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project result.setAutomaticCheckIntervalMinutes(fromAccount.getSyncInterval()); 610b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // fromAccount.mHostAuthKeyRecv - id not saved; will be reassigned when restoring 611b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // fromAccount.mHostAuthKeySend - id not saved; will be reassigned when restoring 612de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project 613b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Provider Account flags, and how they are mapped. 614b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // FLAGS_NOTIFY_NEW_MAIL -> mNotifyNewMail 615de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project // FLAGS_VIBRATE_ALWAYS -> mVibrate 616de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project // FLAGS_VIBRATE_WHEN_SILENT -> mVibrateWhenSilent 617b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // DELETE_POLICY_NEVER -> mDeletePolicy 618b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // DELETE_POLICY_7DAYS 619b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // DELETE_POLICY_ON_DELETE 620b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setNotifyNewMail(0 != 621de365d87520c97d6b1636442e6b5c82a3e036f29The Android Open Source Project (fromAccount.getFlags() & EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL)); 622b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setVibrate(0 != 623b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project (fromAccount.getFlags() & EmailContent.Account.FLAGS_VIBRATE_ALWAYS)); 624b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setVibrateWhenSilent(0 != 625b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project (fromAccount.getFlags() & EmailContent.Account.FLAGS_VIBRATE_WHEN_SILENT)); 626b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setDeletePolicy(fromAccount.getDeletePolicy()); 627b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 628b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mUuid = fromAccount.getUuid(); 629b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setName(fromAccount.mSenderName); 630b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setRingtone(fromAccount.mRingtoneUri); 631b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mProtocolVersion = fromAccount.mProtocolVersion; 632b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // int fromAccount.mNewMessageCount = will be reset on next sync 633b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mSecurityFlags = fromAccount.mSecurityFlags; 634b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mSignature = fromAccount.mSignature; 635b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 636b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // Use the existing conversions from HostAuth <-> Uri 637b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setStoreUri(fromAccount.getStoreUri(context)); 638b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setSenderUri(fromAccount.getSenderUri(context)); 639b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 640b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return result; 641314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber } 642314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber 643314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber /** 644314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber * Conversion from legacy account to provider account 645314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber * 646314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber * Used for backup/restore and for account migration. 647314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber * 648314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber * @param context application context 649314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber * @param fromAccount the legacy account to convert to modern format 650314f9a79f1395af71f2c2bb629435bfda07a55aeAndreas Huber * @return an Account ready to be committed to provider 651b128446b7ef264c33e91e119391045156a19439bWu-cheng Li */ 652b128446b7ef264c33e91e119391045156a19439bWu-cheng Li public static EmailContent.Account makeAccount(Context context, Account fromAccount) { 653b128446b7ef264c33e91e119391045156a19439bWu-cheng Li 654b128446b7ef264c33e91e119391045156a19439bWu-cheng Li EmailContent.Account result = new EmailContent.Account(); 655b128446b7ef264c33e91e119391045156a19439bWu-cheng Li 656b128446b7ef264c33e91e119391045156a19439bWu-cheng Li result.setDisplayName(fromAccount.getDescription()); 657b128446b7ef264c33e91e119391045156a19439bWu-cheng Li result.setEmailAddress(fromAccount.getEmail()); 658b128446b7ef264c33e91e119391045156a19439bWu-cheng Li result.mSyncKey = null; 659b128446b7ef264c33e91e119391045156a19439bWu-cheng Li result.setSyncLookback(fromAccount.getSyncWindow()); 660b128446b7ef264c33e91e119391045156a19439bWu-cheng Li result.setSyncInterval(fromAccount.getAutomaticCheckIntervalMinutes()); 661b128446b7ef264c33e91e119391045156a19439bWu-cheng Li // result.mHostAuthKeyRecv; -- will be set when object is saved 662b128446b7ef264c33e91e119391045156a19439bWu-cheng Li // result.mHostAuthKeySend; -- will be set when object is saved 663b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project int flags = 0; 664b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (fromAccount.isNotifyNewMail()) flags |= EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL; 665b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (fromAccount.isVibrate()) flags |= EmailContent.Account.FLAGS_VIBRATE_ALWAYS; 666b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (fromAccount.isVibrateWhenSilent()) 667b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project flags |= EmailContent.Account.FLAGS_VIBRATE_WHEN_SILENT; 668b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setFlags(flags); 669b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setDeletePolicy(fromAccount.getDeletePolicy()); 670b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // result.setDefaultAccount(); -- will be set by caller, if neededf 671b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mCompatibilityUuid = fromAccount.getUuid(); 672b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setSenderName(fromAccount.getName()); 6730a475e11e2ceadbaa70308b52e06f4e6d9e56f12Chih-Chung Chang result.setRingtone(fromAccount.getRingtone()); 674b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mProtocolVersion = fromAccount.mProtocolVersion; 675b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mNewMessageCount = 0; 676b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mSecurityFlags = fromAccount.mSecurityFlags; 677b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mSecuritySyncKey = null; 678b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mSignature = fromAccount.mSignature; 679b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 680b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setStoreUri(context, fromAccount.getStoreUri()); 681b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.setSenderUri(context, fromAccount.getSenderUri()); 682b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 683b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return result; 684b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 685b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 686b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /** 687b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Conversion from legacy folder to provider mailbox. Used for account migration. 688b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Note: Many mailbox fields are unused in IMAP & POP accounts. 689b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * 690b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param context application context 691b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param toAccount the provider account that this folder will be associated with 692b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @param fromFolder the legacy folder to convert to modern format 693b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * @return an Account ready to be committed to provider 694b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 6959bc8d1b47e5bab978cc9571ddfdedc8309a0b65dChih-Chung Chang public static EmailContent.Mailbox makeMailbox(Context context, EmailContent.Account toAccount, 696b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Folder fromFolder) throws MessagingException { 697b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project EmailContent.Mailbox result = new EmailContent.Mailbox(); 698b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 699b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mDisplayName = fromFolder.getName(); 700d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang // result.mServerId 701d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang // result.mParentServerId 702095afa19556bf550262e3cccb9edacc04e6f726aOwen Lin result.mAccountKey = toAccount.mId; 703b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mType = inferMailboxTypeFromName(context, fromFolder.getName()); 704b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // result.mDelimiter 705095afa19556bf550262e3cccb9edacc04e6f726aOwen Lin // result.mSyncKey 706b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // result.mSyncLookback 707b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // result.mSyncInterval 70823c51b794e95c201290e36737f379c4bb8eefeaeRay Chen result.mSyncTime = 0; 709b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mFlagVisible = true; 710b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mFlags = 0; 711b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project result.mVisibleLimit = Email.VISIBLE_LIMIT_DEFAULT; 712b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project // result.mSyncStatus 713b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 714b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return result; 715b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 716b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project 717b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project /** 718b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * Infer mailbox type from mailbox name. Used by MessagingController (for live folder sync) 719b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project * and for legacy account upgrades. 720b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project */ 721d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang public static synchronized int inferMailboxTypeFromName(Context context, String mailboxName) { 722d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang if (sServerMailboxNames.size() == 0) { 723d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang // preload the hashmap, one time only 724d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang sServerMailboxNames.put( 725d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang context.getString(R.string.mailbox_name_server_inbox).toLowerCase(), 726d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang Mailbox.TYPE_INBOX); 727d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang sServerMailboxNames.put( 728d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang context.getString(R.string.mailbox_name_server_outbox).toLowerCase(), 729d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang Mailbox.TYPE_OUTBOX); 730d8209aa01ae56ea27f551f621b419251bf80b265Chih-Chung Chang sServerMailboxNames.put( 731b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project context.getString(R.string.mailbox_name_server_drafts).toLowerCase(), 732b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Mailbox.TYPE_DRAFTS); 733b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project sServerMailboxNames.put( 734b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project context.getString(R.string.mailbox_name_server_trash).toLowerCase(), 735b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Mailbox.TYPE_TRASH); 736b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project sServerMailboxNames.put( 737b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project context.getString(R.string.mailbox_name_server_sent).toLowerCase(), 738b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Mailbox.TYPE_SENT); 739b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project sServerMailboxNames.put( 740b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project context.getString(R.string.mailbox_name_server_junk).toLowerCase(), 741b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Mailbox.TYPE_JUNK); 742b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 743b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (mailboxName == null || mailboxName.length() == 0) { 744b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return EmailContent.Mailbox.TYPE_MAIL; 745b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 746b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project String lowerCaseName = mailboxName.toLowerCase(); 747b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project Integer type = sServerMailboxNames.get(lowerCaseName); 748b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project if (type != null) { 749b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return type; 750b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 751b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project return EmailContent.Mailbox.TYPE_MAIL; 752b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project } 753b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project} 754b64d345c9d51cabce43b5191532a0c185d2a70a5The Android Open Source Project