From bd700127dec2c9bef12cd0ac9fd8864a1e471cc9 Mon Sep 17 00:00:00 2001 From: ashley willis Date: Mon, 23 Jan 2012 19:51:30 -0600 Subject: [PATCH 01/15] added montclair.edu to res/xml/providers.xml based on http://oit.montclair.edu/documentation/msu_apps/email/AndroidPhoneSettingUpYourMSUEmailAccount.pdf --- res/xml/providers.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/xml/providers.xml b/res/xml/providers.xml index 9a7ecc794..62a7f9c75 100644 --- a/res/xml/providers.xml +++ b/res/xml/providers.xml @@ -170,6 +170,10 @@ + + + + From 7a3cadbf1c838f097332e5d04a05aeaabb6afa28 Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 24 Jan 2012 14:34:32 +0100 Subject: [PATCH 02/15] Refactored AttachmentProvider.openFile() --- .../fsck/k9/provider/AttachmentProvider.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/com/fsck/k9/provider/AttachmentProvider.java b/src/com/fsck/k9/provider/AttachmentProvider.java index 542beab00..1a493a446 100644 --- a/src/com/fsck/k9/provider/AttachmentProvider.java +++ b/src/com/fsck/k9/provider/AttachmentProvider.java @@ -157,24 +157,24 @@ public class AttachmentProvider extends ContentProvider { @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + File file; + List segments = uri.getPathSegments(); - String dbName = segments.get(0); // "/sdcard/..." is URL-encoded and makes up only 1 segment - String id = segments.get(1); + String accountUuid = segments.get(0); + String attachmentId = segments.get(1); String format = segments.get(2); + if (FORMAT_THUMBNAIL.equals(format)) { int width = Integer.parseInt(segments.get(3)); int height = Integer.parseInt(segments.get(4)); - String filename = "thmb_" + dbName + "_" + id + ".tmp"; - int index = dbName.lastIndexOf('/'); - if (index >= 0) { - filename = /*dbName.substring(0, index + 1) + */"thmb_" + dbName.substring(index + 1) + "_" + id + ".tmp"; - } + + String filename = "thmb_" + accountUuid + "_" + attachmentId + ".tmp"; File dir = getContext().getCacheDir(); - File file = new File(dir, filename); + file = new File(dir, filename); if (!file.exists()) { - String type = getType(dbName, id, FORMAT_VIEW); + String type = getType(accountUuid, attachmentId, FORMAT_VIEW); try { - FileInputStream in = new FileInputStream(getFile(dbName, id)); + FileInputStream in = new FileInputStream(getFile(accountUuid, attachmentId)); try { Bitmap thumbnail = createThumbnail(type, in); if (thumbnail != null) { @@ -187,18 +187,17 @@ public class AttachmentProvider extends ContentProvider { } } } finally { - try { in.close(); } catch (Throwable ignore) {} + try { in.close(); } catch (Throwable ignore) { /* ignore */ } } } catch (IOException ioe) { return null; } } - return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } else { - return ParcelFileDescriptor.open( - getFile(dbName, id), - ParcelFileDescriptor.MODE_READ_ONLY); + file = getFile(accountUuid, attachmentId); } + + return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } @Override From c6696f632a18a3292f2edc7ee0650154e148fb73 Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 24 Jan 2012 14:49:08 +0100 Subject: [PATCH 03/15] Code cleanup, fixed some warnings, rearranged some stuff --- .../fsck/k9/provider/AttachmentProvider.java | 168 +++++++++--------- 1 file changed, 88 insertions(+), 80 deletions(-) diff --git a/src/com/fsck/k9/provider/AttachmentProvider.java b/src/com/fsck/k9/provider/AttachmentProvider.java index 1a493a446..4b90305c7 100644 --- a/src/com/fsck/k9/provider/AttachmentProvider.java +++ b/src/com/fsck/k9/provider/AttachmentProvider.java @@ -23,8 +23,12 @@ import java.io.*; import java.util.List; /** - * A simple ContentProvider that allows file access to Email's attachments.
- * Warning! We make heavy assumptions about the Uris used by the {@link LocalStore} for an {@link Account} here. + * A simple ContentProvider that allows file access to attachments. + * + *

+ * Warning! We make heavy assumptions about the Uris used by the {@link LocalStore} for an + * {@link Account} here. + *

