1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-23 18:02:15 -05:00

Fix downloading/saving single message parts

This commit is contained in:
cketti 2015-01-10 04:04:37 +01:00
parent 743e640d8c
commit bd97004ebd
6 changed files with 83 additions and 40 deletions

View File

@ -2,14 +2,25 @@ package com.fsck.k9.mail;
public abstract class BodyPart implements Part { 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() { public Multipart getParent() {
return mParent; return parent;
} }
public void setParent(Multipart parent) { public void setParent(Multipart parent) {
mParent = parent; this.parent = parent;
} }
public abstract void setEncoding(String encoding) throws MessagingException; public abstract void setEncoding(String encoding) throws MessagingException;

View File

@ -46,4 +46,8 @@ public interface Part {
*/ */
//TODO perhaps it would be clearer to use a flag "force7bit" in writeTo //TODO perhaps it would be clearer to use a flag "force7bit" in writeTo
void setUsing7bitTransport() throws MessagingException; void setUsing7bitTransport() throws MessagingException;
String getServerExtra();
void setServerExtra(String serverExtra);
} }

View File

@ -11,28 +11,11 @@ import java.util.*;
public class MimeHeader { public class MimeHeader {
private static final String[] EMPTY_STRING_ARRAY = new String[0]; 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_TYPE = "Content-Type";
public static final String HEADER_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding"; 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_DISPOSITION = "Content-Disposition";
public static final String HEADER_CONTENT_ID = "Content-ID"; 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<Field> mFields = new ArrayList<Field>(); private List<Field> mFields = new ArrayList<Field>();
private String mCharset = null; private String mCharset = null;
@ -101,14 +84,12 @@ public class MimeHeader {
public void writeTo(OutputStream out) throws IOException { public void writeTo(OutputStream out) throws IOException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
for (Field field : mFields) { for (Field field : mFields) {
if (!Arrays.asList(writeOmitFields).contains(field.name)) { if (field.hasRawData()) {
if (field.hasRawData()) { writer.write(field.getRaw());
writer.write(field.getRaw()); } else {
} else { writeNameValueField(writer, field);
writeNameValueField(writer, field);
}
writer.write("\r\n");
} }
writer.write("\r\n");
} }
writer.flush(); writer.flush();
} }

View File

@ -57,6 +57,7 @@ public class MimeMessage extends Message {
private Body mBody; private Body mBody;
protected int mSize; protected int mSize;
private String serverExtra;
public MimeMessage() { public MimeMessage() {
} }
@ -693,4 +694,16 @@ public class MimeMessage extends Message {
setEncoding(MimeUtil.ENC_QUOTED_PRINTABLE); setEncoding(MimeUtil.ENC_QUOTED_PRINTABLE);
} }
} }
@Override
public String getServerExtra() {
return serverExtra;
}
@Override
public void setServerExtra(String serverExtra) {
this.serverExtra = serverExtra;
}
} }

View File

@ -1455,13 +1455,9 @@ public class ImapStore extends RemoteStore {
throws MessagingException { throws MessagingException {
checkOpen(); //only need READ access checkOpen(); //only need READ access
String[] parts = part.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); String partId = part.getServerExtra();
if (parts == null) {
return;
}
String fetch; String fetch;
String partId = parts[0];
if ("TEXT".equalsIgnoreCase(partId)) { if ("TEXT".equalsIgnoreCase(partId)) {
fetch = String.format(Locale.US, "BODY.PEEK[TEXT]<0.%d>", fetch = String.format(Locale.US, "BODY.PEEK[TEXT]<0.%d>",
mStoreConfig.getMaximumAutoDownloadMessageSize()); mStoreConfig.getMaximumAutoDownloadMessageSize());
@ -1834,7 +1830,7 @@ public class ImapStore extends RemoteStore {
if (part instanceof ImapMessage) { if (part instanceof ImapMessage) {
((ImapMessage) part).setSize(size); ((ImapMessage) part).setSize(size);
} }
part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, id); part.setServerExtra(id);
} }
} }

View File

@ -672,6 +672,7 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
long parentId = cursor.getLong(2); long parentId = cursor.getLong(2);
String mimeType = cursor.getString(3); String mimeType = cursor.getString(3);
byte[] header = cursor.getBlob(6); byte[] header = cursor.getBlob(6);
String serverExtra = cursor.getString(15);
final Part part; final Part part;
if (id == message.getMessagePartId()) { if (id == message.getMessagePartId()) {
@ -698,6 +699,7 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
parseHeaderBytes(part, header); parseHeaderBytes(part, header);
} }
partById.put(id, part); partById.put(id, part);
part.setServerExtra(serverExtra);
boolean isMultipart = mimeType.startsWith("multipart/"); boolean isMultipart = mimeType.startsWith("multipart/");
if (isMultipart) { if (isMultipart) {
@ -1322,14 +1324,22 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
Part part = partContainer.part; Part part = partContainer.part;
byte[] headerBytes = getHeaderBytes(part);
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
if (rootMessagePartId != -1) { if (rootMessagePartId != -1) {
cv.put("root", rootMessagePartId); cv.put("root", rootMessagePartId);
} }
cv.put("parent", partContainer.parent); cv.put("parent", partContainer.parent);
cv.put("seq", order); 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("mime_type", part.getMimeType());
cv.put("header", headerBytes); cv.put("header", headerBytes);
cv.put("type", MessagePartType.UNKNOWN); cv.put("type", MessagePartType.UNKNOWN);
@ -1355,8 +1365,6 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
cv.put("data", bodyData); cv.put("data", bodyData);
cv.put("content_id", part.getContentId()); cv.put("content_id", part.getContentId());
} }
return db.insertOrThrow("message_parts", null, cv);
} }
private byte[] getHeaderBytes(Part part) throws IOException, MessagingException { private byte[] getHeaderBytes(Part part) throws IOException, MessagingException {
@ -1403,9 +1411,39 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
public void addPartToMessage(final LocalMessage message, final Part part) throws MessagingException { public void addPartToMessage(final LocalMessage message, final Part part) throws MessagingException {
open(OPEN_MODE_RW); open(OPEN_MODE_RW);
throw new RuntimeException("Not implemented yet");
// localStore.notifyChange(); localStore.database.execute(false, new DbCallback<Void>() {
@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<LocalMessage> implements Serializable {
@Override @Override
public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException { public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException {
db.update("messages", cv, "id = ?", new String[] db.update("messages", cv, "id = ?", new String[]
{ Long.toString(message.getId()) }); { Long.toString(message.getId()) });
return null; return null;
} }
}); });