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:
parent
743e640d8c
commit
bd97004ebd
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user