*/ public class AttachmentProvider extends ContentProvider { public static final Uri CONTENT_URI = Uri.parse("content://com.fsck.k9.attachmentprovider"); @@ -33,6 +37,11 @@ public class AttachmentProvider extends ContentProvider { private static final String FORMAT_VIEW = "VIEW"; private static final String FORMAT_THUMBNAIL = "THUMBNAIL"; + private static final String[] DEFAULT_PROJECTION = new String[] { + AttachmentProviderColumns._ID, + AttachmentProviderColumns.DATA, + }; + public static class AttachmentProviderColumns { public static final String _ID = "_id"; public static final String DATA = "_data"; @@ -40,6 +49,7 @@ public class AttachmentProvider extends ContentProvider { public static final String SIZE = "_size"; } + public static Uri getAttachmentUri(Account account, long id) { return getAttachmentUri(account.getUuid(), id, true); } @@ -66,6 +76,23 @@ public class AttachmentProvider extends ContentProvider { .build(); } + public static void clear(Context context) { + /* + * We use the cache dir as a temporary directory (since Android doesn't give us one) so + * on startup we'll clean up any .tmp files from the last run. + */ + File[] files = context.getCacheDir().listFiles(); + for (File file : files) { + try { + if (K9.DEBUG) { + Log.d(K9.LOG_TAG, "Deleting file " + file.getCanonicalPath()); + } + } catch (IOException ioe) { /* No need to log failure to log */ } + file.delete(); + } + } + + @Override public boolean onCreate() { /* @@ -89,21 +116,6 @@ public class AttachmentProvider extends ContentProvider { return true; } - public static void clear(Context lContext) { - /* - * We use the cache dir as a temporary directory (since Android doesn't give us one) so - * on startup we'll clean up any .tmp files from the last run. - */ - File[] files = lContext.getCacheDir().listFiles(); - for (File file : files) { - try { - if (K9.DEBUG) - Log.d(K9.LOG_TAG, "Deleting file " + file.getCanonicalPath()); - } catch (IOException ioe) {} // No need to log failure to log - file.delete(); - } - } - @Override public String getType(Uri uri) { List segments = uri.getPathSegments(); @@ -114,47 +126,6 @@ public class AttachmentProvider extends ContentProvider { return getType(dbName, id, format); } - private String getType(String dbName, String id, String format) { - if (FORMAT_THUMBNAIL.equals(format)) { - return "image/png"; - } else { - final Account account = Preferences.getPreferences(getContext()).getAccount(dbName); - - try { - final LocalStore localStore = LocalStore.getLocalInstance(account, K9.app); - - 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; - } - } - } - - private File getFile(String dbName, String id) - throws FileNotFoundException { - try { - final Account account = Preferences.getPreferences(getContext()).getAccount(dbName); - final File attachmentsDir; - attachmentsDir = StorageManager.getInstance(K9.app).getAttachmentDirectory(dbName, - account.getLocalStorageProviderId()); - final File file = new File(attachmentsDir, id); - if (!file.exists()) { - throw new FileNotFoundException(file.getAbsolutePath()); - } - return file; - } catch (IOException e) { - Log.w(K9.LOG_TAG, null, e); - throw new FileNotFoundException(e.getMessage()); - } - } - @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { File file; @@ -200,26 +171,11 @@ public class AttachmentProvider extends ContentProvider { return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } - @Override - public int delete(Uri uri, String arg1, String[] arg2) { - return 0; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - if (projection == null) { - projection = - new String[] { - AttachmentProviderColumns._ID, - AttachmentProviderColumns.DATA, - }; - } + + String[] columnNames = (projection == null) ? DEFAULT_PROJECTION : projection; List segments = uri.getPathSegments(); String dbName = segments.get(0); @@ -231,7 +187,6 @@ public class AttachmentProvider extends ContentProvider { dbName = dbName.substring(0, dbName.length() - 3); } - //String format = segments.get(2); final AttachmentInfo attachmentInfo; try { final Account account = Preferences.getPreferences(getContext()).getAccount(dbName); @@ -241,10 +196,10 @@ public class AttachmentProvider extends ContentProvider { return null; } - MatrixCursor ret = new MatrixCursor(projection); - Object[] values = new Object[projection.length]; - for (int i = 0, count = projection.length; i < count; i++) { - String column = projection[i]; + MatrixCursor ret = new MatrixCursor(columnNames); + Object[] values = new Object[columnNames.length]; + for (int i = 0, count = columnNames.length; i < count; i++) { + String column = columnNames[i]; if (AttachmentProviderColumns._ID.equals(column)) { values[i] = id; } else if (AttachmentProviderColumns.DATA.equals(column)) { @@ -264,6 +219,59 @@ public class AttachmentProvider extends ContentProvider { return 0; } + @Override + public int delete(Uri uri, String arg1, String[] arg2) { + return 0; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + private String getType(String dbName, String id, String format) { + String type; + if (FORMAT_THUMBNAIL.equals(format)) { + type = "image/png"; + } else { + final Account account = Preferences.getPreferences(getContext()).getAccount(dbName); + + try { + final LocalStore localStore = LocalStore.getLocalInstance(account, K9.app); + + AttachmentInfo attachmentInfo = localStore.getAttachmentInfo(id); + if (FORMAT_VIEW.equals(format)) { + type = MimeUtility.getMimeTypeForViewing(attachmentInfo.type, attachmentInfo.name); + } else { + // When accessing the "raw" message we deliver the original MIME type. + type = attachmentInfo.type; + } + } catch (MessagingException e) { + Log.e(K9.LOG_TAG, "Unable to retrieve LocalStore for " + account, e); + type = null; + } + } + + return type; + } + + private File getFile(String dbName, String id) throws FileNotFoundException { + try { + final Account account = Preferences.getPreferences(getContext()).getAccount(dbName); + final File attachmentsDir; + attachmentsDir = StorageManager.getInstance(K9.app).getAttachmentDirectory(dbName, + account.getLocalStorageProviderId()); + final File file = new File(attachmentsDir, id); + if (!file.exists()) { + throw new FileNotFoundException(file.getAbsolutePath()); + } + return file; + } catch (IOException e) { + Log.w(K9.LOG_TAG, null, e); + throw new FileNotFoundException(e.getMessage()); + } + } + private Bitmap createThumbnail(String type, InputStream data) { if (MimeUtility.mimeTypeMatches(type, "image/*")) { return createImageThumbnail(data); From 4e5d1167138869d42276c7e4114de12c4a31f5ee Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 24 Jan 2012 15:41:03 +0100 Subject: [PATCH 04/15] Delete attachment metadata and thumbnails when deleting attachments --- src/com/fsck/k9/mail/store/LocalStore.java | 28 +++++++++++++------ .../fsck/k9/provider/AttachmentProvider.java | 28 +++++++++++++++++-- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java index abfa3ed1d..38130c509 100644 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ b/src/com/fsck/k9/mail/store/LocalStore.java @@ -2692,22 +2692,34 @@ public class LocalStore extends Store implements Serializable { public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException { Cursor attachmentsCursor = null; try { - attachmentsCursor = db.query("attachments", new String[] - { "id" }, "message_id = ?", new String[] - { Long.toString(messageId) }, null, null, null); + String accountUuid = mAccount.getUuid(); + Context context = mApplication; + + // Get attachment IDs + String[] whereArgs = new String[] { Long.toString(messageId) }; + attachmentsCursor = db.query("attachments", new String[] { "id" }, + "message_id = ?", whereArgs, null, null, null); + final File attachmentDirectory = StorageManager.getInstance(mApplication) - .getAttachmentDirectory(uUid, database.getStorageProviderId()); + .getAttachmentDirectory(uUid, database.getStorageProviderId()); + while (attachmentsCursor.moveToNext()) { - long attachmentId = attachmentsCursor.getLong(0); + String attachmentId = Long.toString(attachmentsCursor.getLong(0)); try { - File file = new File(attachmentDirectory, Long.toString(attachmentId)); + // Delete stored attachment + File file = new File(attachmentDirectory, attachmentId); if (file.exists()) { file.delete(); } - } catch (Exception e) { - } + // Delete thumbnail file + AttachmentProvider.deleteThumbnail(context, accountUuid, + attachmentId); + } catch (Exception e) { /* ignore */ } } + + // Delete attachment metadata from the database + db.delete("attachments", "message_id = ?", whereArgs); } finally { Utility.closeQuietly(attachmentsCursor); } diff --git a/src/com/fsck/k9/provider/AttachmentProvider.java b/src/com/fsck/k9/provider/AttachmentProvider.java index 4b90305c7..dd380e6af 100644 --- a/src/com/fsck/k9/provider/AttachmentProvider.java +++ b/src/com/fsck/k9/provider/AttachmentProvider.java @@ -92,6 +92,30 @@ public class AttachmentProvider extends ContentProvider { } } + /** + * Delete the thumbnail of an attachment. + * + * @param context + * The application context. + * @param accountUuid + * The UUID of the account the attachment belongs to. + * @param attachmentId + * The ID of the attachment the thumbnail was created for. + */ + public static void deleteThumbnail(Context context, String accountUuid, String attachmentId) { + File file = getThumbnailFile(context, accountUuid, attachmentId); + if (file.exists()) { + file.delete(); + } + } + + private static File getThumbnailFile(Context context, String accountUuid, + String attachmentId) { + String filename = "thmb_" + accountUuid + "_" + attachmentId + ".tmp"; + File dir = context.getCacheDir(); + return new File(dir, filename); + } + @Override public boolean onCreate() { @@ -139,9 +163,7 @@ public class AttachmentProvider extends ContentProvider { int width = Integer.parseInt(segments.get(3)); int height = Integer.parseInt(segments.get(4)); - String filename = "thmb_" + accountUuid + "_" + attachmentId + ".tmp"; - File dir = getContext().getCacheDir(); - file = new File(dir, filename); + file = getThumbnailFile(getContext(), accountUuid, attachmentId); if (!file.exists()) { String type = getType(accountUuid, attachmentId, FORMAT_VIEW); try { From aae734c175b630db9654ec221b1210f772a02397 Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 24 Jan 2012 22:14:21 +0100 Subject: [PATCH 05/15] Don't Log.w() full stacktrace if file wasn't found This happens regularly when AttachmentView tries to get a thumbnail for attachments that haven't been downloaded yet. --- .../fsck/k9/provider/AttachmentProvider.java | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/com/fsck/k9/provider/AttachmentProvider.java b/src/com/fsck/k9/provider/AttachmentProvider.java index dd380e6af..ec81e30ba 100644 --- a/src/com/fsck/k9/provider/AttachmentProvider.java +++ b/src/com/fsck/k9/provider/AttachmentProvider.java @@ -278,20 +278,17 @@ public class AttachmentProvider extends ContentProvider { } private File getFile(String dbName, String id) throws FileNotFoundException { - try { - final Account account = Preferences.getPreferences(getContext()).getAccount(dbName); - final File attachmentsDir; - attachmentsDir = StorageManager.getInstance(K9.app).getAttachmentDirectory(dbName, - account.getLocalStorageProviderId()); - final File file = new File(attachmentsDir, id); - if (!file.exists()) { - throw new FileNotFoundException(file.getAbsolutePath()); - } - return file; - } catch (IOException e) { - Log.w(K9.LOG_TAG, null, e); - throw new FileNotFoundException(e.getMessage()); + Account account = Preferences.getPreferences(getContext()).getAccount(dbName); + + File attachmentsDir = StorageManager.getInstance(K9.app).getAttachmentDirectory(dbName, + account.getLocalStorageProviderId()); + + File file = new File(attachmentsDir, id); + if (!file.exists()) { + throw new FileNotFoundException(file.getAbsolutePath()); } + + return file; } private Bitmap createThumbnail(String type, InputStream data) { From 5a8ddaa039ae325bb80f1cc3542f497bd2e5415d Mon Sep 17 00:00:00 2001 From: cketti Date: Thu, 26 Jan 2012 00:37:25 +0100 Subject: [PATCH 06/15] Make sure draft id points to a valid message before deleting it Avoids IllegalArgumentException in LocalStore.getMessage() --- src/com/fsck/k9/activity/MessageCompose.java | 5 +++-- src/com/fsck/k9/controller/MessagingController.java | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java index 6da95c263..2eac71f19 100644 --- a/src/com/fsck/k9/activity/MessageCompose.java +++ b/src/com/fsck/k9/activity/MessageCompose.java @@ -2988,9 +2988,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc } MessagingController.getInstance(getApplication()).sendMessage(mAccount, message, null); - if (mDraftId != INVALID_DRAFT_ID) { - MessagingController.getInstance(getApplication()).deleteDraft(mAccount, mDraftId); + long draftId = mDraftId; + if (draftId != INVALID_DRAFT_ID) { mDraftId = INVALID_DRAFT_ID; + MessagingController.getInstance(getApplication()).deleteDraft(mAccount, draftId); } return null; diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index 2aaa48ae1..b3b6b5462 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -3311,9 +3311,11 @@ public class MessagingController implements Runnable { localFolder = localStore.getFolder(account.getDraftsFolderName()); localFolder.open(OpenMode.READ_WRITE); String uid = localFolder.getMessageUidById(id); - Message message = localFolder.getMessage(uid); - if (message != null) { - deleteMessages(new Message[] { message }, null); + if (uid != null) { + Message message = localFolder.getMessage(uid); + if (message != null) { + deleteMessages(new Message[] { message }, null); + } } } catch (MessagingException me) { addErrorMessage(account, null, me); From e8eae3738963cc5f14c8750197fea1423e8818e1 Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 27 Jan 2012 00:51:18 +0100 Subject: [PATCH 07/15] Reset unread/flagged count on "empty trash" --- src/com/fsck/k9/controller/MessagingController.java | 5 +++-- src/com/fsck/k9/mail/store/LocalStore.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index b3b6b5462..389e6f2a4 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -3470,12 +3470,13 @@ public class MessagingController implements Runnable { putBackground("emptyTrash", listener, new Runnable() { @Override public void run() { - Folder localFolder = null; + LocalFolder localFolder = null; try { Store localStore = account.getLocalStore(); - localFolder = localStore.getFolder(account.getTrashFolderName()); + localFolder = (LocalFolder) localStore.getFolder(account.getTrashFolderName()); localFolder.open(OpenMode.READ_WRITE); localFolder.setFlags(new Flag[] { Flag.DELETED }, true); + localFolder.resetUnreadAndFlaggedCounts(); for (MessagingListener l : getListeners()) { l.emptyTrashCompleted(account); diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java index 38130c509..049f4222e 100644 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ b/src/com/fsck/k9/mail/store/LocalStore.java @@ -2619,7 +2619,7 @@ public class LocalStore extends Store implements Serializable { setVisibleLimit(mAccount.getDisplayCount()); } - private void resetUnreadAndFlaggedCounts() { + public void resetUnreadAndFlaggedCounts() { try { int newUnread = 0; int newFlagged = 0; From 193450cd63086e11b4822b3b3b13d663a47c1bb3 Mon Sep 17 00:00:00 2001 From: wilian-cb Date: Thu, 26 Jan 2012 19:25:46 -0200 Subject: [PATCH 08/15] 3674: Illegal characters used in file names are being removed when saving them on the device. --- src/com/fsck/k9/view/AttachmentView.java | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/com/fsck/k9/view/AttachmentView.java b/src/com/fsck/k9/view/AttachmentView.java index 9e9a4c441..764663cbe 100644 --- a/src/com/fsck/k9/view/AttachmentView.java +++ b/src/com/fsck/k9/view/AttachmentView.java @@ -52,6 +52,13 @@ public class AttachmentView extends FrameLayout { public String contentType; public long size; public ImageView iconView; + + /** + * Regular expression that represents characters that aren't allowed + * to be used in file names saved using K-9 + */ + private static final String specialCharacters = new String("[^\\d\\s\\w!" + + "#\\$%&'\\(\\)\\-@\\^_`\\{\\}~.,]"); private AttachmentFileDownloadCallback callback; @@ -196,7 +203,8 @@ public class AttachmentView extends FrameLayout { */ public void writeFile(File directory) { try { - File file = Utility.createUniqueFile(directory, name); + String filename = removeSpecialCharacters(name); + File file = Utility.createUniqueFile(directory, filename); Uri uri = AttachmentProvider.getAttachmentUri(mAccount, part.getAttachmentId()); InputStream in = mContext.getContentResolver().openInputStream(uri); OutputStream out = new FileOutputStream(file); @@ -204,12 +212,24 @@ public class AttachmentView extends FrameLayout { out.flush(); out.close(); in.close(); - attachmentSaved(file.toString()); + attachmentSaved(filename.toString()); new MediaScannerNotifier(mContext, file); } catch (IOException ioe) { attachmentNotSaved(); } } + + /** + * Removes characters that aren't allowed to be used in file names saved + * in K-9 application. + * + * @param filename The original file name. + * @return A file name with only legal characters. + */ + private String removeSpecialCharacters(String filename) { + return filename.replaceAll(specialCharacters, ""); + } + /** * saves the file to the defaultpath setting in the config, or if the config * is not set => to the Environment From 9a0f650cd95c93e59f7b21ee38892c26b4d2e9ff Mon Sep 17 00:00:00 2001 From: wilian-cb Date: Thu, 26 Jan 2012 20:53:41 -0200 Subject: [PATCH 09/15] 3674: Displaying the final file name. --- src/com/fsck/k9/view/AttachmentView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/fsck/k9/view/AttachmentView.java b/src/com/fsck/k9/view/AttachmentView.java index 764663cbe..7525456fd 100644 --- a/src/com/fsck/k9/view/AttachmentView.java +++ b/src/com/fsck/k9/view/AttachmentView.java @@ -212,7 +212,7 @@ public class AttachmentView extends FrameLayout { out.flush(); out.close(); in.close(); - attachmentSaved(filename.toString()); + attachmentSaved(file.toString()); new MediaScannerNotifier(mContext, file); } catch (IOException ioe) { attachmentNotSaved(); From 68f5f009f1548efbcb87c4cb837d1201eeaf761c Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 27 Jan 2012 03:07:44 +0100 Subject: [PATCH 10/15] Whitespace cleanup --- src/com/fsck/k9/view/AttachmentView.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/fsck/k9/view/AttachmentView.java b/src/com/fsck/k9/view/AttachmentView.java index 7525456fd..0a851e658 100644 --- a/src/com/fsck/k9/view/AttachmentView.java +++ b/src/com/fsck/k9/view/AttachmentView.java @@ -52,13 +52,13 @@ public class AttachmentView extends FrameLayout { public String contentType; public long size; public ImageView iconView; - + /** * Regular expression that represents characters that aren't allowed * to be used in file names saved using K-9 */ private static final String specialCharacters = new String("[^\\d\\s\\w!" + - "#\\$%&'\\(\\)\\-@\\^_`\\{\\}~.,]"); + "#\\$%&'\\(\\)\\-@\\^_`\\{\\}~.,]"); private AttachmentFileDownloadCallback callback; @@ -222,12 +222,12 @@ public class AttachmentView extends FrameLayout { /** * Removes characters that aren't allowed to be used in file names saved * in K-9 application. - * + * * @param filename The original file name. * @return A file name with only legal characters. */ private String removeSpecialCharacters(String filename) { - return filename.replaceAll(specialCharacters, ""); + return filename.replaceAll(specialCharacters, ""); } /** From 6c23e204baa21d74bec9a6099956061da58116e8 Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 27 Jan 2012 03:21:20 +0100 Subject: [PATCH 11/15] Replace invalid characters in file name instead of removing them --- src/com/fsck/k9/view/AttachmentView.java | 34 ++++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/com/fsck/k9/view/AttachmentView.java b/src/com/fsck/k9/view/AttachmentView.java index 0a851e658..8621aa7a9 100644 --- a/src/com/fsck/k9/view/AttachmentView.java +++ b/src/com/fsck/k9/view/AttachmentView.java @@ -39,6 +39,18 @@ import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBodyPart; import com.fsck.k9.provider.AttachmentProvider; public class AttachmentView extends FrameLayout { + /** + * Regular expression that represents characters that aren't allowed + * to be used in file names saved using K-9 + */ + private static final String INVALID_CHARACTERS = "[^\\d\\s\\w!" + + "#\\$%&'\\(\\)\\-@\\^_`\\{\\}~.,]+"; + + /** + * Invalid characters in a file name are replaced by this character. + */ + private static final String REPLACEMENT_CHARACTER = "_"; + private Context mContext; public Button viewButton; @@ -53,13 +65,6 @@ public class AttachmentView extends FrameLayout { public long size; public ImageView iconView; - /** - * Regular expression that represents characters that aren't allowed - * to be used in file names saved using K-9 - */ - private static final String specialCharacters = new String("[^\\d\\s\\w!" + - "#\\$%&'\\(\\)\\-@\\^_`\\{\\}~.,]"); - private AttachmentFileDownloadCallback callback; public AttachmentView(Context context, AttributeSet attrs, int defStyle) { @@ -203,7 +208,7 @@ public class AttachmentView extends FrameLayout { */ public void writeFile(File directory) { try { - String filename = removeSpecialCharacters(name); + String filename = sanitizeFilename(name); File file = Utility.createUniqueFile(directory, filename); Uri uri = AttachmentProvider.getAttachmentUri(mAccount, part.getAttachmentId()); InputStream in = mContext.getContentResolver().openInputStream(uri); @@ -220,14 +225,15 @@ public class AttachmentView extends FrameLayout { } /** - * Removes characters that aren't allowed to be used in file names saved - * in K-9 application. + * Replace characters we don't allow in file names with a replacement character. * - * @param filename The original file name. - * @return A file name with only legal characters. + * @param filename + * The original file name. + * + * @return The sanitized file name containing only allowed characters. */ - private String removeSpecialCharacters(String filename) { - return filename.replaceAll(specialCharacters, ""); + private String sanitizeFilename(String filename) { + return filename.replaceAll(INVALID_CHARACTERS, REPLACEMENT_CHARACTER); } /** From 1165787129e27877f4d61099d9e41e490b9886a4 Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 27 Jan 2012 03:39:08 +0100 Subject: [PATCH 12/15] Changed regular expression for invalid characters in a file name --- src/com/fsck/k9/view/AttachmentView.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/com/fsck/k9/view/AttachmentView.java b/src/com/fsck/k9/view/AttachmentView.java index 8621aa7a9..bb736f6cc 100644 --- a/src/com/fsck/k9/view/AttachmentView.java +++ b/src/com/fsck/k9/view/AttachmentView.java @@ -40,11 +40,19 @@ import com.fsck.k9.provider.AttachmentProvider; public class AttachmentView extends FrameLayout { /** - * Regular expression that represents characters that aren't allowed - * to be used in file names saved using K-9 + * Regular expression that represents characters we won't allow in file names. + * + *

+ * Allowed are: + *

    + *
  • word characters (letters, digits, and underscores): {@code \w}
  • + *
  • spaces: {@code " "}
  • + *
  • special characters: {@code !}, {@code #}, {@code $}, {@code %}, {@code &}, {@code '}, + * {@code (}, {@code )}, {@code -}, {@code @}, {@code ^}, {@code `}, {, + * }, {@code ~}, {@code .}, {@code ,}
  • + *

*/ - private static final String INVALID_CHARACTERS = "[^\\d\\s\\w!" + - "#\\$%&'\\(\\)\\-@\\^_`\\{\\}~.,]+"; + private static final String INVALID_CHARACTERS = "[^\\w !#$%&'()\\-@\\^`{}~.,]+"; /** * Invalid characters in a file name are replaced by this character. From b1a1de8f7b829e8a07e74c5e79eeb1b29bb19d42 Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 27 Jan 2012 08:39:10 +0100 Subject: [PATCH 13/15] Restore mark as unread in message view Fixes issue 3958 Fixes issue 3319 --- src/com/fsck/k9/activity/MessageView.java | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/com/fsck/k9/activity/MessageView.java b/src/com/fsck/k9/activity/MessageView.java index fb6afcc60..64f4c9208 100644 --- a/src/com/fsck/k9/activity/MessageView.java +++ b/src/com/fsck/k9/activity/MessageView.java @@ -20,6 +20,7 @@ import com.fsck.k9.crypto.PgpData; import com.fsck.k9.helper.FileBrowserHelper; import com.fsck.k9.helper.FileBrowserHelper.FileBrowserFailOverCallback; import com.fsck.k9.mail.*; +import com.fsck.k9.mail.store.LocalStore.LocalMessage; import com.fsck.k9.mail.store.StorageManager; import com.fsck.k9.view.AttachmentView; import com.fsck.k9.view.ToggleScrollView; @@ -726,10 +727,15 @@ public class MessageView extends K9Activity implements OnClickListener { private void onFlag() { if (mMessage != null) { - mController.setFlag(mAccount, - mMessage.getFolder().getName(), new String[] {mMessage.getUid()}, Flag.FLAGGED, !mMessage.isSet(Flag.FLAGGED)); + boolean newState = !mMessage.isSet(Flag.FLAGGED); + mController.setFlag(mAccount, mMessage.getFolder().getName(), + new String[] {mMessage.getUid()}, Flag.FLAGGED, newState); try { - mMessage.setFlag(Flag.FLAGGED, !mMessage.isSet(Flag.FLAGGED)); + // FIXME: This is a hack to change the flagged state of our message object. We + // can't call Message.setFlag() because that would "adjust" the flagged count + // another time (first time by MessagingController.setFlag(...)). + ((LocalMessage)mMessage).setFlagInternal(Flag.FLAGGED, newState); + mMessageView.setHeaders(mMessage, mAccount); } catch (MessagingException me) { Log.e(K9.LOG_TAG, "Could not set flag on local message", me); @@ -876,9 +882,13 @@ public class MessageView extends K9Activity implements OnClickListener { private void onMarkAsUnread() { if (mMessage != null) { -// (Issue 3319) mController.setFlag(mAccount, mMessageReference.folderName, new String[] { mMessage.getUid() }, Flag.SEEN, false); + mController.setFlag(mAccount, mMessage.getFolder().getName(), + new String[] { mMessage.getUid() }, Flag.SEEN, false); try { - mMessage.setFlag(Flag.SEEN, false); + // FIXME: This is a hack to mark our message object as unread. We can't call + // Message.setFlag() because that would "adjust" the unread count twice. + ((LocalMessage)mMessage).setFlagInternal(Flag.SEEN, false); + mMessageView.setHeaders(mMessage, mAccount); String subject = mMessage.getSubject(); setTitle(subject); From 35b5aebdb322fa44e2c8173dbd9a5f5ef3c51c36 Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 3 Feb 2012 01:22:37 +0100 Subject: [PATCH 14/15] Add debug message when saving an attachment to SD card fails --- src/com/fsck/k9/view/AttachmentView.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/fsck/k9/view/AttachmentView.java b/src/com/fsck/k9/view/AttachmentView.java index bb736f6cc..f581c3db2 100644 --- a/src/com/fsck/k9/view/AttachmentView.java +++ b/src/com/fsck/k9/view/AttachmentView.java @@ -228,6 +228,9 @@ public class AttachmentView extends FrameLayout { attachmentSaved(file.toString()); new MediaScannerNotifier(mContext, file); } catch (IOException ioe) { + if (K9.DEBUG) { + Log.e(K9.LOG_TAG, "Error saving attachment", ioe); + } attachmentNotSaved(); } } From 46bf2c5be7e9d3097da736d8448ddd325aae8702 Mon Sep 17 00:00:00 2001 From: Nick Nikolaou Date: Thu, 2 Feb 2012 21:56:56 +0000 Subject: [PATCH 15/15] Add discard confirmation dialog when pressing back --- res/values/strings.xml | 3 ++ src/com/fsck/k9/activity/MessageCompose.java | 42 +++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index f2666ff53..9fd5973aa 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1030,6 +1030,9 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin Save draft message? Save or Discard this message? + Discard message? + Are you sure you want to discard this message? + Refuse to save draft message. Refuse to save draft message marked encrypted. diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java index 2eac71f19..a24423eb3 100644 --- a/src/com/fsck/k9/activity/MessageCompose.java +++ b/src/com/fsck/k9/activity/MessageCompose.java @@ -83,6 +83,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc private static final int DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE = 1; private static final int DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED = 2; private static final int DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY = 3; + private static final int DIALOG_CONFIRM_DISCARD_ON_BACK = 4; private static final long INVALID_DRAFT_ID = MessagingController.INVALID_MESSAGE_ID; @@ -2051,13 +2052,21 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc @Override public void onBackPressed() { - if (mEncryptCheckbox.isChecked()) { - showDialog(DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED); - } else if (!mDraftNeedsSaving || isDraftsFolderDisabled()) { - Toast.makeText(MessageCompose.this, getString(R.string.message_discarded_toast), Toast.LENGTH_LONG).show(); - super.onBackPressed(); + if (mDraftNeedsSaving) { + if (mEncryptCheckbox.isChecked()) { + showDialog(DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED); + } else if (isDraftsFolderDisabled()) { + showDialog(DIALOG_CONFIRM_DISCARD_ON_BACK); + } else { + showDialog(DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE); + } } else { - showDialog(DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE); + // Check if editing an existing draft. + if (mDraftId == INVALID_DRAFT_ID) { + onDiscard(); + } else { + super.onBackPressed(); + } } } @@ -2118,6 +2127,27 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc } }) .create(); + case DIALOG_CONFIRM_DISCARD_ON_BACK: + return new AlertDialog.Builder(this) + .setTitle(R.string.confirm_discard_draft_message_title) + .setMessage(R.string.confirm_discard_draft_message) + .setPositiveButton(R.string.cancel_action, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + dismissDialog(DIALOG_CONFIRM_DISCARD_ON_BACK); + } + }) + .setNegativeButton(R.string.discard_action, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + dismissDialog(DIALOG_CONFIRM_DISCARD_ON_BACK); + Toast.makeText(MessageCompose.this, + getString(R.string.message_discarded_toast), + Toast.LENGTH_LONG).show(); + onDiscard(); + } + }) + .create(); } return super.onCreateDialog(id); }