diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/BodyPart.java b/k9mail-library/src/main/java/com/fsck/k9/mail/BodyPart.java index 551866829..ef48dce8f 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/BodyPart.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/BodyPart.java @@ -2,14 +2,25 @@ package com.fsck.k9.mail; public abstract class BodyPart implements Part { - private Multipart mParent; + private String serverExtra; + private Multipart parent; + + @Override + public String getServerExtra() { + return serverExtra; + } + + @Override + public void setServerExtra(String serverExtra) { + this.serverExtra = serverExtra; + } public Multipart getParent() { - return mParent; + return parent; } public void setParent(Multipart parent) { - mParent = parent; + this.parent = parent; } public abstract void setEncoding(String encoding) throws MessagingException; diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/Part.java b/k9mail-library/src/main/java/com/fsck/k9/mail/Part.java index 15e371392..492b2a171 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/Part.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/Part.java @@ -46,4 +46,8 @@ public interface Part { */ //TODO perhaps it would be clearer to use a flag "force7bit" in writeTo void setUsing7bitTransport() throws MessagingException; + + String getServerExtra(); + + void setServerExtra(String serverExtra); } diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/internet/MimeHeader.java b/k9mail-library/src/main/java/com/fsck/k9/mail/internet/MimeHeader.java index f3835d04a..318ea6da0 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/internet/MimeHeader.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/internet/MimeHeader.java @@ -11,28 +11,11 @@ import java.util.*; public class MimeHeader { private static final String[] EMPTY_STRING_ARRAY = new String[0]; - /** - * Application specific header that contains Store specific information about an attachment. - * In IMAP this contains the IMAP BODYSTRUCTURE part id so that the ImapStore can later - * retrieve the attachment at will from the server. - * The info is recorded from this header on LocalStore.appendMessages and is put back - * into the MIME data by LocalStore.fetch. - */ - public static final String HEADER_ANDROID_ATTACHMENT_STORE_DATA = "X-Android-Attachment-StoreData"; - public static final String HEADER_CONTENT_TYPE = "Content-Type"; public static final String HEADER_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding"; public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; public static final String HEADER_CONTENT_ID = "Content-ID"; - /** - * Fields that should be omitted when writing the header using writeTo() - */ - private static final String[] writeOmitFields = { -// HEADER_ANDROID_ATTACHMENT_DOWNLOADED, -// HEADER_ANDROID_ATTACHMENT_ID, - HEADER_ANDROID_ATTACHMENT_STORE_DATA - }; private List mFields = new ArrayList(); private String mCharset = null; @@ -101,14 +84,12 @@ public class MimeHeader { public void writeTo(OutputStream out) throws IOException { BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); for (Field field : mFields) { - if (!Arrays.asList(writeOmitFields).contains(field.name)) { - if (field.hasRawData()) { - writer.write(field.getRaw()); - } else { - writeNameValueField(writer, field); - } - writer.write("\r\n"); + if (field.hasRawData()) { + writer.write(field.getRaw()); + } else { + writeNameValueField(writer, field); } + writer.write("\r\n"); } writer.flush(); } diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/internet/MimeMessage.java b/k9mail-library/src/main/java/com/fsck/k9/mail/internet/MimeMessage.java index e7909c105..4cf09460e 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/internet/MimeMessage.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/internet/MimeMessage.java @@ -57,6 +57,7 @@ public class MimeMessage extends Message { private Body mBody; protected int mSize; + private String serverExtra; public MimeMessage() { } @@ -693,4 +694,16 @@ public class MimeMessage extends Message { setEncoding(MimeUtil.ENC_QUOTED_PRINTABLE); } } + + @Override + public String getServerExtra() { + return serverExtra; + } + + @Override + public void setServerExtra(String serverExtra) { + this.serverExtra = serverExtra; + } + + } diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapStore.java b/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapStore.java index 7df04e2b4..6cf6825fe 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapStore.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapStore.java @@ -1455,13 +1455,9 @@ public class ImapStore extends RemoteStore { throws MessagingException { checkOpen(); //only need READ access - String[] parts = part.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); - if (parts == null) { - return; - } + String partId = part.getServerExtra(); String fetch; - String partId = parts[0]; if ("TEXT".equalsIgnoreCase(partId)) { fetch = String.format(Locale.US, "BODY.PEEK[TEXT]<0.%d>", mStoreConfig.getMaximumAutoDownloadMessageSize()); @@ -1834,7 +1830,7 @@ public class ImapStore extends RemoteStore { if (part instanceof ImapMessage) { ((ImapMessage) part).setSize(size); } - part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, id); + part.setServerExtra(id); } } diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java b/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java index a4eb27112..265a0015c 100644 --- a/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java +++ b/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java @@ -672,6 +672,7 @@ public class LocalFolder extends Folder implements Serializable { long parentId = cursor.getLong(2); String mimeType = cursor.getString(3); byte[] header = cursor.getBlob(6); + String serverExtra = cursor.getString(15); final Part part; if (id == message.getMessagePartId()) { @@ -698,6 +699,7 @@ public class LocalFolder extends Folder implements Serializable { parseHeaderBytes(part, header); } partById.put(id, part); + part.setServerExtra(serverExtra); boolean isMultipart = mimeType.startsWith("multipart/"); if (isMultipart) { @@ -1322,14 +1324,22 @@ public class LocalFolder extends Folder implements Serializable { Part part = partContainer.part; - byte[] headerBytes = getHeaderBytes(part); - ContentValues cv = new ContentValues(); if (rootMessagePartId != -1) { cv.put("root", rootMessagePartId); } cv.put("parent", partContainer.parent); cv.put("seq", order); + cv.put("server_extra", part.getServerExtra()); + + partToContentValues(cv, part); + + return db.insertOrThrow("message_parts", null, cv); + } + + private void partToContentValues(ContentValues cv, Part part) throws IOException, MessagingException { + byte[] headerBytes = getHeaderBytes(part); + cv.put("mime_type", part.getMimeType()); cv.put("header", headerBytes); cv.put("type", MessagePartType.UNKNOWN); @@ -1355,8 +1365,6 @@ public class LocalFolder extends Folder implements Serializable { cv.put("data", bodyData); cv.put("content_id", part.getContentId()); } - - return db.insertOrThrow("message_parts", null, cv); } private byte[] getHeaderBytes(Part part) throws IOException, MessagingException { @@ -1403,9 +1411,39 @@ public class LocalFolder extends Folder implements Serializable { public void addPartToMessage(final LocalMessage message, final Part part) throws MessagingException { open(OPEN_MODE_RW); - throw new RuntimeException("Not implemented yet"); -// localStore.notifyChange(); + localStore.database.execute(false, new DbCallback() { + @Override + public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException { + String messagePartId; + + Cursor cursor = db.query("message_parts", new String[] { "id" }, "root = ? AND server_extra = ?", + new String[] { Long.toString(message.getMessagePartId()), part.getServerExtra() }, + null, null, null); + try { + if (!cursor.moveToFirst()) { + throw new IllegalStateException("Message part not found"); + } + + messagePartId = cursor.getString(0); + } finally { + cursor.close(); + } + + try { + ContentValues cv = new ContentValues(); + partToContentValues(cv, part); + + db.update("message_parts", cv, "id = ?", new String[] { messagePartId }); + } catch (Exception e) { + Log.e(K9.LOG_TAG, "Error writing message part", e); + } + + return null; + } + }); + + localStore.notifyChange(); } /** @@ -1422,7 +1460,7 @@ public class LocalFolder extends Folder implements Serializable { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException { db.update("messages", cv, "id = ?", new String[] - { Long.toString(message.getId()) }); + { Long.toString(message.getId()) }); return null; } });