2009-08-11 22:02:57 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2009 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package com.android.email;
|
|
|
|
|
2011-06-24 21:40:03 +00:00
|
|
|
import android.content.ContentUris;
|
|
|
|
import android.content.ContentValues;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.net.Uri;
|
|
|
|
import android.util.Log;
|
|
|
|
|
2011-02-11 23:05:17 +00:00
|
|
|
import com.android.emailcommon.Logging;
|
2011-02-10 02:47:43 +00:00
|
|
|
import com.android.emailcommon.internet.MimeBodyPart;
|
|
|
|
import com.android.emailcommon.internet.MimeHeader;
|
|
|
|
import com.android.emailcommon.internet.MimeMessage;
|
|
|
|
import com.android.emailcommon.internet.MimeMultipart;
|
|
|
|
import com.android.emailcommon.internet.MimeUtility;
|
|
|
|
import com.android.emailcommon.internet.TextBody;
|
|
|
|
import com.android.emailcommon.mail.Address;
|
|
|
|
import com.android.emailcommon.mail.Flag;
|
|
|
|
import com.android.emailcommon.mail.Message;
|
2011-04-28 00:12:06 +00:00
|
|
|
import com.android.emailcommon.mail.Message.RecipientType;
|
2011-02-10 02:47:43 +00:00
|
|
|
import com.android.emailcommon.mail.MessagingException;
|
|
|
|
import com.android.emailcommon.mail.Part;
|
2011-02-10 18:26:56 +00:00
|
|
|
import com.android.emailcommon.provider.EmailContent;
|
|
|
|
import com.android.emailcommon.provider.EmailContent.Attachment;
|
|
|
|
import com.android.emailcommon.provider.EmailContent.AttachmentColumns;
|
2011-05-14 00:26:27 +00:00
|
|
|
import com.android.emailcommon.provider.Mailbox;
|
2011-02-09 01:50:30 +00:00
|
|
|
import com.android.emailcommon.utility.AttachmentUtilities;
|
2009-08-11 22:02:57 +00:00
|
|
|
|
|
|
|
import org.apache.commons.io.IOUtils;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Date;
|
2010-03-08 21:52:09 +00:00
|
|
|
import java.util.HashMap;
|
2009-08-11 22:02:57 +00:00
|
|
|
|
|
|
|
public class LegacyConversions {
|
|
|
|
|
2009-10-14 15:20:59 +00:00
|
|
|
/** DO NOT CHECK IN "TRUE" */
|
|
|
|
private static final boolean DEBUG_ATTACHMENTS = false;
|
|
|
|
|
2010-03-08 21:52:09 +00:00
|
|
|
/** Used for mapping folder names to type codes (e.g. inbox, drafts, trash) */
|
|
|
|
private static final HashMap<String, Integer>
|
|
|
|
sServerMailboxNames = new HashMap<String, Integer>();
|
|
|
|
|
2009-09-25 21:54:32 +00:00
|
|
|
/**
|
|
|
|
* Values for HEADER_ANDROID_BODY_QUOTED_PART to tag body parts
|
|
|
|
*/
|
|
|
|
/* package */ static final String BODY_QUOTED_PART_REPLY = "quoted-reply";
|
|
|
|
/* package */ static final String BODY_QUOTED_PART_FORWARD = "quoted-forward";
|
|
|
|
/* package */ static final String BODY_QUOTED_PART_INTRO = "quoted-intro";
|
|
|
|
|
2009-08-11 22:02:57 +00:00
|
|
|
/**
|
|
|
|
* Copy field-by-field from a "store" message to a "provider" message
|
2009-09-25 21:54:32 +00:00
|
|
|
* @param message The message we've just downloaded (must be a MimeMessage)
|
2009-08-11 22:02:57 +00:00
|
|
|
* @param localMessage The message we'd like to write into the DB
|
|
|
|
* @result true if dirty (changes were made)
|
|
|
|
*/
|
|
|
|
public static boolean updateMessageFields(EmailContent.Message localMessage, Message message,
|
|
|
|
long accountId, long mailboxId) throws MessagingException {
|
|
|
|
|
|
|
|
Address[] from = message.getFrom();
|
|
|
|
Address[] to = message.getRecipients(Message.RecipientType.TO);
|
|
|
|
Address[] cc = message.getRecipients(Message.RecipientType.CC);
|
|
|
|
Address[] bcc = message.getRecipients(Message.RecipientType.BCC);
|
|
|
|
Address[] replyTo = message.getReplyTo();
|
|
|
|
String subject = message.getSubject();
|
|
|
|
Date sentDate = message.getSentDate();
|
2009-09-23 01:31:10 +00:00
|
|
|
Date internalDate = message.getInternalDate();
|
2009-08-11 22:02:57 +00:00
|
|
|
|
|
|
|
if (from != null && from.length > 0) {
|
|
|
|
localMessage.mDisplayName = from[0].toFriendly();
|
|
|
|
}
|
|
|
|
if (sentDate != null) {
|
|
|
|
localMessage.mTimeStamp = sentDate.getTime();
|
|
|
|
}
|
|
|
|
if (subject != null) {
|
|
|
|
localMessage.mSubject = subject;
|
|
|
|
}
|
2009-08-26 05:45:11 +00:00
|
|
|
localMessage.mFlagRead = message.isSet(Flag.SEEN);
|
2011-06-24 21:40:03 +00:00
|
|
|
if (message.isSet(Flag.ANSWERED)) {
|
|
|
|
localMessage.mFlags |= EmailContent.Message.FLAG_REPLIED_TO;
|
|
|
|
}
|
2009-08-11 22:02:57 +00:00
|
|
|
|
|
|
|
// Keep the message in the "unloaded" state until it has (at least) a display name.
|
|
|
|
// This prevents early flickering of empty messages in POP download.
|
2009-09-10 18:52:36 +00:00
|
|
|
if (localMessage.mFlagLoaded != EmailContent.Message.FLAG_LOADED_COMPLETE) {
|
2009-08-11 22:02:57 +00:00
|
|
|
if (localMessage.mDisplayName == null || "".equals(localMessage.mDisplayName)) {
|
2009-09-10 18:52:36 +00:00
|
|
|
localMessage.mFlagLoaded = EmailContent.Message.FLAG_LOADED_UNLOADED;
|
2009-08-11 22:02:57 +00:00
|
|
|
} else {
|
2009-09-10 18:52:36 +00:00
|
|
|
localMessage.mFlagLoaded = EmailContent.Message.FLAG_LOADED_PARTIAL;
|
2009-08-11 22:02:57 +00:00
|
|
|
}
|
|
|
|
}
|
2009-08-26 05:45:11 +00:00
|
|
|
localMessage.mFlagFavorite = message.isSet(Flag.FLAGGED);
|
2009-08-11 22:02:57 +00:00
|
|
|
// public boolean mFlagAttachment = false;
|
|
|
|
// public int mFlags = 0;
|
2009-09-02 06:19:12 +00:00
|
|
|
|
2009-08-11 22:02:57 +00:00
|
|
|
localMessage.mServerId = message.getUid();
|
2009-09-23 01:31:10 +00:00
|
|
|
if (internalDate != null) {
|
|
|
|
localMessage.mServerTimeStamp = internalDate.getTime();
|
|
|
|
}
|
2009-08-11 22:02:57 +00:00
|
|
|
// public String mClientId;
|
2009-10-06 21:20:09 +00:00
|
|
|
|
Follow-up to MimeMessage efficiency improvements.
I missed a case where message-id should not be set locally, which is
the case where the Mime parser clears all headers *and* does not find
a message-id. The parsed MimeMessage should accurately reflect this.
In the old code, the local id was created at construction time and then
immediately discarded by the parser (calling headers.clear()).
In the new code, I was generating a message-id any time I couldn't find
one. Now, when explicitly cleared or removed, I set a boolean to inhibit
automatic generation of a new one.
I also missed the fact that a missing message-id no longer throws an
exception, it simply returns null, and so I changed the code that was
catching that exception to simply check for null.
(Note: Clearly, modeling of legacy behavior is becoming annoying here;
It would be better to do away with all of the automatic logic, and simply
generate message-id locally when appropriate: On locally-generated
messages. I don't want to touch this for the current release, but I left
a note in the code to this effect.)
Bug: 2504774
Change-Id: Ibfcbd2363c7ae39ee6d44e4c3295f88258cb4945
2010-03-11 00:42:49 +00:00
|
|
|
// Only replace the local message-id if a new one was found. This is seen in some ISP's
|
|
|
|
// which may deliver messages w/o a message-id header.
|
|
|
|
String messageId = ((MimeMessage)message).getMessageId();
|
|
|
|
if (messageId != null) {
|
|
|
|
localMessage.mMessageId = messageId;
|
2009-10-06 21:20:09 +00:00
|
|
|
}
|
2009-09-02 06:19:12 +00:00
|
|
|
|
2009-08-11 22:02:57 +00:00
|
|
|
// public long mBodyKey;
|
|
|
|
localMessage.mMailboxKey = mailboxId;
|
|
|
|
localMessage.mAccountKey = accountId;
|
2009-09-02 06:19:12 +00:00
|
|
|
|
2009-08-11 22:02:57 +00:00
|
|
|
if (from != null && from.length > 0) {
|
|
|
|
localMessage.mFrom = Address.pack(from);
|
|
|
|
}
|
|
|
|
|
|
|
|
localMessage.mTo = Address.pack(to);
|
|
|
|
localMessage.mCc = Address.pack(cc);
|
|
|
|
localMessage.mBcc = Address.pack(bcc);
|
|
|
|
localMessage.mReplyTo = Address.pack(replyTo);
|
|
|
|
|
|
|
|
// public String mText;
|
|
|
|
// public String mHtml;
|
2009-09-02 06:19:12 +00:00
|
|
|
// public String mTextReply;
|
|
|
|
// public String mHtmlReply;
|
|
|
|
|
2009-08-11 22:02:57 +00:00
|
|
|
// // Can be used while building messages, but is NOT saved by the Provider
|
|
|
|
// transient public ArrayList<Attachment> mAttachments = null;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copy attachments from MimeMessage to provider Message.
|
|
|
|
*
|
|
|
|
* @param context a context for file operations
|
|
|
|
* @param localMessage the attachments will be built against this message
|
2009-09-02 06:19:12 +00:00
|
|
|
* @param attachments the attachments to add
|
2009-08-11 22:02:57 +00:00
|
|
|
* @throws IOException
|
|
|
|
*/
|
|
|
|
public static void updateAttachments(Context context, EmailContent.Message localMessage,
|
2011-02-06 08:54:39 +00:00
|
|
|
ArrayList<Part> attachments) throws MessagingException, IOException {
|
2009-08-11 22:02:57 +00:00
|
|
|
localMessage.mAttachments = null;
|
|
|
|
for (Part attachmentPart : attachments) {
|
2011-02-06 08:54:39 +00:00
|
|
|
addOneAttachment(context, localMessage, attachmentPart);
|
2009-08-11 22:02:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a single attachment part to the message
|
|
|
|
*
|
2009-10-14 15:20:59 +00:00
|
|
|
* This will skip adding attachments if they are already found in the attachments table.
|
|
|
|
* The heuristic for this will fail (false-positive) if two identical attachments are
|
|
|
|
* included in a single POP3 message.
|
|
|
|
* TODO: Fix that, by (elsewhere) simulating an mLocation value based on the attachments
|
|
|
|
* position within the list of multipart/mixed elements. This would make every POP3 attachment
|
|
|
|
* unique, and might also simplify the code (since we could just look at the positions, and
|
|
|
|
* ignore the filename, etc.)
|
|
|
|
*
|
2009-08-11 22:02:57 +00:00
|
|
|
* TODO: Take a closer look at encoding and deal with it if necessary.
|
|
|
|
*
|
|
|
|
* @param context a context for file operations
|
|
|
|
* @param localMessage the attachments will be built against this message
|
|
|
|
* @param part a single attachment part from POP or IMAP
|
|
|
|
* @throws IOException
|
|
|
|
*/
|
|
|
|
private static void addOneAttachment(Context context, EmailContent.Message localMessage,
|
2011-02-06 08:54:39 +00:00
|
|
|
Part part) throws MessagingException, IOException {
|
2009-08-11 22:02:57 +00:00
|
|
|
|
|
|
|
Attachment localAttachment = new Attachment();
|
|
|
|
|
|
|
|
// Transfer fields from mime format to provider format
|
|
|
|
String contentType = MimeUtility.unfoldAndDecode(part.getContentType());
|
|
|
|
String name = MimeUtility.getHeaderParameter(contentType, "name");
|
|
|
|
if (name == null) {
|
2010-03-18 00:59:09 +00:00
|
|
|
String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition());
|
2009-08-11 22:02:57 +00:00
|
|
|
name = MimeUtility.getHeaderParameter(contentDisposition, "filename");
|
|
|
|
}
|
|
|
|
|
2011-02-06 08:54:39 +00:00
|
|
|
// Incoming attachment: Try to pull size from disposition (if not downloaded yet)
|
2009-08-11 22:02:57 +00:00
|
|
|
long size = 0;
|
2011-02-06 08:54:39 +00:00
|
|
|
String disposition = part.getDisposition();
|
|
|
|
if (disposition != null) {
|
|
|
|
String s = MimeUtility.getHeaderParameter(disposition, "size");
|
|
|
|
if (s != null) {
|
|
|
|
size = Long.parseLong(s);
|
2009-08-11 22:02:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get partId for unloaded IMAP attachments (if any)
|
|
|
|
// This is only provided (and used) when we have structure but not the actual attachment
|
|
|
|
String[] partIds = part.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA);
|
2009-09-02 06:19:12 +00:00
|
|
|
String partId = partIds != null ? partIds[0] : null;
|
2009-08-11 22:02:57 +00:00
|
|
|
|
2010-03-18 00:59:09 +00:00
|
|
|
localAttachment.mFileName = name;
|
2009-08-11 22:02:57 +00:00
|
|
|
localAttachment.mMimeType = part.getMimeType();
|
|
|
|
localAttachment.mSize = size; // May be reset below if file handled
|
|
|
|
localAttachment.mContentId = part.getContentId();
|
2011-02-06 08:54:39 +00:00
|
|
|
localAttachment.mContentUri = null; // Will be rewritten by saveAttachmentBody
|
2009-08-11 22:02:57 +00:00
|
|
|
localAttachment.mMessageKey = localMessage.mId;
|
|
|
|
localAttachment.mLocation = partId;
|
|
|
|
localAttachment.mEncoding = "B"; // TODO - convert other known encodings
|
2010-12-09 01:11:04 +00:00
|
|
|
localAttachment.mAccountKey = localMessage.mAccountKey;
|
2009-08-11 22:02:57 +00:00
|
|
|
|
2009-10-14 15:20:59 +00:00
|
|
|
if (DEBUG_ATTACHMENTS) {
|
2011-02-11 23:05:17 +00:00
|
|
|
Log.d(Logging.LOG_TAG, "Add attachment " + localAttachment);
|
2009-10-14 15:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// To prevent duplication - do we already have a matching attachment?
|
|
|
|
// The fields we'll check for equality are:
|
|
|
|
// mFileName, mMimeType, mContentId, mMessageKey, mLocation
|
|
|
|
// NOTE: This will false-positive if you attach the exact same file, twice, to a POP3
|
|
|
|
// message. We can live with that - you'll get one of the copies.
|
|
|
|
Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
|
|
|
|
Cursor cursor = context.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
|
|
|
|
null, null, null);
|
|
|
|
boolean attachmentFoundInDb = false;
|
|
|
|
try {
|
|
|
|
while (cursor.moveToNext()) {
|
2011-02-02 21:23:06 +00:00
|
|
|
Attachment dbAttachment = new Attachment();
|
|
|
|
dbAttachment.restore(cursor);
|
2009-10-14 15:20:59 +00:00
|
|
|
// We test each of the fields here (instead of in SQL) because they may be
|
|
|
|
// null, or may be strings.
|
|
|
|
if (stringNotEqual(dbAttachment.mFileName, localAttachment.mFileName)) continue;
|
|
|
|
if (stringNotEqual(dbAttachment.mMimeType, localAttachment.mMimeType)) continue;
|
|
|
|
if (stringNotEqual(dbAttachment.mContentId, localAttachment.mContentId)) continue;
|
|
|
|
if (stringNotEqual(dbAttachment.mLocation, localAttachment.mLocation)) continue;
|
|
|
|
// We found a match, so use the existing attachment id, and stop looking/looping
|
|
|
|
attachmentFoundInDb = true;
|
|
|
|
localAttachment.mId = dbAttachment.mId;
|
|
|
|
if (DEBUG_ATTACHMENTS) {
|
2011-02-11 23:05:17 +00:00
|
|
|
Log.d(Logging.LOG_TAG, "Skipped, found db attachment " + dbAttachment);
|
2009-10-14 15:20:59 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
|
2009-08-11 22:02:57 +00:00
|
|
|
// Save the attachment (so far) in order to obtain an id
|
2009-10-14 15:20:59 +00:00
|
|
|
if (!attachmentFoundInDb) {
|
|
|
|
localAttachment.save(context);
|
|
|
|
}
|
2009-08-11 22:02:57 +00:00
|
|
|
|
|
|
|
// If an attachment body was actually provided, we need to write the file now
|
2011-02-06 08:54:39 +00:00
|
|
|
saveAttachmentBody(context, part, localAttachment, localMessage.mAccountKey);
|
2009-08-19 20:15:13 +00:00
|
|
|
|
|
|
|
if (localMessage.mAttachments == null) {
|
|
|
|
localMessage.mAttachments = new ArrayList<Attachment>();
|
|
|
|
}
|
|
|
|
localMessage.mAttachments.add(localAttachment);
|
|
|
|
localMessage.mFlagAttachment = true;
|
|
|
|
}
|
|
|
|
|
2009-10-14 15:20:59 +00:00
|
|
|
/**
|
|
|
|
* Helper for addOneAttachment that compares two strings, deals with nulls, and treats
|
|
|
|
* nulls and empty strings as equal.
|
|
|
|
*/
|
|
|
|
/* package */ static boolean stringNotEqual(String a, String b) {
|
|
|
|
if (a == null && b == null) return false; // fast exit for two null strings
|
|
|
|
if (a == null) a = "";
|
|
|
|
if (b == null) b = "";
|
|
|
|
return !a.equals(b);
|
|
|
|
}
|
|
|
|
|
2009-08-19 20:15:13 +00:00
|
|
|
/**
|
|
|
|
* Save the body part of a single attachment, to a file in the attachments directory.
|
|
|
|
*/
|
|
|
|
public static void saveAttachmentBody(Context context, Part part, Attachment localAttachment,
|
|
|
|
long accountId) throws MessagingException, IOException {
|
2009-08-11 22:02:57 +00:00
|
|
|
if (part.getBody() != null) {
|
|
|
|
long attachmentId = localAttachment.mId;
|
|
|
|
|
|
|
|
InputStream in = part.getBody().getInputStream();
|
|
|
|
|
2011-02-09 01:50:30 +00:00
|
|
|
File saveIn = AttachmentUtilities.getAttachmentDirectory(context, accountId);
|
2009-08-11 22:02:57 +00:00
|
|
|
if (!saveIn.exists()) {
|
|
|
|
saveIn.mkdirs();
|
|
|
|
}
|
2011-02-09 01:50:30 +00:00
|
|
|
File saveAs = AttachmentUtilities.getAttachmentFilename(context, accountId,
|
2009-08-11 22:02:57 +00:00
|
|
|
attachmentId);
|
|
|
|
saveAs.createNewFile();
|
|
|
|
FileOutputStream out = new FileOutputStream(saveAs);
|
|
|
|
long copySize = IOUtils.copy(in, out);
|
|
|
|
in.close();
|
|
|
|
out.close();
|
|
|
|
|
|
|
|
// update the attachment with the extra information we now know
|
2011-02-09 01:50:30 +00:00
|
|
|
String contentUriString = AttachmentUtilities.getAttachmentUri(
|
2009-08-11 22:02:57 +00:00
|
|
|
accountId, attachmentId).toString();
|
|
|
|
|
|
|
|
localAttachment.mSize = copySize;
|
|
|
|
localAttachment.mContentUri = contentUriString;
|
|
|
|
|
|
|
|
// update the attachment in the database as well
|
|
|
|
ContentValues cv = new ContentValues();
|
|
|
|
cv.put(AttachmentColumns.SIZE, copySize);
|
|
|
|
cv.put(AttachmentColumns.CONTENT_URI, contentUriString);
|
|
|
|
Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachmentId);
|
|
|
|
context.getContentResolver().update(uri, cv, null, null);
|
|
|
|
}
|
|
|
|
}
|
2009-08-19 20:15:13 +00:00
|
|
|
|
2009-09-25 21:54:32 +00:00
|
|
|
/**
|
|
|
|
* Read a complete Provider message into a legacy message (for IMAP upload). This
|
|
|
|
* is basically the equivalent of LocalFolder.getMessages() + LocalFolder.fetch().
|
|
|
|
*/
|
|
|
|
public static Message makeMessage(Context context, EmailContent.Message localMessage)
|
|
|
|
throws MessagingException {
|
|
|
|
MimeMessage message = new MimeMessage();
|
|
|
|
|
|
|
|
// LocalFolder.getMessages() equivalent: Copy message fields
|
|
|
|
message.setSubject(localMessage.mSubject == null ? "" : localMessage.mSubject);
|
|
|
|
Address[] from = Address.unpack(localMessage.mFrom);
|
|
|
|
if (from.length > 0) {
|
|
|
|
message.setFrom(from[0]);
|
|
|
|
}
|
|
|
|
message.setSentDate(new Date(localMessage.mTimeStamp));
|
|
|
|
message.setUid(localMessage.mServerId);
|
|
|
|
message.setFlag(Flag.DELETED,
|
|
|
|
localMessage.mFlagLoaded == EmailContent.Message.FLAG_LOADED_DELETED);
|
|
|
|
message.setFlag(Flag.SEEN, localMessage.mFlagRead);
|
|
|
|
message.setFlag(Flag.FLAGGED, localMessage.mFlagFavorite);
|
|
|
|
// message.setFlag(Flag.DRAFT, localMessage.mMailboxKey == draftMailboxKey);
|
|
|
|
message.setRecipients(RecipientType.TO, Address.unpack(localMessage.mTo));
|
|
|
|
message.setRecipients(RecipientType.CC, Address.unpack(localMessage.mCc));
|
|
|
|
message.setRecipients(RecipientType.BCC, Address.unpack(localMessage.mBcc));
|
|
|
|
message.setReplyTo(Address.unpack(localMessage.mReplyTo));
|
|
|
|
message.setInternalDate(new Date(localMessage.mServerTimeStamp));
|
|
|
|
message.setMessageId(localMessage.mMessageId);
|
|
|
|
|
|
|
|
// LocalFolder.fetch() equivalent: build body parts
|
|
|
|
message.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "multipart/mixed");
|
|
|
|
MimeMultipart mp = new MimeMultipart();
|
|
|
|
mp.setSubType("mixed");
|
|
|
|
message.setBody(mp);
|
|
|
|
|
|
|
|
try {
|
|
|
|
addTextBodyPart(mp, "text/html", null,
|
|
|
|
EmailContent.Body.restoreBodyHtmlWithMessageId(context, localMessage.mId));
|
|
|
|
} catch (RuntimeException rte) {
|
2011-02-11 23:05:17 +00:00
|
|
|
Log.d(Logging.LOG_TAG, "Exception while reading html body " + rte.toString());
|
2009-09-25 21:54:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
addTextBodyPart(mp, "text/plain", null,
|
|
|
|
EmailContent.Body.restoreBodyTextWithMessageId(context, localMessage.mId));
|
|
|
|
} catch (RuntimeException rte) {
|
2011-02-11 23:05:17 +00:00
|
|
|
Log.d(Logging.LOG_TAG, "Exception while reading text body " + rte.toString());
|
2009-09-25 21:54:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
boolean isReply = (localMessage.mFlags & EmailContent.Message.FLAG_TYPE_REPLY) != 0;
|
|
|
|
boolean isForward = (localMessage.mFlags & EmailContent.Message.FLAG_TYPE_FORWARD) != 0;
|
|
|
|
|
|
|
|
// If there is a quoted part (forwarding or reply), add the intro first, and then the
|
|
|
|
// rest of it. If it is opened in some other viewer, it will (hopefully) be displayed in
|
|
|
|
// the same order as we've just set up the blocks: composed text, intro, replied text
|
|
|
|
if (isReply || isForward) {
|
|
|
|
try {
|
|
|
|
addTextBodyPart(mp, "text/plain", BODY_QUOTED_PART_INTRO,
|
|
|
|
EmailContent.Body.restoreIntroTextWithMessageId(context, localMessage.mId));
|
|
|
|
} catch (RuntimeException rte) {
|
2011-02-11 23:05:17 +00:00
|
|
|
Log.d(Logging.LOG_TAG, "Exception while reading text reply " + rte.toString());
|
2009-09-25 21:54:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String replyTag = isReply ? BODY_QUOTED_PART_REPLY : BODY_QUOTED_PART_FORWARD;
|
|
|
|
try {
|
|
|
|
addTextBodyPart(mp, "text/html", replyTag,
|
|
|
|
EmailContent.Body.restoreReplyHtmlWithMessageId(context, localMessage.mId));
|
|
|
|
} catch (RuntimeException rte) {
|
2011-02-11 23:05:17 +00:00
|
|
|
Log.d(Logging.LOG_TAG, "Exception while reading html reply " + rte.toString());
|
2009-09-25 21:54:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
addTextBodyPart(mp, "text/plain", replyTag,
|
|
|
|
EmailContent.Body.restoreReplyTextWithMessageId(context, localMessage.mId));
|
|
|
|
} catch (RuntimeException rte) {
|
2011-02-11 23:05:17 +00:00
|
|
|
Log.d(Logging.LOG_TAG, "Exception while reading text reply " + rte.toString());
|
2009-09-25 21:54:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attachments
|
|
|
|
// TODO: Make sure we deal with these as structures and don't accidentally upload files
|
|
|
|
// Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
|
|
|
|
// Cursor attachments = context.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
|
|
|
|
// null, null, null);
|
|
|
|
// try {
|
|
|
|
//
|
|
|
|
// } finally {
|
|
|
|
// attachments.close();
|
|
|
|
// }
|
|
|
|
|
|
|
|
return message;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to add a body part for a given type of text, if found
|
|
|
|
*
|
|
|
|
* @param mp The text body part will be added to this multipart
|
|
|
|
* @param contentType The content-type of the text being added
|
|
|
|
* @param quotedPartTag If non-null, HEADER_ANDROID_BODY_QUOTED_PART will be set to this value
|
|
|
|
* @param partText The text to add. If null, nothing happens
|
|
|
|
*/
|
|
|
|
private static void addTextBodyPart(MimeMultipart mp, String contentType, String quotedPartTag,
|
|
|
|
String partText) throws MessagingException {
|
|
|
|
if (partText == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TextBody body = new TextBody(partText);
|
|
|
|
MimeBodyPart bp = new MimeBodyPart(body, contentType);
|
|
|
|
if (quotedPartTag != null) {
|
|
|
|
bp.addHeader(MimeHeader.HEADER_ANDROID_BODY_QUOTED_PART, quotedPartTag);
|
|
|
|
}
|
|
|
|
mp.addBodyPart(bp);
|
|
|
|
}
|
2010-01-20 09:36:01 +00:00
|
|
|
|
2010-03-08 21:52:09 +00:00
|
|
|
|
|
|
|
/**
|
2011-02-06 08:54:39 +00:00
|
|
|
* Infer mailbox type from mailbox name. Used by MessagingController (for live folder sync).
|
2010-03-08 21:52:09 +00:00
|
|
|
*/
|
|
|
|
public static synchronized int inferMailboxTypeFromName(Context context, String mailboxName) {
|
|
|
|
if (sServerMailboxNames.size() == 0) {
|
|
|
|
// preload the hashmap, one time only
|
|
|
|
sServerMailboxNames.put(
|
|
|
|
context.getString(R.string.mailbox_name_server_inbox).toLowerCase(),
|
|
|
|
Mailbox.TYPE_INBOX);
|
|
|
|
sServerMailboxNames.put(
|
|
|
|
context.getString(R.string.mailbox_name_server_outbox).toLowerCase(),
|
|
|
|
Mailbox.TYPE_OUTBOX);
|
|
|
|
sServerMailboxNames.put(
|
|
|
|
context.getString(R.string.mailbox_name_server_drafts).toLowerCase(),
|
|
|
|
Mailbox.TYPE_DRAFTS);
|
|
|
|
sServerMailboxNames.put(
|
|
|
|
context.getString(R.string.mailbox_name_server_trash).toLowerCase(),
|
|
|
|
Mailbox.TYPE_TRASH);
|
|
|
|
sServerMailboxNames.put(
|
|
|
|
context.getString(R.string.mailbox_name_server_sent).toLowerCase(),
|
|
|
|
Mailbox.TYPE_SENT);
|
|
|
|
sServerMailboxNames.put(
|
|
|
|
context.getString(R.string.mailbox_name_server_junk).toLowerCase(),
|
|
|
|
Mailbox.TYPE_JUNK);
|
|
|
|
}
|
|
|
|
if (mailboxName == null || mailboxName.length() == 0) {
|
2011-05-14 00:26:27 +00:00
|
|
|
return Mailbox.TYPE_MAIL;
|
2010-03-08 21:52:09 +00:00
|
|
|
}
|
|
|
|
String lowerCaseName = mailboxName.toLowerCase();
|
|
|
|
Integer type = sServerMailboxNames.get(lowerCaseName);
|
|
|
|
if (type != null) {
|
|
|
|
return type;
|
|
|
|
}
|
2011-05-14 00:26:27 +00:00
|
|
|
return Mailbox.TYPE_MAIL;
|
2010-03-08 21:52:09 +00:00
|
|
|
}
|
2009-08-11 22:02:57 +00:00
|
|
|
}
|