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