diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java index be318d998..24f9da2da 100644 --- a/src/com/fsck/k9/mail/internet/MimeUtility.java +++ b/src/com/fsck/k9/mail/internet/MimeUtility.java @@ -876,7 +876,14 @@ public class MimeUtility { { "zmm", "application/vnd.handheld-entertainment+xml"} }; - + /** + * Table for MIME type replacements. + * + * Table format: wrong type, correct type + */ + private static final String[][] MIME_TYPE_REPLACEMENT_MAP = new String[][] { + {"image/jpg", "image/jpeg"} + }; public static String unfold(String s) { if (s == null) { @@ -1193,6 +1200,46 @@ public class MimeUtility { return DEFAULT_ATTACHMENT_MIME_TYPE; } + /** + * Convert some wrong MIME types encountered in the wild to canonical MIME + * types. + * + * @param mimeType The original MIME type + * @return If {@code mimeType} is known to be wrong the correct MIME type + * is returned. Otherwise the value of {@code mimeType} is returned + * unmodified. + * + * @see #MIME_TYPE_REPLACEMENT_MAP + */ + public static String canonicalizeMimeType(String mimeType) { + for (String[] mimeTypeMapEntry : MIME_TYPE_REPLACEMENT_MAP) { + if (mimeTypeMapEntry[0].equals(mimeType)) { + return mimeTypeMapEntry[1]; + } + } + return mimeType; + } + + /** + * When viewing the attachment we want the MIME type to be as sensible as + * possible. So we fix it up if necessary. + * + * @param mimeType The original MIME type of the attachment. + * @param name The (file)name of the attachment. + * + * @return The best MIME type we can come up with. + */ + public static String getMimeTypeForViewing(String mimeType, String name) { + if (DEFAULT_ATTACHMENT_MIME_TYPE.equalsIgnoreCase(mimeType)) { + // If the MIME type is the generic "application/octet-stream" + // we try to find a better one by looking at the file extension. + return getMimeTypeByExtension(name); + } else { + // Some messages contain wrong MIME types. See if we know better. + return canonicalizeMimeType(mimeType); + } + } + private static Message getMessageFromPart(Part part) { while (part != null) { if (part instanceof Message) diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java index e90e5a64e..4c2ede1e5 100644 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ b/src/com/fsck/k9/mail/store/LocalStore.java @@ -988,49 +988,18 @@ public class LocalStore extends Store implements Serializable { } - public String getAttachmentType(final String attachmentId) throws UnavailableStorageException { - return database.execute(false, new DbCallback() { - @Override - public String doDbWork(final SQLiteDatabase db) throws WrappedException { - Cursor cursor = null; - try { - cursor = db.query( - "attachments", - new String[] { "mime_type", "name" }, - "id = ?", - new String[] { attachmentId }, - null, - null, - null); - cursor.moveToFirst(); - String type = cursor.getString(0); - String name = cursor.getString(1); - cursor.close(); - - if (MimeUtility.DEFAULT_ATTACHMENT_MIME_TYPE.equalsIgnoreCase(type)) { - type = MimeUtility.getMimeTypeByExtension(name); - } - return type; - } finally { - if (cursor != null) { - cursor.close(); - } - } - } - }); - } - public AttachmentInfo getAttachmentInfo(final String attachmentId) throws UnavailableStorageException { return database.execute(false, new DbCallback() { @Override public AttachmentInfo doDbWork(final SQLiteDatabase db) throws WrappedException { String name; + String type; int size; Cursor cursor = null; try { cursor = db.query( "attachments", - new String[] { "name", "size" }, + new String[] { "name", "size", "mime_type" }, "id = ?", new String[] { attachmentId }, null, @@ -1041,9 +1010,11 @@ public class LocalStore extends Store implements Serializable { } name = cursor.getString(0); size = cursor.getInt(1); + type = cursor.getString(2); final AttachmentInfo attachmentInfo = new AttachmentInfo(); attachmentInfo.name = name; attachmentInfo.size = size; + attachmentInfo.type = type; return attachmentInfo; } finally { if (cursor != null) { @@ -1057,6 +1028,7 @@ public class LocalStore extends Store implements Serializable { public static class AttachmentInfo { public String name; public int size; + public String type; } public void createFolders(final List foldersToCreate, final int visibleLimit) throws UnavailableStorageException { diff --git a/src/com/fsck/k9/provider/AttachmentProvider.java b/src/com/fsck/k9/provider/AttachmentProvider.java index fc9c8c4f6..126223d72 100644 --- a/src/com/fsck/k9/provider/AttachmentProvider.java +++ b/src/com/fsck/k9/provider/AttachmentProvider.java @@ -30,6 +30,7 @@ public class AttachmentProvider extends ContentProvider { public static final Uri CONTENT_URI = Uri.parse("content://com.fsck.k9.attachmentprovider"); private static final String FORMAT_RAW = "RAW"; + private static final String FORMAT_VIEW = "VIEW"; private static final String FORMAT_THUMBNAIL = "THUMBNAIL"; public static class AttachmentProviderColumns { @@ -40,7 +41,11 @@ public class AttachmentProvider extends ContentProvider { } public static Uri getAttachmentUri(Account account, long id) { - return getAttachmentUri(account.getUuid(), id); + return getAttachmentUri(account.getUuid(), id, true); + } + + public static Uri getAttachmentUriForViewing(Account account, long id) { + return getAttachmentUri(account.getUuid(), id, false); } public static Uri getAttachmentThumbnailUri(Account account, long id, int width, int height) { @@ -53,11 +58,11 @@ public class AttachmentProvider extends ContentProvider { .build(); } - private static Uri getAttachmentUri(String db, long id) { + private static Uri getAttachmentUri(String db, long id, boolean raw) { return CONTENT_URI.buildUpon() .appendPath(db) .appendPath(Long.toString(id)) - .appendPath(FORMAT_RAW) + .appendPath(raw ? FORMAT_RAW : FORMAT_VIEW) .build(); } @@ -98,6 +103,11 @@ public class AttachmentProvider extends ContentProvider { String dbName = segments.get(0); String id = segments.get(1); String format = segments.get(2); + + return getType(dbName, id, format); + } + + private String getType(String dbName, String id, String format) { if (FORMAT_THUMBNAIL.equals(format)) { return "image/png"; } else { @@ -105,7 +115,14 @@ public class AttachmentProvider extends ContentProvider { try { final LocalStore localStore = LocalStore.getLocalInstance(account, K9.app); - return localStore.getAttachmentType(id); + + AttachmentInfo attachmentInfo = localStore.getAttachmentInfo(id); + if (FORMAT_VIEW.equals(format)) { + return MimeUtility.getMimeTypeForViewing(attachmentInfo.type, attachmentInfo.name); + } else { + // When accessing the "raw" message we deliver the original MIME type. + return attachmentInfo.type; + } } catch (MessagingException e) { Log.e(K9.LOG_TAG, "Unable to retrieve LocalStore for " + account, e); return null; @@ -148,8 +165,7 @@ public class AttachmentProvider extends ContentProvider { File dir = getContext().getCacheDir(); File file = new File(dir, filename); if (!file.exists()) { - Uri attachmentUri = getAttachmentUri(dbName, Long.parseLong(id)); - String type = getType(attachmentUri); + String type = getType(dbName, id, FORMAT_VIEW); try { FileInputStream in = new FileInputStream(getFile(dbName, id)); try { diff --git a/src/com/fsck/k9/view/AttachmentView.java b/src/com/fsck/k9/view/AttachmentView.java index 21fea308b..1fff23319 100644 --- a/src/com/fsck/k9/view/AttachmentView.java +++ b/src/com/fsck/k9/view/AttachmentView.java @@ -78,10 +78,7 @@ public class AttachmentView extends FrameLayout { mListener = listener; size = Integer.parseInt(MimeUtility.getHeaderParameter(contentDisposition, "size")); - contentType = part.getMimeType(); - if (MimeUtility.DEFAULT_ATTACHMENT_MIME_TYPE.equalsIgnoreCase(contentType)) { - contentType = MimeUtility.getMimeTypeByExtension(name); - } + contentType = MimeUtility.getMimeTypeForViewing(part.getMimeType(), name); TextView attachmentName = (TextView) findViewById(R.id.attachment_name); TextView attachmentInfo = (TextView) findViewById(R.id.attachment_info); ImageView attachmentIcon = (ImageView) findViewById(R.id.attachment_icon); @@ -196,7 +193,7 @@ public class AttachmentView extends FrameLayout { public void showFile() { - Uri uri = AttachmentProvider.getAttachmentUri(mAccount, part.getAttachmentId()); + Uri uri = AttachmentProvider.getAttachmentUriForViewing(mAccount, part.getAttachmentId()); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(uri); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); @@ -227,7 +224,7 @@ public class AttachmentView extends FrameLayout { return; } try { - Uri uri = AttachmentProvider.getAttachmentUri(mAccount, part.getAttachmentId()); + Uri uri = AttachmentProvider.getAttachmentUriForViewing(mAccount, part.getAttachmentId()); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(uri); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);