LegacyConversions.java revision 0d1078363581db8caded06cf94e729e88a88761a
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.email; 18 19import com.android.email.mail.Address; 20import com.android.email.mail.Message; 21import com.android.email.mail.MessagingException; 22import com.android.email.mail.Part; 23import com.android.email.mail.internet.MimeHeader; 24import com.android.email.mail.internet.MimeUtility; 25import com.android.email.provider.AttachmentProvider; 26import com.android.email.provider.EmailContent; 27import com.android.email.provider.EmailContent.Attachment; 28import com.android.email.provider.EmailContent.AttachmentColumns; 29 30import org.apache.commons.io.IOUtils; 31 32import android.content.ContentUris; 33import android.content.ContentValues; 34import android.content.Context; 35import android.net.Uri; 36 37import java.io.File; 38import java.io.FileOutputStream; 39import java.io.IOException; 40import java.io.InputStream; 41import java.util.ArrayList; 42import java.util.Date; 43 44public class LegacyConversions { 45 46 /** 47 * Copy field-by-field from a "store" message to a "provider" message 48 * @param message The message we've just downloaded 49 * @param localMessage The message we'd like to write into the DB 50 * @result true if dirty (changes were made) 51 */ 52 public static boolean updateMessageFields(EmailContent.Message localMessage, Message message, 53 long accountId, long mailboxId) throws MessagingException { 54 55 Address[] from = message.getFrom(); 56 Address[] to = message.getRecipients(Message.RecipientType.TO); 57 Address[] cc = message.getRecipients(Message.RecipientType.CC); 58 Address[] bcc = message.getRecipients(Message.RecipientType.BCC); 59 Address[] replyTo = message.getReplyTo(); 60 String subject = message.getSubject(); 61 Date sentDate = message.getSentDate(); 62 63 if (from != null && from.length > 0) { 64 localMessage.mDisplayName = from[0].toFriendly(); 65 } 66 if (sentDate != null) { 67 localMessage.mTimeStamp = sentDate.getTime(); 68 } 69 if (subject != null) { 70 localMessage.mSubject = subject; 71 } 72// public String mPreview; 73// public boolean mFlagRead = false; 74 75 // Keep the message in the "unloaded" state until it has (at least) a display name. 76 // This prevents early flickering of empty messages in POP download. 77 if (localMessage.mFlagLoaded != EmailContent.Message.LOADED) { 78 if (localMessage.mDisplayName == null || "".equals(localMessage.mDisplayName)) { 79 localMessage.mFlagLoaded = EmailContent.Message.NOT_LOADED; 80 } else { 81 localMessage.mFlagLoaded = EmailContent.Message.PARTIALLY_LOADED; 82 } 83 } 84 // TODO handle flags, favorites, and read/unread 85// public boolean mFlagFavorite = false; 86// public boolean mFlagAttachment = false; 87// public int mFlags = 0; 88// 89// public String mTextInfo; 90// public String mHtmlInfo; 91// 92 localMessage.mServerId = message.getUid(); 93// public int mServerIntId; 94// public String mClientId; 95// public String mMessageId; 96// public String mThreadId; 97// 98// public long mBodyKey; 99 localMessage.mMailboxKey = mailboxId; 100 localMessage.mAccountKey = accountId; 101// public long mReferenceKey; 102// 103// public String mSender; 104 if (from != null && from.length > 0) { 105 localMessage.mFrom = Address.pack(from); 106 } 107 108 localMessage.mTo = Address.pack(to); 109 localMessage.mCc = Address.pack(cc); 110 localMessage.mBcc = Address.pack(bcc); 111 localMessage.mReplyTo = Address.pack(replyTo); 112 113// public String mServerVersion; 114// 115// public String mText; 116// public String mHtml; 117// 118// // Can be used while building messages, but is NOT saved by the Provider 119// transient public ArrayList<Attachment> mAttachments = null; 120 121 return true; 122 } 123 124 /** 125 * Copy body text (plain and/or HTML) from MimeMessage to provider Message 126 * 127 * TODO: Take a closer look at textInfo and deal with it if necessary. 128 */ 129 public static boolean updateBodyFields(EmailContent.Body body, 130 EmailContent.Message localMessage, ArrayList<Part> viewables) 131 throws MessagingException { 132 133 body.mMessageKey = localMessage.mId; 134 135 StringBuffer sbHtml = new StringBuffer(); 136 StringBuffer sbText = new StringBuffer(); 137 for (Part viewable : viewables) { 138 String text = MimeUtility.getTextFromPart(viewable); 139 if ("text/html".equalsIgnoreCase(viewable.getMimeType())) { 140 if (sbHtml.length() > 0) { 141 sbHtml.append('\n'); 142 } 143 sbHtml.append(text); 144 } else { 145 if (sbText.length() > 0) { 146 sbText.append('\n'); 147 } 148 sbText.append(text); 149 } 150 } 151 152 // write the combined data to the body part 153 if (sbText.length() != 0) { 154 localMessage.mTextInfo = "X;X;8;" + sbText.length()*2; 155 body.mTextContent = sbText.toString(); 156 } 157 if (sbHtml.length() != 0) { 158 localMessage.mHtmlInfo = "X;X;8;" + sbHtml.length()*2; 159 body.mHtmlContent = sbHtml.toString(); 160 } 161 return true; 162 } 163 164 /** 165 * Copy attachments from MimeMessage to provider Message. 166 * 167 * @param context a context for file operations 168 * @param localMessage the attachments will be built against this message 169 * @param message the original message from POP or IMAP, that may have attachments 170 * @return true if it succeeded 171 * @throws IOException 172 */ 173 public static void updateAttachments(Context context, EmailContent.Message localMessage, 174 ArrayList<Part> attachments) throws MessagingException, IOException { 175 localMessage.mAttachments = null; 176 for (Part attachmentPart : attachments) { 177 addOneAttachment(context, localMessage, attachmentPart); 178 } 179 } 180 181 /** 182 * Add a single attachment part to the message 183 * 184 * TODO: This will simply add to any existing attachments - could this ever happen? If so, 185 * change it to find existing attachments and delete/merge them. 186 * TODO: Take a closer look at encoding and deal with it if necessary. 187 * 188 * @param context a context for file operations 189 * @param localMessage the attachments will be built against this message 190 * @param part a single attachment part from POP or IMAP 191 * @return true if it succeeded 192 * @throws IOException 193 */ 194 private static void addOneAttachment(Context context, EmailContent.Message localMessage, 195 Part part) throws MessagingException, IOException { 196 197 Attachment localAttachment = new Attachment(); 198 199 // Transfer fields from mime format to provider format 200 String contentType = MimeUtility.unfoldAndDecode(part.getContentType()); 201 String name = MimeUtility.getHeaderParameter(contentType, "name"); 202 if (name == null) { 203 String contentDisposition = MimeUtility.unfoldAndDecode(part.getContentType()); 204 name = MimeUtility.getHeaderParameter(contentDisposition, "filename"); 205 } 206 207 // Try to pull size from disposition (if not downloaded) 208 long size = 0; 209 String disposition = part.getDisposition(); 210 if (disposition != null) { 211 String s = MimeUtility.getHeaderParameter(disposition, "size"); 212 if (s != null) { 213 size = Long.parseLong(s); 214 } 215 } 216 217 // Get partId for unloaded IMAP attachments (if any) 218 // This is only provided (and used) when we have structure but not the actual attachment 219 String[] partIds = part.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); 220 String partId = partIds != null ? partIds[0] : null;; 221 222 localAttachment.mFileName = MimeUtility.getHeaderParameter(contentType, "name"); 223 localAttachment.mMimeType = part.getMimeType(); 224 localAttachment.mSize = size; // May be reset below if file handled 225 localAttachment.mContentId = part.getContentId(); 226 localAttachment.mContentUri = null; // Will be set when file is saved 227 localAttachment.mMessageKey = localMessage.mId; 228 localAttachment.mLocation = partId; 229 localAttachment.mEncoding = "B"; // TODO - convert other known encodings 230 231 // Save the attachment (so far) in order to obtain an id 232 localAttachment.save(context); 233 234 // If an attachment body was actually provided, we need to write the file now 235 saveAttachmentBody(context, part, localAttachment, localMessage.mAccountKey); 236 237 if (localMessage.mAttachments == null) { 238 localMessage.mAttachments = new ArrayList<Attachment>(); 239 } 240 localMessage.mAttachments.add(localAttachment); 241 localMessage.mFlagAttachment = true; 242 } 243 244 /** 245 * Save the body part of a single attachment, to a file in the attachments directory. 246 */ 247 public static void saveAttachmentBody(Context context, Part part, Attachment localAttachment, 248 long accountId) throws MessagingException, IOException { 249 if (part.getBody() != null) { 250 long attachmentId = localAttachment.mId; 251 252 InputStream in = part.getBody().getInputStream(); 253 254 File saveIn = AttachmentProvider.getAttachmentDirectory(context, accountId); 255 if (!saveIn.exists()) { 256 saveIn.mkdirs(); 257 } 258 File saveAs = AttachmentProvider.getAttachmentFilename(context, accountId, 259 attachmentId); 260 saveAs.createNewFile(); 261 FileOutputStream out = new FileOutputStream(saveAs); 262 long copySize = IOUtils.copy(in, out); 263 in.close(); 264 out.close(); 265 266 // update the attachment with the extra information we now know 267 String contentUriString = AttachmentProvider.getAttachmentUri( 268 accountId, attachmentId).toString(); 269 270 localAttachment.mSize = copySize; 271 localAttachment.mContentUri = contentUriString; 272 273 // update the attachment in the database as well 274 ContentValues cv = new ContentValues(); 275 cv.put(AttachmentColumns.SIZE, copySize); 276 cv.put(AttachmentColumns.CONTENT_URI, contentUriString); 277 Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachmentId); 278 context.getContentResolver().update(uri, cv, null, null); 279 } 280 } 281 282} 283