From 6c84e196aa9ddd37f33c57bcb189f9e3cca590a3 Mon Sep 17 00:00:00 2001
From: Apoorv Khatreja
Date: Tue, 21 Jun 2011 02:56:53 +0530
Subject: [PATCH 01/80] Astyle is seriously getting on my nerves. I'm
committing this with nothing but astyle changes so that forthcoming commits
are clean.
---
.../k9/activity/setup/AccountSettings.java | 4 ++--
src/com/fsck/k9/mail/internet/MimeUtility.java | 18 +++++++++---------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java
index 38c9e38e0..1032291f6 100644
--- a/src/com/fsck/k9/activity/setup/AccountSettings.java
+++ b/src/com/fsck/k9/activity/setup/AccountSettings.java
@@ -884,8 +884,8 @@ public class AccountSettings extends K9PreferenceActivity {
}
}
- allFolderValues = new String[folders.size()+1];
- allFolderLabels = new String[folders.size()+1];
+ allFolderValues = new String[folders.size() + 1];
+ allFolderLabels = new String[folders.size() + 1];
allFolderValues[0] = K9.FOLDER_NONE;
allFolderLabels[0] = K9.FOLDER_NONE;
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 0fd320c0a..54040a364 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -1076,7 +1076,7 @@ public class MimeUtility {
*/
if (contentTransferEncoding != null) {
contentTransferEncoding =
- MimeUtility.getHeaderParameter(contentTransferEncoding, null);
+ MimeUtility.getHeaderParameter(contentTransferEncoding, null);
if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) {
in = new QuotedPrintableInputStream(in);
} else if ("base64".equalsIgnoreCase(contentTransferEncoding)) {
@@ -1102,7 +1102,7 @@ public class MimeUtility {
* @throws MessagingException
*/
public static void collectParts(Part part, ArrayList viewables,
- ArrayList attachments) throws MessagingException {
+ ArrayList attachments) throws MessagingException {
/*
* If the part is Multipart but not alternative it's either mixed or
* something we don't know about, which means we treat it as mixed
@@ -1326,10 +1326,10 @@ public class MimeUtility {
private static String getJisVariantFromAddress(String address) {
if (isInDomain(address, "docomo.ne.jp") || isInDomain(address, "dwmail.jp") ||
- isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com"))
+ isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com"))
return "docomo";
else if (isInDomain(address, "softbank.ne.jp") || isInDomain(address, "vodafone.ne.jp") ||
- isInDomain(address, "disney.ne.jp") || isInDomain(address, "vertuclub.ne.jp"))
+ isInDomain(address, "disney.ne.jp") || isInDomain(address, "vertuclub.ne.jp"))
return "softbank";
else if (isInDomain(address, "ezweb.ne.jp") || isInDomain(address, "ido.ne.jp"))
return "kddi";
@@ -1364,14 +1364,14 @@ public class MimeUtility {
// iso-2022-jp variants are supported by no versions as of Dec 2010.
if (charset.length() > 19 && charset.startsWith("x-") &&
- charset.endsWith("-iso-2022-jp-2007") && !Charset.isSupported(charset)) {
+ charset.endsWith("-iso-2022-jp-2007") && !Charset.isSupported(charset)) {
in = new Iso2022JpToShiftJisInputStream(in);
charset = "x-" + charset.substring(2, charset.length() - 17) + "-shift_jis-2007";
}
// shift_jis variants are supported by Eclair and later.
if (charset.length() > 17 && charset.startsWith("x-") &&
- charset.endsWith("-shift_jis-2007") && !Charset.isSupported(charset)) {
+ charset.endsWith("-shift_jis-2007") && !Charset.isSupported(charset)) {
// If the JIS variant is iPhone, map the Unicode private use area in iPhone to the one in Android after
// converting the character set from the standard Shift JIS to Unicode.
if (charset.substring(2, charset.length() - 15).equals("iphone"))
@@ -1392,7 +1392,7 @@ public class MimeUtility {
}
if (!supported) {
Log.e(K9.LOG_TAG, "I don't know how to deal with the charset " + charset +
- ". Falling back to US-ASCII");
+ ". Falling back to US-ASCII");
charset = "US-ASCII";
}
/*
@@ -2393,12 +2393,12 @@ public class MimeUtility {
public static void setCharset(String charset, Part part) throws MessagingException {
part.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
- part.getMimeType() + ";\n charset=" + getExternalCharset(charset));
+ part.getMimeType() + ";\n charset=" + getExternalCharset(charset));
}
public static String getExternalCharset(String charset) {
if (charset.length() > 17 && charset.startsWith("x-") &&
- charset.endsWith("-shift_jis-2007"))
+ charset.endsWith("-shift_jis-2007"))
return "shift_jis";
return charset;
From 970271dbf943e6a71dcb262832c2eaff5880b7cb Mon Sep 17 00:00:00 2001
From: Apoorv Khatreja
Date: Tue, 21 Jun 2011 04:34:57 +0530
Subject: [PATCH 02/80] If the response for an APPEND command contains the
APPENDUID response code, read the UID of the newly appended message from
there.
---
src/com/fsck/k9/mail/store/ImapStore.java | 26 +++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index b639a11f2..f37e44de8 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -52,6 +52,7 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.PowerManager;
+import android.text.TextUtils;
import android.util.Log;
import com.beetstra.jutf7.CharsetProvider;
@@ -1617,6 +1618,31 @@ public class ImapStore extends Store {
while (response.more());
} while (response.mTag == null);
+ /*
+ * If the server supports UIDPLUS, then along with the APPEND response it will return an APPENDUID response code.
+ * e.g. 11 OK [APPENDUID 2 238268] APPEND completed
+ *
+ * We can use the UID included in this response to update our records.
+ *
+ * Code imported from AOSP Email as of git rev a5c3744a247e432acf9f571a9dfb55321c4baa1a
+ */
+ Object responseList = response.get(1);
+
+ if (responseList instanceof ImapList) {
+ final ImapList appendList = (ImapList) responseList;
+ if ((appendList.size() >= 3) && appendList.getString(0).equals("APPENDUID")) {
+ String serverUid = appendList.getString(2);
+ if (!TextUtils.isEmpty(serverUid)) {
+ message.setUid(serverUid);
+ continue;
+ }
+ }
+ }
+
+
+ /*
+ * This part is executed in case the server does not support UIDPLUS or does not implement the APPENDUID response code.
+ */
String newUid = getUidFromMessageId(message);
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Got UID " + newUid + " for message for " + getLogId());
From 0ba7f206225d4f9c71e83cf94f1bf74ca27aa5aa Mon Sep 17 00:00:00 2001
From: Apoorv Khatreja
Date: Fri, 24 Jun 2011 02:54:12 +0530
Subject: [PATCH 03/80] Attempt to implement COPYUID, works for the most part
except for updation of the LocalStore with freshly copied messages.
---
src/com/fsck/k9/mail/store/ImapStore.java | 130 ++++++++++++++++++++--
1 file changed, 122 insertions(+), 8 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index f37e44de8..8824e0988 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -29,6 +29,7 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -39,7 +40,9 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.SortedSet;
import java.util.StringTokenizer;
+import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -813,8 +816,24 @@ public class ImapStore extends Store {
ImapFolder iFolder = (ImapFolder)folder;
checkOpen();
+
+ SortedSet messageSet = new TreeSet(new Comparator() {
+ public int compare(Message m1, Message m2) {
+ int uid1 = Integer.parseInt(m1.getUid()), uid2 = Integer.parseInt(m2.getUid());
+ if (uid1 < uid2) {
+ return -1;
+ } else if (uid1 == uid2) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ });
String[] uids = new String[messages.length];
for (int i = 0, count = messages.length; i < count; i++) {
+ messageSet.add(messages[i]);
+
+ // Not bothering to sort the UIDs in ascending order while sending the command for convenience, and because it does not make a difference.
uids[i] = messages[i].getUid();
}
try {
@@ -829,20 +848,104 @@ public class ImapStore extends Store {
iFolder.create(FolderType.HOLDS_MESSAGES);
}
- if (exists(remoteDestName)) {
- executeSimpleCommand(String.format("UID COPY %s %s",
- Utility.combine(uids, ','),
- remoteDestName));
- } else {
- throw new MessagingException("IMAPMessage.copyMessages: remote destination folder " + folder.getName()
- + " does not exist and could not be created for " + getLogId()
- , true);
+ mConnection.sendCommand(String.format("UID COPY %s %s",
+ Utility.combine(uids, ','),
+ remoteDestName), false);
+ ImapResponse response;
+ do {
+ response = mConnection.readResponse();
+ handleUntaggedResponse(response);
+ if (response.mCommandContinuationRequested) {
+ EOLConvertingOutputStream eolOut = new EOLConvertingOutputStream(mConnection.mOut);
+ eolOut.write('\r');
+ eolOut.write('\n');
+ eolOut.flush();
+ }
+ while (response.more());
+ } while (response.mTag == null);
+
+ /*
+ * If the server supports UIDPLUS, then along with the COPY response it will return an COPYUID response code.
+ * e.g. 24 OK [COPYUID 38505 304,319:320 3956:3958] Success
+ *
+ * COPYUID is followed by UIDVALIDITY, set of UIDs of copied messages from the source folder and set of corresponding UIDs assigned to them in the destination folder.
+ *
+ * We can use the new UIDs included in this response to update our records.
+ */
+
+ Object responseList = response.get(1);
+
+ if (responseList instanceof ImapList) {
+ final ImapList copyList = (ImapList) responseList;
+ if ((copyList.size() >= 4) && copyList.getString(0).equals("COPYUID")) {
+ List oldUids = parseSequenceSet(copyList.getString(2));
+ List newUids = parseSequenceSet(copyList.getString(3));
+ if (oldUids.size() == newUids.size()) {
+ Iterator messageIterator = messageSet.iterator();
+ for (int i = 0; i < messages.length && messageIterator.hasNext(); i++) {
+ Message nextMessage = messageIterator.next();
+ if (oldUids.get(i).equals(nextMessage.getUid())) {
+ /*
+ * Here, we need to *create* new messages in the localstore, same as the older messages, the only changes are that old UIDs need to be swapped with new UIDs,
+ * and old folder swapped with new folder.
+ */
+// nextMessage.setUid(newUids.get(i));
+ }
+ }
+ }
+ }
}
} catch (IOException ioe) {
throw ioExceptionHandler(mConnection, ioe);
}
}
+ private List parseSequenceSet(String set) {
+ int index = 0;
+ List sequenceList = new ArrayList();
+ String element = "";
+
+ while (index < set.length()) {
+ if (set.charAt(index) == ':') {
+ String upperBound = "";
+ index++;
+ while (index < set.length()) {
+ if (!(set.charAt(index) == ',')) {
+ upperBound += set.charAt(index);
+ index++;
+ } else {
+ break;
+ }
+ }
+
+ int lower = Integer.parseInt(element);
+ int upper = Integer.parseInt(upperBound);
+
+ if (lower < upper) {
+ for (int i = lower; i <= upper; i++) {
+ sequenceList.add(String.valueOf(i));
+ }
+ } else {
+ for (int i = upper; i <= lower; i++) {
+ sequenceList.add(String.valueOf(i));
+ }
+ }
+
+ element = "";
+ } else if (set.charAt(index) == ',') {
+ sequenceList.add(element);
+ element = "";
+ } else {
+ element += set.charAt(index);
+ }
+ index++;
+ }
+ if (!element.equals("")) {
+ sequenceList.add(element);
+ }
+ return sequenceList;
+ }
+
@Override
public void moveMessages(Message[] messages, Folder folder) throws MessagingException {
if (messages.length == 0)
@@ -2290,6 +2393,17 @@ public class ImapStore extends Store {
return executeSimpleCommand(command, sensitive, null);
}
+// public void logResponse (ImapList response) {
+// for(int i=0;i executeSimpleCommand(String command, boolean sensitive, UntaggedHandler untaggedHandler)
throws IOException, ImapException, MessagingException {
String commandToLog = command;
From bc9b7030d7d250c61b7bf8b624c6fa84c0363dd3 Mon Sep 17 00:00:00 2001
From: Apoorv Khatreja
Date: Tue, 28 Jun 2011 16:50:48 +0530
Subject: [PATCH 04/80] COPYUID implementation now in place and working,
restructured appendMessages, copyMessages and moveMessages globally to return
a Map of srcUids -> destUids rather than returning nothing. This is now used
to bring local and remote UIDs upto speed without the need for additional
requests.
---
.../k9/controller/MessagingController.java | 94 ++++++++++++++++---
src/com/fsck/k9/mail/Folder.java | 11 ++-
src/com/fsck/k9/mail/store/ImapStore.java | 83 ++++++++--------
src/com/fsck/k9/mail/store/LocalStore.java | 30 ++++--
src/com/fsck/k9/mail/store/Pop3Store.java | 4 +-
src/com/fsck/k9/mail/store/WebDavStore.java | 10 +-
6 files changed, 163 insertions(+), 69 deletions(-)
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 079b72812..198f4b9a0 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -2088,9 +2088,32 @@ public class MessagingController implements Runnable {
command.arguments[0] = srcFolder;
command.arguments[1] = destFolder;
command.arguments[2] = Boolean.toString(isCopy);
- System.arraycopy(uids, 0, command.arguments, 3, uids.length);
+ command.arguments[3] = Boolean.toString(false);
+ System.arraycopy(uids, 0, command.arguments, 4, uids.length);
queuePendingCommand(account, command);
}
+
+ private void queueMoveOrCopy(Account account, String srcFolder, String destFolder, boolean isCopy, String uids[], Map uidMap) {
+ if (uidMap == null || uidMap.isEmpty()) {
+ queueMoveOrCopy(account, srcFolder, destFolder, isCopy, uids);
+ } else {
+ if (account.getErrorFolderName().equals(srcFolder)) {
+ return;
+ }
+ PendingCommand command = new PendingCommand();
+ command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK;
+
+ int length = 4 + uidMap.keySet().size() + uidMap.values().size();
+ command.arguments = new String[length];
+ command.arguments[0] = srcFolder;
+ command.arguments[1] = destFolder;
+ command.arguments[2] = Boolean.toString(isCopy);
+ command.arguments[3] = Boolean.toString(true);
+ System.arraycopy(uidMap.keySet().toArray(), 0, command.arguments, 4, uidMap.keySet().size());
+ System.arraycopy(uidMap.values().toArray(), 0, command.arguments, 4 + uidMap.keySet().size(), uidMap.values().size());
+ queuePendingCommand(account, command);
+ }
+ }
/**
* Process a pending trash message command.
*
@@ -2102,6 +2125,7 @@ public class MessagingController implements Runnable {
throws MessagingException {
Folder remoteSrcFolder = null;
Folder remoteDestFolder = null;
+ Folder localDestFolder = null;
try {
String srcFolder = command.arguments[0];
if (account.getErrorFolderName().equals(srcFolder)) {
@@ -2109,14 +2133,42 @@ public class MessagingController implements Runnable {
}
String destFolder = command.arguments[1];
String isCopyS = command.arguments[2];
+ String hasNewUidsS = command.arguments[3];
+
+ boolean hasNewUids = false;
+ if (hasNewUidsS != null) {
+ hasNewUids = Boolean.parseBoolean(hasNewUidsS);
+ }
+
Store remoteStore = account.getRemoteStore();
remoteSrcFolder = remoteStore.getFolder(srcFolder);
+ Store localStore = account.getLocalStore();
+ localDestFolder = localStore.getFolder(destFolder);
List messages = new ArrayList();
- for (int i = 3; i < command.arguments.length; i++) {
- String uid = command.arguments[i];
- if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
- messages.add(remoteSrcFolder.getMessage(uid));
+
+ /*
+ * We split up the localUidMap into two parts while sending the command, here we assemble it back.
+ */
+ Map localUidMap = new HashMap();
+ if (hasNewUids) {
+ int offset = (command.arguments.length - 4) / 2;
+
+ for (int i = 4; i < 4 + offset; i++) {
+ localUidMap.put(command.arguments[i], command.arguments[i + offset]);
+
+ String uid = command.arguments[i];
+ if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
+ messages.add(remoteSrcFolder.getMessage(uid));
+ }
+ }
+
+ } else {
+ for (int i = 4; i < command.arguments.length; i++) {
+ String uid = command.arguments[i];
+ if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
+ messages.add(remoteSrcFolder.getMessage(uid));
+ }
}
}
@@ -2137,6 +2189,8 @@ public class MessagingController implements Runnable {
Log.d(K9.LOG_TAG, "processingPendingMoveOrCopy: source folder = " + srcFolder
+ ", " + messages.size() + " messages, destination folder = " + destFolder + ", isCopy = " + isCopy);
+ Map remoteUidMap = new HashMap();
+
if (!isCopy && destFolder.equals(account.getTrashFolderName())) {
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "processingPendingMoveOrCopy doing special case for deleting message");
@@ -2150,9 +2204,9 @@ public class MessagingController implements Runnable {
remoteDestFolder = remoteStore.getFolder(destFolder);
if (isCopy) {
- remoteSrcFolder.copyMessages(messages.toArray(EMPTY_MESSAGE_ARRAY), remoteDestFolder);
+ remoteUidMap = remoteSrcFolder.copyMessages(messages.toArray(EMPTY_MESSAGE_ARRAY), remoteDestFolder);
} else {
- remoteSrcFolder.moveMessages(messages.toArray(EMPTY_MESSAGE_ARRAY), remoteDestFolder);
+ remoteUidMap = remoteSrcFolder.moveMessages(messages.toArray(EMPTY_MESSAGE_ARRAY), remoteDestFolder);
}
}
if (!isCopy && Account.EXPUNGE_IMMEDIATELY.equals(account.getExpungePolicy())) {
@@ -2161,12 +2215,27 @@ public class MessagingController implements Runnable {
remoteSrcFolder.expunge();
}
+
+ /*
+ * This next part is used to bring the local UIDs of the local destination folder
+ * upto speed with the remote UIDs of remote destionation folder.
+ */
+ if (!localUidMap.isEmpty() && !remoteUidMap.isEmpty()) {
+ Set remoteSrcUids = remoteUidMap.keySet();
+ Iterator remoteSrcUidsIterator = remoteSrcUids.iterator();
+
+ while (remoteSrcUidsIterator.hasNext()) {
+ String remoteSrcUid = remoteSrcUidsIterator.next();
+ String localDestUid = localUidMap.get(remoteSrcUid);
+
+ Message localDestMessage = localDestFolder.getMessage(localDestUid);
+ localDestMessage.setUid(remoteUidMap.get(remoteSrcUid));
+ }
+ }
} finally {
closeFolder(remoteSrcFolder);
closeFolder(remoteDestFolder);
}
-
-
}
private void queueSetFlag(final Account account, final String folderName, final String newState, final String flag, final String[] uids) {
@@ -3248,6 +3317,7 @@ public class MessagingController implements Runnable {
private void moveOrCopyMessageSynchronous(final Account account, final String srcFolder, final Message[] inMessages,
final String destFolder, final boolean isCopy, MessagingListener listener) {
try {
+ Map uidMap = new HashMap();
Store localStore = account.getLocalStore();
Store remoteStore = account.getRemoteStore();
if (!isCopy && (!remoteStore.isMoveCapable() || !localStore.isMoveCapable())) {
@@ -3285,9 +3355,9 @@ public class MessagingController implements Runnable {
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(FetchProfile.Item.BODY);
localSrcFolder.fetch(messages, fp, null);
- localSrcFolder.copyMessages(messages, localDestFolder);
+ uidMap = localSrcFolder.copyMessages(messages, localDestFolder);
} else {
- localSrcFolder.moveMessages(messages, localDestFolder);
+ uidMap = localSrcFolder.moveMessages(messages, localDestFolder);
for (String origUid : origUidMap.keySet()) {
for (MessagingListener l : getListeners()) {
l.messageUidChanged(account, srcFolder, origUid, origUidMap.get(origUid).getUid());
@@ -3296,7 +3366,7 @@ public class MessagingController implements Runnable {
}
}
- queueMoveOrCopy(account, srcFolder, destFolder, isCopy, origUidMap.keySet().toArray(EMPTY_STRING_ARRAY));
+ queueMoveOrCopy(account, srcFolder, destFolder, isCopy, origUidMap.keySet().toArray(EMPTY_STRING_ARRAY), uidMap);
}
processPendingCommands(account);
diff --git a/src/com/fsck/k9/mail/Folder.java b/src/com/fsck/k9/mail/Folder.java
index 0f5b96060..e3dafc3e5 100644
--- a/src/com/fsck/k9/mail/Folder.java
+++ b/src/com/fsck/k9/mail/Folder.java
@@ -1,6 +1,7 @@
package com.fsck.k9.mail;
import java.util.Date;
+import java.util.Map;
import android.util.Log;
import com.fsck.k9.Account;
@@ -102,11 +103,15 @@ public abstract class Folder {
public abstract Message[] getMessages(String[] uids, MessageRetrievalListener listener)
throws MessagingException;
- public abstract void appendMessages(Message[] messages) throws MessagingException;
+ public abstract Map appendMessages(Message[] messages) throws MessagingException;
- public void copyMessages(Message[] msgs, Folder folder) throws MessagingException {}
+ public Map copyMessages(Message[] msgs, Folder folder) throws MessagingException {
+ return null;
+ }
- public void moveMessages(Message[] msgs, Folder folder) throws MessagingException {}
+ public Map moveMessages(Message[] msgs, Folder folder) throws MessagingException {
+ return null;
+ }
public void delete(Message[] msgs, String trashFolderName) throws MessagingException {
for (Message message : msgs) {
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 8824e0988..b4da67248 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -29,7 +29,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -40,9 +39,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import java.util.SortedSet;
import java.util.StringTokenizer;
-import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -806,32 +803,19 @@ public class ImapStore extends Store {
}
@Override
- public void copyMessages(Message[] messages, Folder folder) throws MessagingException {
+ public Map copyMessages(Message[] messages, Folder folder) throws MessagingException {
if (!(folder instanceof ImapFolder)) {
throw new MessagingException("ImapFolder.copyMessages passed non-ImapFolder");
}
if (messages.length == 0)
- return;
+ return null;
ImapFolder iFolder = (ImapFolder)folder;
checkOpen();
- SortedSet messageSet = new TreeSet(new Comparator() {
- public int compare(Message m1, Message m2) {
- int uid1 = Integer.parseInt(m1.getUid()), uid2 = Integer.parseInt(m2.getUid());
- if (uid1 < uid2) {
- return -1;
- } else if (uid1 == uid2) {
- return 0;
- } else {
- return 1;
- }
- }
- });
String[] uids = new String[messages.length];
for (int i = 0, count = messages.length; i < count; i++) {
- messageSet.add(messages[i]);
// Not bothering to sort the UIDs in ascending order while sending the command for convenience, and because it does not make a difference.
uids[i] = messages[i].getUid();
@@ -875,31 +859,36 @@ public class ImapStore extends Store {
Object responseList = response.get(1);
+ Map uidMap = null;
+
if (responseList instanceof ImapList) {
final ImapList copyList = (ImapList) responseList;
if ((copyList.size() >= 4) && copyList.getString(0).equals("COPYUID")) {
- List oldUids = parseSequenceSet(copyList.getString(2));
- List newUids = parseSequenceSet(copyList.getString(3));
- if (oldUids.size() == newUids.size()) {
- Iterator messageIterator = messageSet.iterator();
- for (int i = 0; i < messages.length && messageIterator.hasNext(); i++) {
- Message nextMessage = messageIterator.next();
- if (oldUids.get(i).equals(nextMessage.getUid())) {
- /*
- * Here, we need to *create* new messages in the localstore, same as the older messages, the only changes are that old UIDs need to be swapped with new UIDs,
- * and old folder swapped with new folder.
- */
-// nextMessage.setUid(newUids.get(i));
- }
+ List srcUids = parseSequenceSet(copyList.getString(2));
+ List destUids = parseSequenceSet(copyList.getString(3));
+ if (srcUids.size() == destUids.size()) {
+ Iterator srcUidsIterator = srcUids.iterator();
+ Iterator destUidsIterator = destUids.iterator();
+ uidMap = new HashMap();
+ while (srcUidsIterator.hasNext() && destUidsIterator.hasNext()) {
+ uidMap.put(srcUidsIterator.next(), destUidsIterator.next());
}
}
}
}
+ return uidMap;
} catch (IOException ioe) {
throw ioExceptionHandler(mConnection, ioe);
}
}
+ /**
+ * Can be used to parse sequence sets or UID sets appearing is responses such as COPYUID.
+ * e.g. [COPYUID 38505 304,319:320 3956:3958]
+ *
+ * @param set
+ * @return List sequenceSet
+ */
private List parseSequenceSet(String set) {
int index = 0;
List sequenceList = new ArrayList();
@@ -947,11 +936,12 @@ public class ImapStore extends Store {
}
@Override
- public void moveMessages(Message[] messages, Folder folder) throws MessagingException {
+ public Map moveMessages(Message[] messages, Folder folder) throws MessagingException {
if (messages.length == 0)
- return;
- copyMessages(messages, folder);
+ return null;
+ Map uidMap = copyMessages(messages, folder);
setFlags(messages, new Flag[] { Flag.DELETED }, true);
+ return uidMap;
}
@Override
@@ -1698,9 +1688,10 @@ public class ImapStore extends Store {
* new server UID.
*/
@Override
- public void appendMessages(Message[] messages) throws MessagingException {
+ public Map appendMessages(Message[] messages) throws MessagingException {
checkOpen();
try {
+ Map uidMap = null;
for (Message message : messages) {
mConnection.sendCommand(
String.format("APPEND %s (%s) {%d}",
@@ -1734,9 +1725,18 @@ public class ImapStore extends Store {
if (responseList instanceof ImapList) {
final ImapList appendList = (ImapList) responseList;
if ((appendList.size() >= 3) && appendList.getString(0).equals("APPENDUID")) {
- String serverUid = appendList.getString(2);
- if (!TextUtils.isEmpty(serverUid)) {
- message.setUid(serverUid);
+ String newUid = appendList.getString(2);
+
+ /*
+ * We need uidMap to be null initially to maintain consistency with the behavior of other similar methods (copyMessages, moveMessages) which
+ * return null if new UIDs are not available. Therefore, we initialize uidMap over here.
+ */
+ if (uidMap == null) {
+ uidMap = new HashMap();
+ }
+ uidMap.put(message.getUid(), newUid);
+ if (!TextUtils.isEmpty(newUid)) {
+ message.setUid(newUid);
continue;
}
}
@@ -1751,11 +1751,14 @@ public class ImapStore extends Store {
Log.d(K9.LOG_TAG, "Got UID " + newUid + " for message for " + getLogId());
if (newUid != null) {
+ if (uidMap == null) {
+ uidMap = new HashMap();
+ }
+ uidMap.put(message.getUid(), newUid);
message.setUid(newUid);
}
-
-
}
+ return uidMap;
} catch (IOException ioe) {
throw ioExceptionHandler(mConnection, ioe);
}
diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java
index fba282164..0c3647034 100644
--- a/src/com/fsck/k9/mail/store/LocalStore.java
+++ b/src/com/fsck/k9/mail/store/LocalStore.java
@@ -1885,21 +1885,23 @@ public class LocalStore extends Store implements Serializable {
}
@Override
- public void copyMessages(Message[] msgs, Folder folder) throws MessagingException {
+ public Map copyMessages(Message[] msgs, Folder folder) throws MessagingException {
if (!(folder instanceof LocalFolder)) {
throw new MessagingException("copyMessages called with incorrect Folder");
}
- ((LocalFolder) folder).appendMessages(msgs, true);
+ return ((LocalFolder) folder).appendMessages(msgs, true);
}
@Override
- public void moveMessages(final Message[] msgs, final Folder destFolder) throws MessagingException {
+ public Map moveMessages(final Message[] msgs, final Folder destFolder) throws MessagingException {
if (!(destFolder instanceof LocalFolder)) {
throw new MessagingException("moveMessages called with non-LocalFolder");
}
final LocalFolder lDestFolder = (LocalFolder)destFolder;
+ final Map uidMap = new HashMap();
+
try {
database.execute(false, new DbCallback() {
@Override
@@ -1936,7 +1938,7 @@ public class LocalStore extends Store implements Serializable {
LocalMessage placeHolder = new LocalMessage(oldUID, LocalFolder.this);
placeHolder.setFlagInternal(Flag.DELETED, true);
placeHolder.setFlagInternal(Flag.SEEN, true);
- appendMessages(new Message[] { placeHolder });
+ uidMap.putAll(appendMessages(new Message[] { placeHolder }));
}
} catch (MessagingException e) {
throw new WrappedException(e);
@@ -1944,6 +1946,7 @@ public class LocalStore extends Store implements Serializable {
return null;
}
});
+ return uidMap;
} catch (WrappedException e) {
throw(MessagingException) e.getCause();
}
@@ -1989,8 +1992,8 @@ public class LocalStore extends Store implements Serializable {
* message, retrieve the appropriate local message instance first (if it already exists).
*/
@Override
- public void appendMessages(Message[] messages) throws MessagingException {
- appendMessages(messages, false);
+ public Map appendMessages(Message[] messages) throws MessagingException {
+ return appendMessages(messages, false);
}
public void destroyMessages(final Message[] messages) throws MessagingException {
@@ -2026,10 +2029,12 @@ public class LocalStore extends Store implements Serializable {
* message, retrieve the appropriate local message instance first (if it already exists).
* @param messages
* @param copy
+ * @return Map uidMap of srcUids -> destUids
*/
- private void appendMessages(final Message[] messages, final boolean copy) throws MessagingException {
+ private Map appendMessages(final Message[] messages, final boolean copy) throws MessagingException {
open(OpenMode.READ_WRITE);
try {
+ final Map uidMap = new HashMap();
database.execute(true, new DbCallback() {
@Override
public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException {
@@ -2040,11 +2045,15 @@ public class LocalStore extends Store implements Serializable {
}
String uid = message.getUid();
- if (uid == null || copy) {
+ if (uid == null && !copy) {
uid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
- if (!copy) {
- message.setUid(uid);
+ message.setUid(uid);
+ } else if (copy) {
+ String temp = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
+ if (uid != null) {
+ uidMap.put(uid, temp);
}
+ uid = temp;
} else {
Message oldMessage = getMessage(uid);
if (oldMessage != null && !oldMessage.isSet(Flag.SEEN)) {
@@ -2150,6 +2159,7 @@ public class LocalStore extends Store implements Serializable {
return null;
}
});
+ return uidMap;
} catch (WrappedException e) {
throw(MessagingException) e.getCause();
}
diff --git a/src/com/fsck/k9/mail/store/Pop3Store.java b/src/com/fsck/k9/mail/store/Pop3Store.java
index a307c8484..e0c57591e 100644
--- a/src/com/fsck/k9/mail/store/Pop3Store.java
+++ b/src/com/fsck/k9/mail/store/Pop3Store.java
@@ -24,6 +24,7 @@ import java.util.LinkedList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
public class Pop3Store extends Store {
public static final int CONNECTION_SECURITY_NONE = 0;
@@ -736,7 +737,8 @@ public class Pop3Store extends Store {
}
@Override
- public void appendMessages(Message[] messages) throws MessagingException {
+ public Map appendMessages(Message[] messages) throws MessagingException {
+ return null;
}
@Override
diff --git a/src/com/fsck/k9/mail/store/WebDavStore.java b/src/com/fsck/k9/mail/store/WebDavStore.java
index 81a498f25..7720b9c18 100644
--- a/src/com/fsck/k9/mail/store/WebDavStore.java
+++ b/src/com/fsck/k9/mail/store/WebDavStore.java
@@ -51,6 +51,7 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Stack;
import java.util.zip.GZIPInputStream;
@@ -1161,13 +1162,15 @@ public class WebDavStore extends Store {
}
@Override
- public void copyMessages(Message[] messages, Folder folder) throws MessagingException {
+ public Map copyMessages(Message[] messages, Folder folder) throws MessagingException {
moveOrCopyMessages(messages, folder.getName(), false);
+ return null;
}
@Override
- public void moveMessages(Message[] messages, Folder folder) throws MessagingException {
+ public Map moveMessages(Message[] messages, Folder folder) throws MessagingException {
moveOrCopyMessages(messages, folder.getName(), true);
+ return null;
}
@Override
@@ -1728,8 +1731,9 @@ public class WebDavStore extends Store {
}
@Override
- public void appendMessages(Message[] messages) throws MessagingException {
+ public Map appendMessages(Message[] messages) throws MessagingException {
appendWebDavMessages(messages);
+ return null;
}
public Message[] appendWebDavMessages(Message[] messages) throws MessagingException {
From 3321ebdc33f3e51c145d20cc627cafe09021ad81 Mon Sep 17 00:00:00 2001
From: Apoorv Khatreja
Date: Sat, 2 Jul 2011 11:59:00 +0530
Subject: [PATCH 05/80] COPYUID changes were being updated only in memory, but
were not being written to db.
---
src/com/fsck/k9/controller/MessagingController.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 198f4b9a0..c971eebce 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -2125,7 +2125,7 @@ public class MessagingController implements Runnable {
throws MessagingException {
Folder remoteSrcFolder = null;
Folder remoteDestFolder = null;
- Folder localDestFolder = null;
+ LocalFolder localDestFolder = null;
try {
String srcFolder = command.arguments[0];
if (account.getErrorFolderName().equals(srcFolder)) {
@@ -2144,7 +2144,7 @@ public class MessagingController implements Runnable {
remoteSrcFolder = remoteStore.getFolder(srcFolder);
Store localStore = account.getLocalStore();
- localDestFolder = localStore.getFolder(destFolder);
+ localDestFolder = (LocalFolder) localStore.getFolder(destFolder);
List messages = new ArrayList();
/*
@@ -2230,6 +2230,7 @@ public class MessagingController implements Runnable {
Message localDestMessage = localDestFolder.getMessage(localDestUid);
localDestMessage.setUid(remoteUidMap.get(remoteSrcUid));
+ localDestFolder.changeUid((LocalMessage)localDestMessage);
}
}
} finally {
From da9a5e6c17ce89d2fc54cebf35c5397fd609e93d Mon Sep 17 00:00:00 2001
From: Apoorv Khatreja
Date: Mon, 25 Jul 2011 06:50:26 +0530
Subject: [PATCH 06/80] Made some cosmetic changes for clarity, added debug
messages for erroneous conditions. Fixed potential NPE in
ImapFolder.parseSequenceSet().
---
src/com/fsck/k9/mail/store/ImapStore.java | 26 +++++++++++++++++-----
src/com/fsck/k9/mail/store/LocalStore.java | 6 ++---
2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index b4da67248..4e743e70a 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -866,15 +866,26 @@ public class ImapStore extends Store {
if ((copyList.size() >= 4) && copyList.getString(0).equals("COPYUID")) {
List srcUids = parseSequenceSet(copyList.getString(2));
List destUids = parseSequenceSet(copyList.getString(3));
- if (srcUids.size() == destUids.size()) {
- Iterator srcUidsIterator = srcUids.iterator();
- Iterator destUidsIterator = destUids.iterator();
- uidMap = new HashMap();
- while (srcUidsIterator.hasNext() && destUidsIterator.hasNext()) {
- uidMap.put(srcUidsIterator.next(), destUidsIterator.next());
+ if (srcUids != null && destUids != null) {
+ if (srcUids.size() == destUids.size()) {
+ Iterator srcUidsIterator = srcUids.iterator();
+ Iterator destUidsIterator = destUids.iterator();
+ uidMap = new HashMap();
+ while (srcUidsIterator.hasNext() && destUidsIterator.hasNext()) {
+ uidMap.put(srcUidsIterator.next(), destUidsIterator.next());
+ }
+ } else {
+ if(K9.DEBUG)
+ Log.v(K9.LOG_TAG, "Parse error: size of source UIDs list is not the same as size of destination UIDs list.");
}
+ } else {
+ if(K9.DEBUG)
+ Log.v(K9.LOG_TAG, "Parsing of the sequence set failed.");
}
}
+ } else {
+ if(K9.DEBUG)
+ Log.v(K9.LOG_TAG, "Expected COPYUID response was not found.");
}
return uidMap;
} catch (IOException ioe) {
@@ -890,6 +901,9 @@ public class ImapStore extends Store {
* @return List sequenceSet
*/
private List parseSequenceSet(String set) {
+ if (set == null) {
+ return null;
+ }
int index = 0;
List sequenceList = new ArrayList();
String element = "";
diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java
index 0c3647034..7a5a6b437 100644
--- a/src/com/fsck/k9/mail/store/LocalStore.java
+++ b/src/com/fsck/k9/mail/store/LocalStore.java
@@ -2049,11 +2049,11 @@ public class LocalStore extends Store implements Serializable {
uid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
message.setUid(uid);
} else if (copy) {
- String temp = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
+ String randomLocalUid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
if (uid != null) {
- uidMap.put(uid, temp);
+ uidMap.put(uid, randomLocalUid);
}
- uid = temp;
+ uid = randomLocalUid;
} else {
Message oldMessage = getMessage(uid);
if (oldMessage != null && !oldMessage.isSet(Flag.SEEN)) {
From cf390700487daf0f6611415d4531f9b013195b46 Mon Sep 17 00:00:00 2001
From: Apoorv Khatreja
Date: Mon, 25 Jul 2011 18:56:21 +0530
Subject: [PATCH 07/80] Whitespaces :/
---
src/com/fsck/k9/mail/store/ImapStore.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 4e743e70a..d9f8b4548 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -875,16 +875,16 @@ public class ImapStore extends Store {
uidMap.put(srcUidsIterator.next(), destUidsIterator.next());
}
} else {
- if(K9.DEBUG)
+ if(K9.DEBUG)
Log.v(K9.LOG_TAG, "Parse error: size of source UIDs list is not the same as size of destination UIDs list.");
}
} else {
- if(K9.DEBUG)
+ if(K9.DEBUG)
Log.v(K9.LOG_TAG, "Parsing of the sequence set failed.");
}
}
} else {
- if(K9.DEBUG)
+ if(K9.DEBUG)
Log.v(K9.LOG_TAG, "Expected COPYUID response was not found.");
}
return uidMap;
From 4b0d3ccf21caf250806d5b15565d90b0e242b495 Mon Sep 17 00:00:00 2001
From: Apoorv Khatreja
Date: Thu, 17 Nov 2011 02:46:01 +0530
Subject: [PATCH 08/80] Removed an unnecessary portion of code that attempted
to handle command continuation requests after a UID COPY command. Also
removed some extraneous test code that mysteriously creeped into the repo.
---
src/com/fsck/k9/mail/store/ImapStore.java | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index d9f8b4548..a0efebeee 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -839,12 +839,6 @@ public class ImapStore extends Store {
do {
response = mConnection.readResponse();
handleUntaggedResponse(response);
- if (response.mCommandContinuationRequested) {
- EOLConvertingOutputStream eolOut = new EOLConvertingOutputStream(mConnection.mOut);
- eolOut.write('\r');
- eolOut.write('\n');
- eolOut.flush();
- }
while (response.more());
} while (response.mTag == null);
@@ -2410,17 +2404,6 @@ public class ImapStore extends Store {
return executeSimpleCommand(command, sensitive, null);
}
-// public void logResponse (ImapList response) {
-// for(int i=0;i executeSimpleCommand(String command, boolean sensitive, UntaggedHandler untaggedHandler)
throws IOException, ImapException, MessagingException {
String commandToLog = command;
From 396005974a269d03f66785f53aa91adbd4c2539d Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 16 Feb 2012 21:33:53 +0100
Subject: [PATCH 09/80] Cleaned up ImapStore.ImapFolder.appendMessages()
---
src/com/fsck/k9/mail/store/ImapStore.java | 85 +++++++++++++----------
1 file changed, 47 insertions(+), 38 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index abd8cd2e2..461339d41 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -54,7 +54,6 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.PowerManager;
-import android.text.TextUtils;
import android.util.Log;
import com.beetstra.jutf7.CharsetProvider;
@@ -62,6 +61,7 @@ import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.controller.MessageRetrievalListener;
+import com.fsck.k9.helper.StringUtils;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.helper.power.TracingPowerManager;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
@@ -1099,7 +1099,6 @@ public class ImapStore extends Store {
do {
response = mConnection.readResponse();
handleUntaggedResponse(response);
- while (response.more());
} while (response.mTag == null);
/*
@@ -1953,21 +1952,30 @@ public class ImapStore extends Store {
}
/**
- * Appends the given messages to the selected folder. This implementation also determines
- * the new UID of the given message on the IMAP server and sets the Message's UID to the
- * new server UID.
+ * Appends the given messages to the selected folder.
+ *
+ *
+ * This implementation also determines the new UIDs of the given messages on the IMAP
+ * server and changes the messages' UIDs to the new server UIDs.
+ *
+ *
+ * @param messages
+ * The messages to append to the folder.
+ *
+ * @return The mapping of original message UIDs to the new server UIDs.
*/
@Override
public Map appendMessages(Message[] messages) throws MessagingException {
checkOpen();
try {
- Map uidMap = null;
+ Map uidMap = new HashMap();
for (Message message : messages) {
mConnection.sendCommand(
String.format("APPEND %s (%s) {%d}",
encodeString(encodeFolderName(getPrefixedName())),
combineFlags(message.getFlags()),
message.calculateSize()), false);
+
ImapResponse response;
do {
response = mConnection.readResponse();
@@ -1981,53 +1989,54 @@ public class ImapStore extends Store {
}
} while (response.mTag == null);
- /*
- * If the server supports UIDPLUS, then along with the APPEND response it will return an APPENDUID response code.
- * e.g. 11 OK [APPENDUID 2 238268] APPEND completed
- *
- * We can use the UID included in this response to update our records.
- *
- * Code imported from AOSP Email as of git rev a5c3744a247e432acf9f571a9dfb55321c4baa1a
- */
- Object responseList = response.get(1);
+ if (response.size() > 1) {
+ /*
+ * If the server supports UIDPLUS, then along with the APPEND response it
+ * will return an APPENDUID response code, e.g.
+ *
+ * 11 OK [APPENDUID 2 238268] APPEND completed
+ *
+ * We can use the UID included in this response to update our records.
+ */
+ Object responseList = response.get(1);
- if (responseList instanceof ImapList) {
- final ImapList appendList = (ImapList) responseList;
- if ((appendList.size() >= 3) && appendList.getString(0).equals("APPENDUID")) {
- String newUid = appendList.getString(2);
+ if (responseList instanceof ImapList) {
+ ImapList appendList = (ImapList) responseList;
+ if (appendList.size() >= 3 &&
+ appendList.getString(0).equals("APPENDUID")) {
- /*
- * We need uidMap to be null initially to maintain consistency with the behavior of other similar methods (copyMessages, moveMessages) which
- * return null if new UIDs are not available. Therefore, we initialize uidMap over here.
- */
- if (uidMap == null) {
- uidMap = new HashMap();
- }
- uidMap.put(message.getUid(), newUid);
- if (!TextUtils.isEmpty(newUid)) {
- message.setUid(newUid);
- continue;
+ String newUid = appendList.getString(2);
+
+ if (!StringUtils.isNullOrEmpty(newUid)) {
+ message.setUid(newUid);
+ uidMap.put(message.getUid(), newUid);
+ continue;
+ }
}
}
}
-
/*
- * This part is executed in case the server does not support UIDPLUS or does not implement the APPENDUID response code.
+ * This part is executed in case the server does not support UIDPLUS or does
+ * not implement the APPENDUID response code.
*/
String newUid = getUidFromMessageId(message);
- if (K9.DEBUG)
+ if (K9.DEBUG) {
Log.d(K9.LOG_TAG, "Got UID " + newUid + " for message for " + getLogId());
+ }
- if (newUid != null) {
- if (uidMap == null) {
- uidMap = new HashMap();
- }
+ if (!StringUtils.isNullOrEmpty(newUid)) {
uidMap.put(message.getUid(), newUid);
message.setUid(newUid);
}
}
- return uidMap;
+
+ /*
+ * We need uidMap to be null if new UIDs are not available to maintain consistency
+ * with the behavior of other similar methods (copyMessages, moveMessages) which
+ * return null.
+ */
+ return (uidMap.size() == 0) ? null : uidMap;
} catch (IOException ioe) {
throw ioExceptionHandler(mConnection, ioe);
}
From 3e4e6c72fd5180db967ddeaca5febe47954b7121 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 16 Feb 2012 22:12:44 +0100
Subject: [PATCH 10/80] Cleaned up ImapStore.ImapFolder.copyMessages()
---
src/com/fsck/k9/mail/store/ImapStore.java | 108 ++++++++++++++--------
1 file changed, 68 insertions(+), 40 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 461339d41..32b07a6bd 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -1062,36 +1062,54 @@ public class ImapStore extends Store {
}
}
+ /**
+ * Copies the given messages to the specified folder.
+ *
+ *
+ * Note:
+ * Only the UIDs of the given {@link Message} instances are used. It is assumed that all
+ * UIDs represent valid messages in this folder.
+ *
+ *
+ * @param messages
+ * The messages to copy to the specfied folder.
+ * @param folder
+ * The name of the target folder.
+ *
+ * @return The mapping of original message UIDs to the new server UIDs.
+ */
@Override
- public Map copyMessages(Message[] messages, Folder folder) throws MessagingException {
+ public Map copyMessages(Message[] messages, Folder folder)
+ throws MessagingException {
if (!(folder instanceof ImapFolder)) {
throw new MessagingException("ImapFolder.copyMessages passed non-ImapFolder");
}
- if (messages.length == 0)
+ if (messages.length == 0) {
return null;
+ }
ImapFolder iFolder = (ImapFolder)folder;
checkOpen();
String[] uids = new String[messages.length];
for (int i = 0, count = messages.length; i < count; i++) {
-
- // Not bothering to sort the UIDs in ascending order while sending the command for convenience, and because it does not make a difference.
uids[i] = messages[i].getUid();
}
+
try {
String remoteDestName = encodeString(encodeFolderName(iFolder.getPrefixedName()));
if (!exists(remoteDestName)) {
- /*
- * If the remote trash folder doesn't exist we try to create it.
- */
- if (K9.DEBUG)
- Log.i(K9.LOG_TAG, "IMAPMessage.copyMessages: attempting to create remote '" + remoteDestName + "' folder for " + getLogId());
+ // If the remote trash folder doesn't exist we try to create it.
+ if (K9.DEBUG) {
+ Log.i(K9.LOG_TAG, "Attempting to create remote folder '" + remoteDestName +
+ "' for " + getLogId());
+ }
iFolder.create(FolderType.HOLDS_MESSAGES);
}
+ //TODO: Split this into multiple commands if the command exceeds a certain length.
mConnection.sendCommand(String.format("UID COPY %s %s",
Utility.combine(uids, ','),
remoteDestName), false);
@@ -1101,45 +1119,55 @@ public class ImapStore extends Store {
handleUntaggedResponse(response);
} while (response.mTag == null);
- /*
- * If the server supports UIDPLUS, then along with the COPY response it will return an COPYUID response code.
- * e.g. 24 OK [COPYUID 38505 304,319:320 3956:3958] Success
- *
- * COPYUID is followed by UIDVALIDITY, set of UIDs of copied messages from the source folder and set of corresponding UIDs assigned to them in the destination folder.
- *
- * We can use the new UIDs included in this response to update our records.
- */
-
- Object responseList = response.get(1);
-
Map uidMap = null;
+ if (response.size() > 1) {
+ /*
+ * If the server supports UIDPLUS, then along with the COPY response it will
+ * return an COPYUID response code, e.g.
+ *
+ * 24 OK [COPYUID 38505 304,319:320 3956:3958] Success
+ *
+ * COPYUID is followed by UIDVALIDITY, the set of UIDs of copied messages from
+ * the source folder and the set of corresponding UIDs assigned to them in the
+ * destination folder.
+ *
+ * We can use the new UIDs included in this response to update our records.
+ */
+ Object responseList = response.get(1);
- if (responseList instanceof ImapList) {
- final ImapList copyList = (ImapList) responseList;
- if ((copyList.size() >= 4) && copyList.getString(0).equals("COPYUID")) {
- List srcUids = parseSequenceSet(copyList.getString(2));
- List destUids = parseSequenceSet(copyList.getString(3));
- if (srcUids != null && destUids != null) {
- if (srcUids.size() == destUids.size()) {
- Iterator srcUidsIterator = srcUids.iterator();
- Iterator destUidsIterator = destUids.iterator();
- uidMap = new HashMap();
- while (srcUidsIterator.hasNext() && destUidsIterator.hasNext()) {
- uidMap.put(srcUidsIterator.next(), destUidsIterator.next());
+ if (responseList instanceof ImapList) {
+ final ImapList copyList = (ImapList) responseList;
+ if (copyList.size() >= 4 && copyList.getString(0).equals("COPYUID")) {
+ List srcUids = parseSequenceSet(copyList.getString(2));
+ List destUids = parseSequenceSet(copyList.getString(3));
+
+ if (srcUids != null && destUids != null) {
+ if (srcUids.size() == destUids.size()) {
+ Iterator srcUidsIterator = srcUids.iterator();
+ Iterator destUidsIterator = destUids.iterator();
+ uidMap = new HashMap();
+ while (srcUidsIterator.hasNext() &&
+ destUidsIterator.hasNext()) {
+ String srcUid = srcUidsIterator.next();
+ String destUid = destUidsIterator.next();
+ uidMap.put(srcUid, destUid);
+ }
+ } else {
+ if (K9.DEBUG) {
+ Log.v(K9.LOG_TAG, "Parse error: size of source UIDs " +
+ "list is not the same as size of destination " +
+ "UIDs list.");
+ }
}
} else {
- if(K9.DEBUG)
- Log.v(K9.LOG_TAG, "Parse error: size of source UIDs list is not the same as size of destination UIDs list.");
+ if (K9.DEBUG) {
+ Log.v(K9.LOG_TAG, "Parsing of the sequence set failed.");
+ }
}
- } else {
- if(K9.DEBUG)
- Log.v(K9.LOG_TAG, "Parsing of the sequence set failed.");
}
}
- } else {
- if(K9.DEBUG)
- Log.v(K9.LOG_TAG, "Expected COPYUID response was not found.");
}
+
return uidMap;
} catch (IOException ioe) {
throw ioExceptionHandler(mConnection, ioe);
From 89e0ed3c03a6fbab38ffa4c7b45c4fdd4a63de1b Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 16 Feb 2012 22:34:50 +0100
Subject: [PATCH 11/80] Notify listeners of UID changes after remote copy/move
---
src/com/fsck/k9/controller/MessagingController.java | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 61ae0f1b4..6673df75f 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -2227,10 +2227,14 @@ public class MessagingController implements Runnable {
while (remoteSrcUidsIterator.hasNext()) {
String remoteSrcUid = remoteSrcUidsIterator.next();
String localDestUid = localUidMap.get(remoteSrcUid);
+ String newUid = remoteUidMap.get(remoteSrcUid);
Message localDestMessage = localDestFolder.getMessage(localDestUid);
- localDestMessage.setUid(remoteUidMap.get(remoteSrcUid));
+ localDestMessage.setUid(newUid);
localDestFolder.changeUid((LocalMessage)localDestMessage);
+ for (MessagingListener l : getListeners()) {
+ l.messageUidChanged(account, destFolder, localDestUid, newUid);
+ }
}
}
} finally {
From 4ed77c7a29a508240e926854505953391bb17dfb Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 16 Feb 2012 22:36:57 +0100
Subject: [PATCH 12/80] Avoid NullPointerException
---
src/com/fsck/k9/controller/MessagingController.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 6673df75f..06fb59370 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -2189,7 +2189,7 @@ public class MessagingController implements Runnable {
Log.d(K9.LOG_TAG, "processingPendingMoveOrCopy: source folder = " + srcFolder
+ ", " + messages.size() + " messages, destination folder = " + destFolder + ", isCopy = " + isCopy);
- Map remoteUidMap = new HashMap();
+ Map remoteUidMap = null;
if (!isCopy && destFolder.equals(account.getTrashFolderName())) {
if (K9.DEBUG)
@@ -2220,7 +2220,7 @@ public class MessagingController implements Runnable {
* This next part is used to bring the local UIDs of the local destination folder
* upto speed with the remote UIDs of remote destionation folder.
*/
- if (!localUidMap.isEmpty() && !remoteUidMap.isEmpty()) {
+ if (!localUidMap.isEmpty() && remoteUidMap != null && !remoteUidMap.isEmpty()) {
Set remoteSrcUids = remoteUidMap.keySet();
Iterator remoteSrcUidsIterator = remoteSrcUids.iterator();
From 023c60513eeb308f280c836b3334c0959d5de4b3 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 16 Feb 2012 23:37:44 +0100
Subject: [PATCH 13/80] Fixed UID mapping return value of
LocalStore.moveMessages()
---
src/com/fsck/k9/mail/store/LocalStore.java | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java
index ca8980ab0..c36350dfa 100644
--- a/src/com/fsck/k9/mail/store/LocalStore.java
+++ b/src/com/fsck/k9/mail/store/LocalStore.java
@@ -1963,7 +1963,10 @@ public class LocalStore extends Store implements Serializable {
Log.d(K9.LOG_TAG, "Updating folder_id to " + lDestFolder.getId() + " for message with UID "
+ message.getUid() + ", id " + lMessage.getId() + " currently in folder " + getName());
- message.setUid(K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString());
+ String newUid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
+ message.setUid(newUid);
+
+ uidMap.put(oldUID, newUid);
db.execSQL("UPDATE messages " + "SET folder_id = ?, uid = ? " + "WHERE id = ?", new Object[] {
lDestFolder.getId(),
@@ -1971,10 +1974,15 @@ public class LocalStore extends Store implements Serializable {
lMessage.getId()
});
+ /*
+ * Add a placeholder message so we won't download the original
+ * message again if we synchronize before the remote move is
+ * complete.
+ */
LocalMessage placeHolder = new LocalMessage(oldUID, LocalFolder.this);
placeHolder.setFlagInternal(Flag.DELETED, true);
placeHolder.setFlagInternal(Flag.SEEN, true);
- uidMap.putAll(appendMessages(new Message[] { placeHolder }));
+ appendMessages(new Message[] { placeHolder });
}
} catch (MessagingException e) {
throw new WrappedException(e);
From c3885bc475f95dc655d3adbc706749c3d78d0add Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 16 Feb 2012 23:52:44 +0100
Subject: [PATCH 14/80] Cleaned up LocalFolder.appendMessages() a bit
---
src/com/fsck/k9/mail/store/LocalStore.java | 23 ++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java
index c36350dfa..bf797ebfe 100644
--- a/src/com/fsck/k9/mail/store/LocalStore.java
+++ b/src/com/fsck/k9/mail/store/LocalStore.java
@@ -2090,16 +2090,27 @@ public class LocalStore extends Store implements Serializable {
long oldMessageId = -1;
String uid = message.getUid();
- if (uid == null && !copy) {
- uid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
- message.setUid(uid);
- } else if (copy) {
- String randomLocalUid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
- if (uid != null) {
+ if (uid == null || copy) {
+ /*
+ * Create a new message in the database
+ */
+ String randomLocalUid = K9.LOCAL_UID_PREFIX +
+ UUID.randomUUID().toString();
+
+ if (copy) {
+ // Save mapping: source UID -> target UID
uidMap.put(uid, randomLocalUid);
+ } else {
+ // Modify the Message instance to reference the new UID
+ message.setUid(randomLocalUid);
}
+
+ // The message will be saved with the newly generated UID
uid = randomLocalUid;
} else {
+ /*
+ * Replace an existing message in the database
+ */
LocalMessage oldMessage = (LocalMessage) getMessage(uid);
if (oldMessage != null) {
From f7299a69d44efbc36d864a0096d1f741d2a797d6 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 17 Feb 2012 00:43:35 +0100
Subject: [PATCH 15/80] Keep track of UIDs when moving messages to the trash
folder
---
src/com/fsck/k9/controller/MessagingController.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 06fb59370..cc09d8e31 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -3515,6 +3515,7 @@ public class MessagingController implements Runnable {
}
Store localStore = account.getLocalStore();
localFolder = localStore.getFolder(folder);
+ Map uidMap = null;
if (folder.equals(account.getTrashFolderName()) || K9.FOLDER_NONE.equals(account.getTrashFolderName())) {
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Deleting messages in trash folder or trash set to -None-, not copying");
@@ -3529,7 +3530,7 @@ public class MessagingController implements Runnable {
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Deleting messages in normal folder, moving");
- localFolder.moveMessages(messages, localTrashFolder);
+ uidMap = localFolder.moveMessages(messages, localTrashFolder);
}
}
@@ -3562,7 +3563,7 @@ public class MessagingController implements Runnable {
if (folder.equals(account.getTrashFolderName())) {
queueSetFlag(account, folder, Boolean.toString(true), Flag.DELETED.toString(), uids);
} else {
- queueMoveOrCopy(account, folder, account.getTrashFolderName(), false, uids);
+ queueMoveOrCopy(account, folder, account.getTrashFolderName(), false, uids, uidMap);
}
processPendingCommands(account);
} else if (account.getDeletePolicy() == Account.DELETE_POLICY_MARK_AS_READ) {
From c1ed0c78a9c8c08178565ccfa781cb9762884ad0 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 17 Feb 2012 01:59:04 +0100
Subject: [PATCH 16/80] Introduced new pending command to retain upgradability
---
.../k9/controller/MessagingController.java | 40 ++++++++++++++++++-
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index cc09d8e31..008b9afe0 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -117,6 +117,7 @@ public class MessagingController implements Runnable {
private static final String PENDING_COMMAND_MOVE_OR_COPY = "com.fsck.k9.MessagingController.moveOrCopy";
private static final String PENDING_COMMAND_MOVE_OR_COPY_BULK = "com.fsck.k9.MessagingController.moveOrCopyBulk";
+ private static final String PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW = "com.fsck.k9.MessagingController.moveOrCopyBulkNew";
private static final String PENDING_COMMAND_EMPTY_TRASH = "com.fsck.k9.MessagingController.emptyTrash";
private static final String PENDING_COMMAND_SET_FLAG_BULK = "com.fsck.k9.MessagingController.setFlagBulk";
private static final String PENDING_COMMAND_SET_FLAG = "com.fsck.k9.MessagingController.setFlag";
@@ -1902,6 +1903,8 @@ public class MessagingController implements Runnable {
} else if (PENDING_COMMAND_MARK_ALL_AS_READ.equals(command.command)) {
processPendingMarkAllAsRead(command, account);
} else if (PENDING_COMMAND_MOVE_OR_COPY_BULK.equals(command.command)) {
+ processPendingMoveOrCopyOld2(command, account);
+ } else if (PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW.equals(command.command)) {
processPendingMoveOrCopy(command, account);
} else if (PENDING_COMMAND_MOVE_OR_COPY.equals(command.command)) {
processPendingMoveOrCopyOld(command, account);
@@ -2081,7 +2084,7 @@ public class MessagingController implements Runnable {
return;
}
PendingCommand command = new PendingCommand();
- command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK;
+ command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
int length = 3 + uids.length;
command.arguments = new String[length];
@@ -2101,7 +2104,7 @@ public class MessagingController implements Runnable {
return;
}
PendingCommand command = new PendingCommand();
- command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK;
+ command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
int length = 4 + uidMap.keySet().size() + uidMap.values().size();
command.arguments = new String[length];
@@ -2114,6 +2117,39 @@ public class MessagingController implements Runnable {
queuePendingCommand(account, command);
}
}
+
+ /**
+ * Convert pending command to new format and call
+ * {@link #processPendingMoveOrCopy(PendingCommand, Account)}.
+ *
+ *
+ * TODO: This method is obsolete and is only for transition from K-9 4.0 to K-9 4.2
+ * Eventually, it should be removed.
+ *
+ *
+ * @param command
+ * Pending move/copy command in old format.
+ * @param account
+ * The account the pending command belongs to.
+ *
+ * @throws MessagingException
+ * In case of an error.
+ */
+ private void processPendingMoveOrCopyOld2(PendingCommand command, Account account)
+ throws MessagingException {
+ PendingCommand newCommand = new PendingCommand();
+ int len = command.arguments.length;
+ newCommand.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
+ newCommand.arguments = new String[len + 1];
+ newCommand.arguments[0] = command.arguments[0];
+ newCommand.arguments[1] = command.arguments[1];
+ newCommand.arguments[2] = command.arguments[2];
+ newCommand.arguments[3] = Boolean.toString(false);
+ System.arraycopy(command.arguments, 3, newCommand.arguments, 4, len - 3);
+
+ processPendingMoveOrCopy(newCommand, account);
+ }
+
/**
* Process a pending trash message command.
*
From deb01bcd16184eeaeac63b9f22c5b91ad6600682 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 17 Feb 2012 14:59:50 +0100
Subject: [PATCH 17/80] Imported ImapUtility.java from AOSP Email
Modified it to fit our needs.
---
.../fsck/k9/mail/store/imap/ImapUtility.java | 113 ++++++++++++++++++
1 file changed, 113 insertions(+)
create mode 100644 src/com/fsck/k9/mail/store/imap/ImapUtility.java
diff --git a/src/com/fsck/k9/mail/store/imap/ImapUtility.java b/src/com/fsck/k9/mail/store/imap/ImapUtility.java
new file mode 100644
index 000000000..d0ac2b31a
--- /dev/null
+++ b/src/com/fsck/k9/mail/store/imap/ImapUtility.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 The K-9 Dog Walkers
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.fsck.k9.mail.store.imap;
+
+import android.util.Log;
+
+import com.fsck.k9.K9;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility methods for use with IMAP.
+ */
+public class ImapUtility {
+ /**
+ * Gets all of the values in a sequence set per RFC 3501.
+ *
+ *
+ * Any ranges are expanded into a list of individual numbers.
+ *
+ *
+ * @param set
+ * The sequence set string as received by the server.
+ *
+ * @return The list of IDs as strings in this sequence set. If the set is invalid, an empty
+ * list is returned.
+ */
+ public static List getImapSequenceValues(String set) {
+ ArrayList list = new ArrayList();
+ if (set != null) {
+ String[] setItems = set.split(",");
+ for (String item : setItems) {
+ if (item.indexOf(':') == -1) {
+ // simple item
+ try {
+ Integer.parseInt(item); // Don't need the value; just ensure it's valid
+ list.add(item);
+ } catch (NumberFormatException e) {
+ Log.d(K9.LOG_TAG, "Invalid UID value", e);
+ }
+ } else {
+ // range
+ list.addAll(getImapRangeValues(item));
+ }
+ }
+ }
+
+ return list;
+ }
+
+ /**
+ * Expand the given number range into a list of individual numbers.
+ *
+ *
+ *
+ * @param range
+ * The range string as received by the server.
+ *
+ * @return The list of IDs as strings in this range. If the range is not valid, an empty list
+ * is returned.
+ */
+ public static List getImapRangeValues(String range) {
+ ArrayList list = new ArrayList();
+ try {
+ if (range != null) {
+ int colonPos = range.indexOf(':');
+ if (colonPos > 0) {
+ int first = Integer.parseInt(range.substring(0, colonPos));
+ int second = Integer.parseInt(range.substring(colonPos + 1));
+ if (first < second) {
+ for (int i = first; i <= second; i++) {
+ list.add(Integer.toString(i));
+ }
+ } else {
+ for (int i = first; i >= second; i--) {
+ list.add(Integer.toString(i));
+ }
+ }
+ }
+ }
+ } catch (NumberFormatException e) {
+ Log.d(K9.LOG_TAG, "Invalid range value", e);
+ }
+
+ return list;
+ }
+}
From 5083b8f1e866a6783f5afe074d13398d493513db Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 17 Feb 2012 15:01:30 +0100
Subject: [PATCH 18/80] Use newly imported AOSP code instead of
ImapStore.parseSequenceSet()
---
src/com/fsck/k9/mail/store/ImapStore.java | 63 ++---------------------
1 file changed, 5 insertions(+), 58 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 32b07a6bd..b0ecd2adc 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -90,6 +90,7 @@ import com.fsck.k9.mail.internet.MimeMultipart;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
+import com.fsck.k9.mail.store.imap.ImapUtility;
import com.fsck.k9.mail.transport.imap.ImapSettings;
import com.jcraft.jzlib.JZlib;
import com.jcraft.jzlib.ZOutputStream;
@@ -1138,8 +1139,10 @@ public class ImapStore extends Store {
if (responseList instanceof ImapList) {
final ImapList copyList = (ImapList) responseList;
if (copyList.size() >= 4 && copyList.getString(0).equals("COPYUID")) {
- List srcUids = parseSequenceSet(copyList.getString(2));
- List destUids = parseSequenceSet(copyList.getString(3));
+ List srcUids = ImapUtility.getImapSequenceValues(
+ copyList.getString(2));
+ List destUids = ImapUtility.getImapSequenceValues(
+ copyList.getString(3));
if (srcUids != null && destUids != null) {
if (srcUids.size() == destUids.size()) {
@@ -1174,62 +1177,6 @@ public class ImapStore extends Store {
}
}
- /**
- * Can be used to parse sequence sets or UID sets appearing is responses such as COPYUID.
- * e.g. [COPYUID 38505 304,319:320 3956:3958]
- *
- * @param set
- * @return List sequenceSet
- */
- private List parseSequenceSet(String set) {
- if (set == null) {
- return null;
- }
- int index = 0;
- List sequenceList = new ArrayList();
- String element = "";
-
- while (index < set.length()) {
- if (set.charAt(index) == ':') {
- String upperBound = "";
- index++;
- while (index < set.length()) {
- if (!(set.charAt(index) == ',')) {
- upperBound += set.charAt(index);
- index++;
- } else {
- break;
- }
- }
-
- int lower = Integer.parseInt(element);
- int upper = Integer.parseInt(upperBound);
-
- if (lower < upper) {
- for (int i = lower; i <= upper; i++) {
- sequenceList.add(String.valueOf(i));
- }
- } else {
- for (int i = upper; i <= lower; i++) {
- sequenceList.add(String.valueOf(i));
- }
- }
-
- element = "";
- } else if (set.charAt(index) == ',') {
- sequenceList.add(element);
- element = "";
- } else {
- element += set.charAt(index);
- }
- index++;
- }
- if (!element.equals("")) {
- sequenceList.add(element);
- }
- return sequenceList;
- }
-
@Override
public Map moveMessages(Message[] messages, Folder folder) throws MessagingException {
if (messages.length == 0)
From 33029a1f17149a218d6bb03ce8a4629eb5c4e0b7 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 17 Feb 2012 15:34:10 +0100
Subject: [PATCH 19/80] Imported unit tests for ImapUtility from AOSP Email
---
.../k9/mail/store/imap/ImapUtilityTest.java | 125 ++++++++++++++++++
1 file changed, 125 insertions(+)
create mode 100644 tests/src/com/fsck/k9/mail/store/imap/ImapUtilityTest.java
diff --git a/tests/src/com/fsck/k9/mail/store/imap/ImapUtilityTest.java b/tests/src/com/fsck/k9/mail/store/imap/ImapUtilityTest.java
new file mode 100644
index 000000000..496d6922e
--- /dev/null
+++ b/tests/src/com/fsck/k9/mail/store/imap/ImapUtilityTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2012 The K-9 Dog Walkers
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.fsck.k9.mail.store.imap;
+
+import java.util.List;
+import android.test.MoreAsserts;
+import junit.framework.TestCase;
+
+public class ImapUtilityTest extends TestCase {
+ /**
+ * Test getting elements of an IMAP sequence set.
+ */
+ public void testGetImapSequenceValues() {
+ String[] expected;
+ List actual;
+
+ // Test valid sets
+ expected = new String[] {"1"};
+ actual = ImapUtility.getImapSequenceValues("1");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[] {"1", "3", "2"};
+ actual = ImapUtility.getImapSequenceValues("1,3,2");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[] {"4", "5", "6"};
+ actual = ImapUtility.getImapSequenceValues("4:6");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[] {"9", "8", "7"};
+ actual = ImapUtility.getImapSequenceValues("9:7");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[] {"1", "2", "3", "4", "9", "8", "7"};
+ actual = ImapUtility.getImapSequenceValues("1,2:4,9:7");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ // Test partially invalid sets
+ expected = new String[] { "1", "5" };
+ actual = ImapUtility.getImapSequenceValues("1,x,5");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[] { "1", "2", "3" };
+ actual = ImapUtility.getImapSequenceValues("a:d,1:3");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ // Test invalid sets
+ expected = new String[0];
+ actual = ImapUtility.getImapSequenceValues("");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[0];
+ actual = ImapUtility.getImapSequenceValues(null);
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[0];
+ actual = ImapUtility.getImapSequenceValues("a");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[0];
+ actual = ImapUtility.getImapSequenceValues("1:x");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+ }
+
+ /**
+ * Test getting elements of an IMAP range.
+ */
+ public void testGetImapRangeValues() {
+ String[] expected;
+ List actual;
+
+ // Test valid ranges
+ expected = new String[] {"1", "2", "3"};
+ actual = ImapUtility.getImapRangeValues("1:3");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[] {"16", "15", "14"};
+ actual = ImapUtility.getImapRangeValues("16:14");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ // Test in-valid ranges
+ expected = new String[0];
+ actual = ImapUtility.getImapRangeValues("");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[0];
+ actual = ImapUtility.getImapRangeValues(null);
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[0];
+ actual = ImapUtility.getImapRangeValues("a");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[0];
+ actual = ImapUtility.getImapRangeValues("6");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[0];
+ actual = ImapUtility.getImapRangeValues("1:3,6");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[0];
+ actual = ImapUtility.getImapRangeValues("1:x");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+
+ expected = new String[0];
+ actual = ImapUtility.getImapRangeValues("1:*");
+ MoreAsserts.assertEquals(expected, actual.toArray());
+ }
+}
From f6ebe4d4e08ec281c0931c0b46bdc582b308bea8 Mon Sep 17 00:00:00 2001
From: cketti
Date: Wed, 29 Feb 2012 03:03:20 +0100
Subject: [PATCH 20/80] Deduplicated code to create SearchAccounts for special
accounts
---
src/com/fsck/k9/SearchAccount.java | 33 +++++++++++++++++++
src/com/fsck/k9/activity/AccountList.java | 13 +++-----
src/com/fsck/k9/activity/Accounts.java | 11 ++-----
src/com/fsck/k9/provider/MessageProvider.java | 4 +--
4 files changed, 42 insertions(+), 19 deletions(-)
diff --git a/src/com/fsck/k9/SearchAccount.java b/src/com/fsck/k9/SearchAccount.java
index b990e8d09..bf2f25570 100644
--- a/src/com/fsck/k9/SearchAccount.java
+++ b/src/com/fsck/k9/SearchAccount.java
@@ -12,6 +12,39 @@ import com.fsck.k9.mail.Flag;
* is defined by {@link com.fsck.k9.activity.SearchModifier}.
*/
public class SearchAccount implements BaseAccount, SearchSpecification, Serializable {
+ /**
+ * Create a {@code SearchAccount} instance for the Unified Inbox.
+ *
+ * @param context
+ * A {@link Context} instance that will be used to get localized strings and will be
+ * passed on to the {@code SearchAccount} instance.
+ *
+ * @return The {@link SearchAccount} instance for the Unified Inbox.
+ */
+ public static SearchAccount createUnifiedInboxAccount(Context context) {
+ SearchAccount unifiedInbox = new SearchAccount(context, true, null, null);
+ unifiedInbox.setDescription(context.getString(R.string.integrated_inbox_title));
+ unifiedInbox.setEmail(context.getString(R.string.integrated_inbox_detail));
+ return unifiedInbox;
+ }
+
+ /**
+ * Create a {@code SearchAccount} instance for the special account "All messages".
+ *
+ * @param context
+ * A {@link Context} instance that will be used to get localized strings and will be
+ * passed on to the {@code SearchAccount} instance.
+ *
+ * @return The {@link SearchAccount} instance for the Unified Inbox.
+ */
+ public static SearchAccount createAllMessagesAccount(Context context) {
+ SearchAccount allMessages = new SearchAccount(context, false, null, null);
+ allMessages.setDescription(context.getString(R.string.search_all_messages_title));
+ allMessages.setEmail(context.getString(R.string.search_all_messages_detail));
+ return allMessages;
+ }
+
+
private static final long serialVersionUID = -4388420303235543976L;
private Flag[] mRequiredFlags = null;
private Flag[] mForbiddenFlags = null;
diff --git a/src/com/fsck/k9/activity/AccountList.java b/src/com/fsck/k9/activity/AccountList.java
index a229702ad..52c64dbe3 100644
--- a/src/com/fsck/k9/activity/AccountList.java
+++ b/src/com/fsck/k9/activity/AccountList.java
@@ -73,16 +73,11 @@ public abstract class AccountList extends K9ListActivity implements OnItemClickL
List accounts = new ArrayList();
if (displaySpecialAccounts() && !K9.isHideSpecialAccounts()) {
- BaseAccount integratedInboxAccount = new SearchAccount(this, true, null, null);
- integratedInboxAccount.setDescription(getString(R.string.integrated_inbox_title));
- integratedInboxAccount.setEmail(getString(R.string.integrated_inbox_detail));
+ BaseAccount unifiedInboxAccount = SearchAccount.createUnifiedInboxAccount(this);
+ BaseAccount allMessagesAccount = SearchAccount.createAllMessagesAccount(this);
- BaseAccount unreadAccount = new SearchAccount(this, false, null, null);
- unreadAccount.setDescription(getString(R.string.search_all_messages_title));
- unreadAccount.setEmail(getString(R.string.search_all_messages_detail));
-
- accounts.add(integratedInboxAccount);
- accounts.add(unreadAccount);
+ accounts.add(unifiedInboxAccount);
+ accounts.add(allMessagesAccount);
}
accounts.addAll(Arrays.asList(realAccounts));
diff --git a/src/com/fsck/k9/activity/Accounts.java b/src/com/fsck/k9/activity/Accounts.java
index 031785e62..339494044 100644
--- a/src/com/fsck/k9/activity/Accounts.java
+++ b/src/com/fsck/k9/activity/Accounts.java
@@ -382,16 +382,11 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
/**
- * Creates and initializes the special accounts ('Integrated Inbox' and 'All Messages')
+ * Creates and initializes the special accounts ('Unified Inbox' and 'All Messages')
*/
private void createSpecialAccounts() {
- unreadAccount = new SearchAccount(this, false, null, null);
- unreadAccount.setDescription(getString(R.string.search_all_messages_title));
- unreadAccount.setEmail(getString(R.string.search_all_messages_detail));
-
- integratedInboxAccount = new SearchAccount(this, true, null, null);
- integratedInboxAccount.setDescription(getString(R.string.integrated_inbox_title));
- integratedInboxAccount.setEmail(getString(R.string.integrated_inbox_detail));
+ integratedInboxAccount = SearchAccount.createUnifiedInboxAccount(this);
+ unreadAccount = SearchAccount.createAllMessagesAccount(this);
}
@SuppressWarnings("unchecked")
diff --git a/src/com/fsck/k9/provider/MessageProvider.java b/src/com/fsck/k9/provider/MessageProvider.java
index f2c1ec693..50220c31c 100644
--- a/src/com/fsck/k9/provider/MessageProvider.java
+++ b/src/com/fsck/k9/provider/MessageProvider.java
@@ -60,7 +60,7 @@ public class MessageProvider extends ContentProvider {
*
Type: TEXT
*/
String SENDER = "sender";
-
+
/**
*
Type: TEXT
*/
@@ -245,7 +245,7 @@ public class MessageProvider extends ContentProvider {
final BlockingQueue> queue = new SynchronousQueue>();
// new code for integrated inbox, only execute this once as it will be processed afterwards via the listener
- final SearchAccount integratedInboxAccount = new SearchAccount(getContext(), true, null, null);
+ final SearchAccount integratedInboxAccount = SearchAccount.createUnifiedInboxAccount(getContext());
final MessagingController msgController = MessagingController.getInstance(K9.app);
msgController.searchLocalMessages(integratedInboxAccount, null,
From f1baa8f461c92b4d489e7ac52e0c91cef16eed0f Mon Sep 17 00:00:00 2001
From: m0viefreak
Date: Fri, 2 Mar 2012 05:16:58 +0100
Subject: [PATCH 21/80] invalidate message content WebView when the message
header changes
This fixes redraw issues where text appears doubled or is cut off
---
src/com/fsck/k9/view/MessageHeader.java | 17 +++++++++++++++++
src/com/fsck/k9/view/SingleMessageView.java | 10 +++++++++-
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/src/com/fsck/k9/view/MessageHeader.java b/src/com/fsck/k9/view/MessageHeader.java
index a3f10afad..ed51d70d4 100644
--- a/src/com/fsck/k9/view/MessageHeader.java
+++ b/src/com/fsck/k9/view/MessageHeader.java
@@ -63,6 +63,8 @@ public class MessageHeader extends ScrollView implements OnClickListener {
private ImageView mShowAdditionalHeadersIcon;
private SavedState mSavedState;
+ private OnLayoutChangedListener mOnLayoutChangedListener;
+
/**
* Pair class is only available since API Level 5, so we need
* this helper class unfortunately
@@ -272,6 +274,7 @@ public class MessageHeader extends ScrollView implements OnClickListener {
} else {
showAdditionalHeaders();
}
+ layoutChanged();
}
private List getAdditionalHeaders(final Message message)
@@ -378,4 +381,18 @@ public class MessageHeader extends ScrollView implements OnClickListener {
out.writeInt((this.additionalHeadersVisible) ? 1 : 0);
}
}
+
+ public interface OnLayoutChangedListener {
+ void onLayoutChanged();
+ }
+
+ public void setOnLayoutChangedListener(OnLayoutChangedListener listener) {
+ mOnLayoutChangedListener = listener;
+ }
+
+ private void layoutChanged() {
+ if (mOnLayoutChangedListener != null) {
+ mOnLayoutChangedListener.onLayoutChanged();
+ }
+ }
}
diff --git a/src/com/fsck/k9/view/SingleMessageView.java b/src/com/fsck/k9/view/SingleMessageView.java
index b1e0980e9..a19796d8c 100644
--- a/src/com/fsck/k9/view/SingleMessageView.java
+++ b/src/com/fsck/k9/view/SingleMessageView.java
@@ -33,7 +33,8 @@ import com.fsck.k9.mail.store.LocalStore.LocalMessage;
import java.util.List;
-public class SingleMessageView extends LinearLayout implements OnClickListener {
+public class SingleMessageView extends LinearLayout implements OnClickListener,
+ MessageHeader.OnLayoutChangedListener {
private boolean mScreenReaderEnabled;
private MessageCryptoView mCryptoView;
private MessageWebView mMessageContentView;
@@ -65,6 +66,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
mHeaderPlaceHolder = (LinearLayout) findViewById(R.id.message_view_header_container);
mHeaderContainer = (MessageHeader) findViewById(R.id.header_container);
+ mHeaderContainer.setOnLayoutChangedListener(this);
mAttachmentsContainer = findViewById(R.id.attachments_container);
mInsideAttachmentsContainer = (LinearLayout) findViewById(R.id.inside_attachments_container);
@@ -508,6 +510,12 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
mSavedState = savedState;
}
+ public void onLayoutChanged() {
+ if (mMessageContentView != null) {
+ mMessageContentView.invalidate();
+ }
+ }
+
static class SavedState extends BaseSavedState {
boolean attachmentViewVisible;
boolean hiddenAttachmentsVisible;
From 8d12244a9c23da0b5146afa418f75a4b7e49747d Mon Sep 17 00:00:00 2001
From: m0viefreak
Date: Fri, 2 Mar 2012 05:41:01 +0100
Subject: [PATCH 22/80] Message header changes
* remove expand/collapse arrows, instead use the background area of the header to toggle
* allow expanding of To: and Cc: texts when too long and cut off by clicking on them
---
...xml => message_view_header_background.xml} | 0
res/layout/message_view_header.xml | 50 ++-----------------
src/com/fsck/k9/view/MessageHeader.java | 37 ++++++++++----
3 files changed, 31 insertions(+), 56 deletions(-)
rename res/drawable/{separator_area_background.xml => message_view_header_background.xml} (100%)
diff --git a/res/drawable/separator_area_background.xml b/res/drawable/message_view_header_background.xml
similarity index 100%
rename from res/drawable/separator_area_background.xml
rename to res/drawable/message_view_header_background.xml
diff --git a/res/layout/message_view_header.xml b/res/layout/message_view_header.xml
index fe5c486a0..5b4d0d591 100644
--- a/res/layout/message_view_header.xml
+++ b/res/layout/message_view_header.xml
@@ -17,7 +17,7 @@
android:layout_height="wrap_content"
android:stretchColumns="1"
android:shrinkColumns="1"
- android:background="@color/message_view_header_background">
+ android:background="@drawable/message_view_header_background">
@@ -194,51 +194,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="1.5dp"
+ android:background="#59000000"/>
getAdditionalHeaders(final Message message)
throws MessagingException {
List additionalHeaders = new LinkedList();
From 78615f878d4ea28201e79652bd2c8694a09980a4 Mon Sep 17 00:00:00 2001
From: ashley willis
Date: Mon, 5 Mar 2012 15:17:31 -0600
Subject: [PATCH 23/80] added From: addresses on reply all when Reply-To: is
set. don't repeat address in To: field if it's already included in
replyToAddresses.
---
src/com/fsck/k9/activity/MessageCompose.java | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java
index 927078cf2..8ecc78a08 100644
--- a/src/com/fsck/k9/activity/MessageCompose.java
+++ b/src/com/fsck/k9/activity/MessageCompose.java
@@ -2289,8 +2289,15 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
if (ACTION_REPLY_ALL.equals(action)) {
+ if (message.getReplyTo().length > 0) {
+ for (Address address : message.getFrom()) {
+ if (!mAccount.isAnIdentity(address)) {
+ addAddress(mToView, address);
+ }
+ }
+ }
for (Address address : message.getRecipients(RecipientType.TO)) {
- if (!mAccount.isAnIdentity(address)) {
+ if (!mAccount.isAnIdentity(address) && !Utility.arrayContains(replyToAddresses, address)) {
addAddress(mToView, address);
}
From faf9dc6e0263e7cb3df1d09ebdeea6fb85777df8 Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 6 Mar 2012 04:26:18 +0100
Subject: [PATCH 24/80] Restored show/more less indicator in the message header
---
res/layout/message_view_header.xml | 62 ++++++++++++++++++++++++-
src/com/fsck/k9/view/MessageHeader.java | 11 ++++-
2 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/res/layout/message_view_header.xml b/res/layout/message_view_header.xml
index 5b4d0d591..19bd2a52d 100644
--- a/res/layout/message_view_header.xml
+++ b/res/layout/message_view_header.xml
@@ -30,6 +30,7 @@
@@ -134,14 +135,56 @@
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -188,6 +231,21 @@
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="?android:attr/textAppearanceSmall"/>
+
+
+
+
+
diff --git a/src/com/fsck/k9/view/MessageHeader.java b/src/com/fsck/k9/view/MessageHeader.java
index f3f3b9a32..277885b95 100644
--- a/src/com/fsck/k9/view/MessageHeader.java
+++ b/src/com/fsck/k9/view/MessageHeader.java
@@ -59,6 +59,7 @@ public class MessageHeader extends ScrollView implements OnClickListener {
private Account mAccount;
private FontSizes mFontSizes = K9.getFontSizes();
private Contacts mContacts;
+ private ImageView mShowAdditionalHeadersIcon;
private SavedState mSavedState;
private OnLayoutChangedListener mOnLayoutChangedListener;
@@ -98,6 +99,7 @@ public class MessageHeader extends ScrollView implements OnClickListener {
mDateView = (TextView) findViewById(R.id.date);
mTimeView = (TextView) findViewById(R.id.time);
mFlagged = (CheckBox) findViewById(R.id.flagged);
+ mShowAdditionalHeadersIcon = (ImageView) findViewById(R.id.show_additional_headers_icon);
defaultSubjectColor = mSubjectView.getCurrentTextColor();
mSubjectView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageViewSubject());
@@ -113,10 +115,13 @@ public class MessageHeader extends ScrollView implements OnClickListener {
((TextView) findViewById(R.id.to_label)).setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageViewTo());
((TextView) findViewById(R.id.cc_label)).setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageViewCC());
- mToView.setOnClickListener(this);
- mCcView.setOnClickListener(this);
mFromView.setOnClickListener(this);
findViewById(R.id.top_container).setOnClickListener(this);
+
+ TextView dummyDateView = (TextView) findViewById(R.id.dummy_date);
+ TextView dummyTimeView = (TextView) findViewById(R.id.dummy_time);
+ dummyTimeView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageViewTime());
+ dummyDateView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageViewDate());
}
@Override
@@ -168,6 +173,7 @@ public class MessageHeader extends ScrollView implements OnClickListener {
private void hideAdditionalHeaders() {
mAdditionalHeadersView.setVisibility(View.GONE);
mAdditionalHeadersView.setText("");
+ mShowAdditionalHeadersIcon.setImageResource(R.drawable.show_more);
}
@@ -186,6 +192,7 @@ public class MessageHeader extends ScrollView implements OnClickListener {
// Show the additional headers that we have got.
populateAdditionalHeadersView(additionalHeaders);
mAdditionalHeadersView.setVisibility(View.VISIBLE);
+ mShowAdditionalHeadersIcon.setImageResource(R.drawable.show_less);
}
if (!allHeadersDownloaded) {
/*
From 4721d92e7909fd00619a02571916c438ec5b395b Mon Sep 17 00:00:00 2001
From: cketti
Date: Wed, 7 Mar 2012 21:40:41 +0100
Subject: [PATCH 25/80] Avoid some instances of autoboxing
This will hopefully allow us to compile with "Android Java IDE".
---
src/com/fsck/k9/activity/MessageCompose.java | 10 +++++-----
src/com/fsck/k9/controller/MessagingController.java | 10 ++++++++--
2 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java
index 8ecc78a08..e14c34c8e 100644
--- a/src/com/fsck/k9/activity/MessageCompose.java
+++ b/src/com/fsck/k9/activity/MessageCompose.java
@@ -2427,19 +2427,19 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
updateFrom();
Integer bodyLength = k9identity.get(IdentityField.LENGTH) != null
- ? Integer.parseInt(k9identity.get(IdentityField.LENGTH))
+ ? Integer.valueOf(k9identity.get(IdentityField.LENGTH))
: 0;
Integer bodyOffset = k9identity.get(IdentityField.OFFSET) != null
- ? Integer.parseInt(k9identity.get(IdentityField.OFFSET))
+ ? Integer.valueOf(k9identity.get(IdentityField.OFFSET))
: 0;
Integer bodyFooterOffset = k9identity.get(IdentityField.FOOTER_OFFSET) != null
- ? Integer.parseInt(k9identity.get(IdentityField.FOOTER_OFFSET))
+ ? Integer.valueOf(k9identity.get(IdentityField.FOOTER_OFFSET))
: null;
Integer bodyPlainLength = k9identity.get(IdentityField.PLAIN_LENGTH) != null
- ? Integer.parseInt(k9identity.get(IdentityField.PLAIN_LENGTH))
+ ? Integer.valueOf(k9identity.get(IdentityField.PLAIN_LENGTH))
: null;
Integer bodyPlainOffset = k9identity.get(IdentityField.PLAIN_OFFSET) != null
- ? Integer.parseInt(k9identity.get(IdentityField.PLAIN_OFFSET))
+ ? Integer.valueOf(k9identity.get(IdentityField.PLAIN_OFFSET))
: null;
mQuoteStyle = k9identity.get(IdentityField.QUOTE_STYLE) != null
? QuoteStyle.valueOf(k9identity.get(IdentityField.QUOTE_STYLE))
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 023d19f60..250e3fb3d 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -629,7 +629,7 @@ public class MessagingController implements Runnable {
Log.i(K9.LOG_TAG, "searchLocalMessages ("
+ "accountUuids=" + Utility.combine(accountUuids, ',')
+ ", folderNames = " + Utility.combine(folderNames, ',')
- + ", messages.size() = " + (messages != null ? messages.length : null)
+ + ", messages.size() = " + (messages != null ? messages.length : -1)
+ ", query = " + query
+ ", integrate = " + integrate
+ ", requiredFlags = " + Utility.combine(requiredFlags, ',')
@@ -4182,7 +4182,13 @@ public class MessagingController implements Runnable {
NotificationSetting n = account.getNotificationSetting();
- configureNotification(notif, (n.shouldRing() ? n.getRingtone() : null), (n.shouldVibrate() ? n.getVibration() : null), (n.isLed() ? n.getLedColor() : null), K9.NOTIFICATION_LED_BLINK_SLOW, ringAndVibrate);
+ configureNotification(
+ notif,
+ (n.shouldRing()) ? n.getRingtone() : null,
+ (n.shouldVibrate()) ? n.getVibration() : null,
+ (n.isLed()) ? Integer.valueOf(n.getLedColor()) : null,
+ K9.NOTIFICATION_LED_BLINK_SLOW,
+ ringAndVibrate);
notifMgr.notify(account.getAccountNumber(), notif);
}
From ee34344d30fded0c3cba2b489a3462b271ff97a8 Mon Sep 17 00:00:00 2001
From: cketti
Date: Wed, 7 Mar 2012 21:52:47 +0100
Subject: [PATCH 26/80] Upgrade to SDK 15
---
project.properties | 2 +-
src/com/fsck/k9/preferences/Editor.java | 6 ++++
src/com/fsck/k9/preferences/Storage.java | 7 ++++
src/com/fsck/k9/provider/MessageProvider.java | 32 +++++++++++--------
4 files changed, 33 insertions(+), 14 deletions(-)
diff --git a/project.properties b/project.properties
index 213821e1f..46fb34716 100644
--- a/project.properties
+++ b/project.properties
@@ -11,5 +11,5 @@
split.density=false
java.encoding=utf8
# Project target.
-target=android-9
+target=android-15
extensible.libs.classpath=compile-only-libs
diff --git a/src/com/fsck/k9/preferences/Editor.java b/src/com/fsck/k9/preferences/Editor.java
index 412d14ff8..88479d0e2 100644
--- a/src/com/fsck/k9/preferences/Editor.java
+++ b/src/com/fsck/k9/preferences/Editor.java
@@ -7,6 +7,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
public class Editor implements android.content.SharedPreferences.Editor {
private Storage storage;
@@ -138,4 +139,9 @@ public class Editor implements android.content.SharedPreferences.Editor {
return this;
}
+ @Override
+ public android.content.SharedPreferences.Editor putStringSet(String arg0, Set arg1) {
+ throw new RuntimeException("Not implemented");
+ }
+
}
diff --git a/src/com/fsck/k9/preferences/Storage.java b/src/com/fsck/k9/preferences/Storage.java
index 34c978754..b9041c8f6 100644
--- a/src/com/fsck/k9/preferences/Storage.java
+++ b/src/com/fsck/k9/preferences/Storage.java
@@ -15,6 +15,7 @@ import java.net.URI;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -399,4 +400,10 @@ public class Storage implements SharedPreferences {
Log.e(K9.LOG_TAG, "Error writing key '" + key + "', value = '" + value + "'");
}
}
+
+
+ @Override
+ public Set getStringSet(String arg0, Set arg1) {
+ throw new RuntimeException("Not implemented");
+ }
}
diff --git a/src/com/fsck/k9/provider/MessageProvider.java b/src/com/fsck/k9/provider/MessageProvider.java
index 50220c31c..0557575af 100644
--- a/src/com/fsck/k9/provider/MessageProvider.java
+++ b/src/com/fsck/k9/provider/MessageProvider.java
@@ -1,18 +1,5 @@
package com.fsck.k9.provider;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -46,6 +33,19 @@ import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.store.LocalStore;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
public class MessageProvider extends ContentProvider {
public static interface MessageColumns extends BaseColumns {
@@ -714,6 +714,12 @@ public class MessageProvider extends ContentProvider {
checkClosed();
mCursor.unregisterDataSetObserver(observer);
}
+
+ @Override
+ public int getType(int columnIndex) {
+ checkClosed();
+ return mCursor.getType(columnIndex);
+ }
}
protected class ThrottlingQueryHandler implements QueryHandler {
From 7163d39091b2a32724d9767b5ebf92dcb786a90b Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 9 Mar 2012 21:50:26 +0100
Subject: [PATCH 27/80] Change ImapException to always be a permanent error
This way IMAP commands that get anything but an "OK" response are never
tried again (pending actions).
---
src/com/fsck/k9/mail/store/ImapStore.java | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 6a77db634..008d8d45a 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -2735,13 +2735,8 @@ public class ImapStore extends Store {
private static final long serialVersionUID = 3725007182205882394L;
String mAlertText;
- public ImapException(String message, String alertText, Throwable throwable) {
- super(message, throwable);
- this.mAlertText = alertText;
- }
-
public ImapException(String message, String alertText) {
- super(message);
+ super(message, true);
this.mAlertText = alertText;
}
From 0cb4207ef73027e86feee4400647ad8f10f777d9 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 9 Mar 2012 21:51:48 +0100
Subject: [PATCH 28/80] IMAP: don't create the destination folder when copying
messages
---
src/com/fsck/k9/mail/store/ImapStore.java | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 008d8d45a..043920aa6 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -1101,15 +1101,6 @@ public class ImapStore extends Store {
try {
String remoteDestName = encodeString(encodeFolderName(iFolder.getPrefixedName()));
- if (!exists(remoteDestName)) {
- // If the remote trash folder doesn't exist we try to create it.
- if (K9.DEBUG) {
- Log.i(K9.LOG_TAG, "Attempting to create remote folder '" + remoteDestName +
- "' for " + getLogId());
- }
- iFolder.create(FolderType.HOLDS_MESSAGES);
- }
-
//TODO: Split this into multiple commands if the command exceeds a certain length.
mConnection.sendCommand(String.format("UID COPY %s %s",
Utility.combine(uids, ','),
From dda072eff65c135a59da78b8b04482471e9ad199 Mon Sep 17 00:00:00 2001
From: ashley willis
Date: Sun, 11 Mar 2012 14:31:35 -0500
Subject: [PATCH 29/80] Upgrade to SDK 15
---
ant.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ant.properties b/ant.properties
index cfc6e1ad4..6be7f3220 100644
--- a/ant.properties
+++ b/ant.properties
@@ -19,5 +19,5 @@
split.density=false
java.encoding=utf8
# Project target.
-target=android-9
+target=android-15
extensible.libs.classpath=compile-only-libs
From f9a30d1822b0de034bab4d08b1e9392b7d7e69e4 Mon Sep 17 00:00:00 2001
From: ashley willis
Date: Sun, 11 Mar 2012 17:48:56 -0500
Subject: [PATCH 30/80] added sort by arrival option.
---
res/menu/message_list_option.xml | 4 ++++
res/values/strings.xml | 1 +
src/com/fsck/k9/activity/MessageInfoHolder.java | 1 +
src/com/fsck/k9/activity/MessageList.java | 16 +++++++++++++++-
.../fsck/k9/controller/MessagingController.java | 1 +
src/com/fsck/k9/helper/MessageHelper.java | 1 +
6 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/res/menu/message_list_option.xml b/res/menu/message_list_option.xml
index 2aa550a0f..b8bbf03a7 100644
--- a/res/menu/message_list_option.xml
+++ b/res/menu/message_list_option.xml
@@ -15,6 +15,10 @@
android:id="@+id/set_sort_date"
android:title="@string/sort_by_date"
/>
+ Sort by...Date
+ ArrivalSenderSubjectStar
diff --git a/src/com/fsck/k9/activity/MessageInfoHolder.java b/src/com/fsck/k9/activity/MessageInfoHolder.java
index e19fb953a..baee99b9a 100644
--- a/src/com/fsck/k9/activity/MessageInfoHolder.java
+++ b/src/com/fsck/k9/activity/MessageInfoHolder.java
@@ -7,6 +7,7 @@ import com.fsck.k9.mail.store.LocalStore.LocalMessage;
public class MessageInfoHolder {
public String date;
public Date compareDate;
+ public Date compareArrival;
public String compareSubject;
public CharSequence sender;
public String senderAddress;
diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index f874267f9..aec709cfe 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -185,6 +185,15 @@ public class MessageList
}
+ public static class ArrivalComparator implements Comparator {
+
+ @Override
+ public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
+ return object1.compareArrival.compareTo(object2.compareArrival);
+ }
+
+ }
+
public static class SubjectComparator implements Comparator {
@Override
@@ -234,6 +243,7 @@ public class MessageList
final Map> map = new EnumMap>(SORT_TYPE.class);
map.put(SORT_TYPE.SORT_ATTACHMENT, new AttachmentComparator());
map.put(SORT_TYPE.SORT_DATE, new DateComparator());
+ map.put(SORT_TYPE.SORT_ARRIVAL, new ArrivalComparator());
map.put(SORT_TYPE.SORT_FLAGGED, new FlaggedComparator());
map.put(SORT_TYPE.SORT_SENDER, new SenderComparator());
map.put(SORT_TYPE.SORT_SUBJECT, new SubjectComparator());
@@ -460,7 +470,7 @@ public class MessageList
{
// add the date comparator if not already specified
- if (sortType != SORT_TYPE.SORT_DATE) {
+ if (sortType != SORT_TYPE.SORT_DATE && sortType != SORT_TYPE.SORT_ARRIVAL) {
final Comparator comparator = SORT_COMPARATORS.get(SORT_TYPE.SORT_DATE);
if (sortDateAscending) {
chain.add(comparator);
@@ -1439,6 +1449,10 @@ public class MessageList
changeSort(SORT_TYPE.SORT_DATE);
return true;
}
+ case R.id.set_sort_arrival: {
+ changeSort(SORT_TYPE.SORT_ARRIVAL);
+ return true;
+ }
case R.id.set_sort_subject: {
changeSort(SORT_TYPE.SORT_SUBJECT);
return true;
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 250e3fb3d..33acd96f1 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -146,6 +146,7 @@ public class MessagingController implements Runnable {
public enum SORT_TYPE {
SORT_DATE(R.string.sort_earliest_first, R.string.sort_latest_first, false),
+ SORT_ARRIVAL(R.string.sort_earliest_first, R.string.sort_latest_first, false),
SORT_SUBJECT(R.string.sort_subject_alpha, R.string.sort_subject_re_alpha, true),
SORT_SENDER(R.string.sort_sender_alpha, R.string.sort_sender_re_alpha, true),
SORT_UNREAD(R.string.sort_unread_first, R.string.sort_unread_last, true),
diff --git a/src/com/fsck/k9/helper/MessageHelper.java b/src/com/fsck/k9/helper/MessageHelper.java
index 43b208a77..018b481e2 100644
--- a/src/com/fsck/k9/helper/MessageHelper.java
+++ b/src/com/fsck/k9/helper/MessageHelper.java
@@ -49,6 +49,7 @@ public class MessageHelper {
try {
LocalMessage message = (LocalMessage) m;
target.message = message;
+ target.compareArrival = message.getInternalDate();
target.compareDate = message.getSentDate();
if (target.compareDate == null) {
target.compareDate = message.getInternalDate();
From 561d2a1a44ae6e9615b9a9c04d8a040b4a724690 Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 12 Mar 2012 17:44:53 +0100
Subject: [PATCH 31/80] Added unit test for MimeUtility.getHeaderParameter()
---
.../k9/mail/internet/MimeUtilityTest.java | 39 +++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 tests/src/com/fsck/k9/mail/internet/MimeUtilityTest.java
diff --git a/tests/src/com/fsck/k9/mail/internet/MimeUtilityTest.java b/tests/src/com/fsck/k9/mail/internet/MimeUtilityTest.java
new file mode 100644
index 000000000..8bf122395
--- /dev/null
+++ b/tests/src/com/fsck/k9/mail/internet/MimeUtilityTest.java
@@ -0,0 +1,39 @@
+package com.fsck.k9.mail.internet;
+
+import android.test.AndroidTestCase;
+
+public class MimeUtilityTest extends AndroidTestCase {
+
+ public void testGetHeaderParameter() {
+ String result;
+
+ /* Test edge cases */
+ result = MimeUtility.getHeaderParameter(";", null);
+ assertEquals(null, result);
+
+ result = MimeUtility.getHeaderParameter("name", "name");
+ assertEquals(null, result);
+
+ result = MimeUtility.getHeaderParameter("name=", "name");
+ assertEquals("", result);
+
+ result = MimeUtility.getHeaderParameter("name=\"", "name");
+ assertEquals("\"", result);
+
+ /* Test expected cases */
+ result = MimeUtility.getHeaderParameter("name=value", "name");
+ assertEquals("value", result);
+
+ result = MimeUtility.getHeaderParameter("name = value", "name");
+ assertEquals("value", result);
+
+ result = MimeUtility.getHeaderParameter("name=\"value\"", "name");
+ assertEquals("value", result);
+
+ result = MimeUtility.getHeaderParameter("name = \"value\"" , "name");
+ assertEquals("value", result);
+
+ result = MimeUtility.getHeaderParameter("name=\"\"", "name");
+ assertEquals("", result);
+ }
+}
From aeb0220e56b4717e4af262097f391d42fd3a3a4b Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 12 Mar 2012 17:45:34 +0100
Subject: [PATCH 32/80] Fixed MimeUtility.getHeaderParameter() to not crash on
unexpected input
---
src/com/fsck/k9/mail/internet/MimeUtility.java | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 405243d4b..0b8caf71f 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -953,16 +953,20 @@ public class MimeUtility {
}
header = header.replaceAll("\r|\n", "");
String[] parts = header.split(";");
- if (name == null) {
+ if (name == null && parts.length > 0) {
return parts[0];
}
for (String part : parts) {
if (part.trim().toLowerCase(Locale.US).startsWith(name.toLowerCase(Locale.US))) {
- String parameter = part.split("=", 2)[1].trim();
- if (parameter.startsWith("\"") && parameter.endsWith("\"")) {
- return parameter.substring(1, parameter.length() - 1);
- } else {
- return parameter;
+ String[] partParts = part.split("=", 2);
+ if (partParts.length == 2) {
+ String parameter = partParts[1].trim();
+ int len = parameter.length();
+ if (len >= 2 && parameter.startsWith("\"") && parameter.endsWith("\"")) {
+ return parameter.substring(1, len - 1);
+ } else {
+ return parameter;
+ }
}
}
}
From f181e923ca8bb4f75f250f6f56f8b4409e0a4ae3 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 15 Mar 2012 21:21:00 +0100
Subject: [PATCH 33/80] Don't modify draft messages when storing them in the
database
---
.../fsck/k9/mail/internet/MimeUtility.java | 57 +++++++++++++++++++
src/com/fsck/k9/mail/store/LocalStore.java | 27 +++++++--
2 files changed, 79 insertions(+), 5 deletions(-)
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 0b8caf71f..0405fd567 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -3260,4 +3260,61 @@ public class MimeUtility {
return charset;
}
+
+ public static ViewableContainer extractPartsFromDraft(Message message)
+ throws MessagingException {
+
+ Body body = message.getBody();
+ if (message.isMimeType("multipart/mixed") && body instanceof MimeMultipart) {
+ MimeMultipart multipart = (MimeMultipart) body;
+
+ ViewableContainer container;
+ int count = multipart.getCount();
+ if (count >= 1) {
+ // The first part is either a text/plain or a multipart/alternative
+ BodyPart firstPart = multipart.getBodyPart(0);
+ container = extractTextual(firstPart);
+
+ // The rest should be attachments
+ for (int i = 1; i < count; i++) {
+ BodyPart bodyPart = multipart.getBodyPart(i);
+ container.attachments.add(bodyPart);
+ }
+ } else {
+ container = new ViewableContainer(null, null, new ArrayList());
+ }
+
+ return container;
+ }
+
+ return extractTextual(message);
+ }
+
+ private static ViewableContainer extractTextual(Part part) throws MessagingException {
+ String text = null;
+ String html = null;
+ List attachments = new ArrayList();
+
+ Body firstBody = part.getBody();
+ if (part.isMimeType("text/plain") &&
+ firstBody instanceof TextBody) {
+ text = ((TextBody) firstBody).getText();
+ } else if (part.isMimeType("multipart/alternative") &&
+ firstBody instanceof MimeMultipart) {
+ MimeMultipart multipart = (MimeMultipart) firstBody;
+ for (int i = 0, count = multipart.getCount(); i < count; i++) {
+ BodyPart bodyPart = multipart.getBodyPart(i);
+ if (bodyPart.getBody() instanceof TextBody) {
+ TextBody textBody = (TextBody) bodyPart.getBody();
+ if (text == null && bodyPart.isMimeType("text/plain")) {
+ text = textBody.getText();
+ } else if (html == null && bodyPart.isMimeType("text/html")) {
+ html = textBody.getText();
+ }
+ }
+ }
+ }
+
+ return new ViewableContainer(text, html, attachments);
+ }
}
diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java
index f9d769511..64d89610c 100644
--- a/src/com/fsck/k9/mail/store/LocalStore.java
+++ b/src/com/fsck/k9/mail/store/LocalStore.java
@@ -2134,12 +2134,29 @@ public class LocalStore extends Store implements Serializable {
deleteAttachments(message.getUid());
}
- ViewableContainer container =
- MimeUtility.extractTextAndAttachments(mApplication, message);
+ boolean isDraft = (message.getHeader(K9.IDENTITY_HEADER) != null);
- List attachments = container.attachments;
- String text = container.text;
- String html = HtmlConverter.convertEmoji2Img(container.html);
+ List attachments;
+ String text;
+ String html;
+ if (isDraft) {
+ // Don't modify the text/plain or text/html part of our own
+ // draft messages because this will cause the values stored in
+ // the identity header to be wrong.
+ ViewableContainer container =
+ MimeUtility.extractPartsFromDraft(message);
+
+ text = container.text;
+ html = container.html;
+ attachments = container.attachments;
+ } else {
+ ViewableContainer container =
+ MimeUtility.extractTextAndAttachments(mApplication, message);
+
+ attachments = container.attachments;
+ text = container.text;
+ html = HtmlConverter.convertEmoji2Img(container.html);
+ }
String preview = calculateContentPreview(text);
From a48adafbbc99ce2b0ad275060f2045d1f8199328 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 16 Mar 2012 22:56:09 +0100
Subject: [PATCH 34/80] Don't use null for 'text' and 'html' in
ViewableContainer
---
src/com/fsck/k9/mail/internet/MimeUtility.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 0405fd567..1c43d3b58 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -3281,7 +3281,7 @@ public class MimeUtility {
container.attachments.add(bodyPart);
}
} else {
- container = new ViewableContainer(null, null, new ArrayList());
+ container = new ViewableContainer("", "", new ArrayList());
}
return container;
@@ -3291,8 +3291,8 @@ public class MimeUtility {
}
private static ViewableContainer extractTextual(Part part) throws MessagingException {
- String text = null;
- String html = null;
+ String text = "";
+ String html = "";
List attachments = new ArrayList();
Body firstBody = part.getBody();
From dbf38dae653aa2fdfe2372cec2ab2e19bea5f5c7 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 17 Mar 2012 00:30:40 +0100
Subject: [PATCH 35/80] Fixed the change of the previous commit
---
src/com/fsck/k9/mail/internet/MimeUtility.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 1c43d3b58..20486232c 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -3306,9 +3306,9 @@ public class MimeUtility {
BodyPart bodyPart = multipart.getBodyPart(i);
if (bodyPart.getBody() instanceof TextBody) {
TextBody textBody = (TextBody) bodyPart.getBody();
- if (text == null && bodyPart.isMimeType("text/plain")) {
+ if ("".equals(text) && bodyPart.isMimeType("text/plain")) {
text = textBody.getText();
- } else if (html == null && bodyPart.isMimeType("text/html")) {
+ } else if ("".equals(html) && bodyPart.isMimeType("text/html")) {
html = textBody.getText();
}
}
From 3fa8081e88e0b035377c721fd21676a735d82baf Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 17 Mar 2012 03:19:09 +0100
Subject: [PATCH 36/80] Fixed MimeUtility.extractTextual() when loading
messages from the server
---
src/com/fsck/k9/mail/internet/MimeUtility.java | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 20486232c..eb6948c11 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -3304,12 +3304,12 @@ public class MimeUtility {
MimeMultipart multipart = (MimeMultipart) firstBody;
for (int i = 0, count = multipart.getCount(); i < count; i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
- if (bodyPart.getBody() instanceof TextBody) {
- TextBody textBody = (TextBody) bodyPart.getBody();
- if ("".equals(text) && bodyPart.isMimeType("text/plain")) {
- text = textBody.getText();
- } else if ("".equals(html) && bodyPart.isMimeType("text/html")) {
- html = textBody.getText();
+ String bodyText = getTextFromPart(bodyPart);
+ if (bodyText != null) {
+ if (text.length() == 0 && bodyPart.isMimeType("text/plain")) {
+ text = bodyText;
+ } else if (html.length() == 0 && bodyPart.isMimeType("text/html")) {
+ html = bodyText;
}
}
}
From f9a35aeaeeae67bd88c3b253c25d06832ca7da73 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 17 Mar 2012 04:15:30 +0100
Subject: [PATCH 37/80] Replace CRLF with LF when loading drafts
This is necessary because we save the offset and length of the user-
supplied text in the identity header. These values are then later used
to split the draft in user text and quoted message.
When calculating these values we operate on a string with LF line
endings. Ideally we want to do the reverse operation on the same
string, but when saving the message to the server LF is converted to
CRLF to create RFC-conforming messages.
This is only a hack and will probably be the cause of more trouble in
the future. A better solution would be to make the identity header more
robust or get rid of it entirely.
---
.../fsck/k9/mail/internet/MimeUtility.java | 29 +++++++++++++++----
1 file changed, 24 insertions(+), 5 deletions(-)
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index eb6948c11..842a7cc8d 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -3296,9 +3296,11 @@ public class MimeUtility {
List attachments = new ArrayList();
Body firstBody = part.getBody();
- if (part.isMimeType("text/plain") &&
- firstBody instanceof TextBody) {
- text = ((TextBody) firstBody).getText();
+ if (part.isMimeType("text/plain")) {
+ String bodyText = getTextFromPart(part);
+ if (bodyText != null) {
+ text = fixDraftTextBody(bodyText);
+ }
} else if (part.isMimeType("multipart/alternative") &&
firstBody instanceof MimeMultipart) {
MimeMultipart multipart = (MimeMultipart) firstBody;
@@ -3307,9 +3309,9 @@ public class MimeUtility {
String bodyText = getTextFromPart(bodyPart);
if (bodyText != null) {
if (text.length() == 0 && bodyPart.isMimeType("text/plain")) {
- text = bodyText;
+ text = fixDraftTextBody(bodyText);
} else if (html.length() == 0 && bodyPart.isMimeType("text/html")) {
- html = bodyText;
+ html = fixDraftTextBody(bodyText);
}
}
}
@@ -3317,4 +3319,21 @@ public class MimeUtility {
return new ViewableContainer(text, html, attachments);
}
+
+ /**
+ * Fix line endings of text bodies in draft messages.
+ *
+ *
+ * We create drafts with LF line endings. The values in the identity header are based on that.
+ * So we replace CRLF with LF when loading messages (from the server).
+ *
+ *
+ * @param text
+ * The body text with CRLF line endings
+ *
+ * @return The text with LF line endings
+ */
+ private static String fixDraftTextBody(String text) {
+ return text.replace("\r\n", "\n");
+ }
}
From 8192d54cce6d5f0796ad9a806627dd9b11249238 Mon Sep 17 00:00:00 2001
From: Koji Arai
Date: Sat, 17 Mar 2012 23:08:14 +0900
Subject: [PATCH 38/80] Updated Japanese translation. catch up with f9a30d1.
---
res/values-ja/strings.xml | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 55815636e..794a17cf2 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -287,8 +287,11 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
SDカードに添付ファイルを保存できません\"画像表示\"ボタンを押下すると描画します画像表示
- 添付取込中
- 添付ファイルのビューワー見つけられません .%s
+ メッセージ表示
+ 添付ファイル表示
+ 他…
+ 添付ファイル取得中
+ %sのビューワーが見つかりませんすべてダウンロード
@@ -777,6 +780,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
並べ替え...日付
+ 受信順送信者件名フラグ
From 39f2138292225c1b904c5bfbeec41e58c20d100b Mon Sep 17 00:00:00 2001
From: Koji Arai
Date: Sun, 4 Mar 2012 09:47:29 +0900
Subject: [PATCH 39/80] added a Japanese provider "auone.jp"
---
res/values-ja/strings.xml | 4 +++-
res/values/strings.xml | 1 +
res/xml/providers.xml | 5 +++++
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 794a17cf2..4c678800b 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -799,7 +799,9 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
このプログラムでPOPアクセスが許可されているのは一部の「Plus」アカウントだけです。有料の「Plus」アカウントがなければ、正しいメールアドレスとパスワードを入力してもログインできません。これらのアカウントにはブラウザからアクセスしてください。
- Yahoo! JapanでPOP3アクセスを使う場合は、Yahoo!メールサイトの「メールの設定」にてPOPアクセスが許可されていることを確認してください。
+ Yahoo! JapanでPOP3アクセスを行う場合は、Yahoo!メールサイトの「メールの設定」にてPOPアクセスが許可されていることを確認してください。
+
+ au oneでIMAPアクセスを行う場合は、au oneポータルサイトの「メール」→「設定」ページにて「IMAPを有効にする」をチェックしてください。証明書が無効です許可
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d7ad77b8d..820960b66 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -805,6 +805,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
\"Plus\" account. Please launch the Web browser to gain access to
these mail accounts.If you would like to use POP3 for this provider, You should permit to use POP3 on Yahoo mail settings page.
+ If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on au one mail settings page.If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Naver mail settings page.If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Hanmail(Daum) mail settings page.If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Paran mail settings page.
diff --git a/res/xml/providers.xml b/res/xml/providers.xml
index a00108996..d94d929a7 100644
--- a/res/xml/providers.xml
+++ b/res/xml/providers.xml
@@ -283,6 +283,11 @@
+
+
+
+
Date: Wed, 29 Feb 2012 00:51:02 +0900
Subject: [PATCH 40/80] avoid NPE. address may be null when the parser is
failed.
---
src/com/fsck/k9/mail/internet/MimeUtility.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 842a7cc8d..13ebc9304 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -2182,6 +2182,8 @@ public class MimeUtility {
}
private static String getJisVariantFromAddress(String address) {
+ if (address == null)
+ return null;
if (isInDomain(address, "docomo.ne.jp") || isInDomain(address, "dwmail.jp") ||
isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com"))
return "docomo";
From 10c37942a632dc1a05cbf7624e0739a7e624ae02 Mon Sep 17 00:00:00 2001
From: Koji Arai
Date: Wed, 7 Mar 2012 00:56:33 +0900
Subject: [PATCH 41/80] Added two domains handle docomo emoji
---
src/com/fsck/k9/mail/internet/MimeUtility.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 13ebc9304..e1908670d 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -2185,7 +2185,8 @@ public class MimeUtility {
if (address == null)
return null;
if (isInDomain(address, "docomo.ne.jp") || isInDomain(address, "dwmail.jp") ||
- isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com"))
+ isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com") ||
+ isInDomain(address, "emnet.ne.jp") || isInDomain(address, "emobile.ne.jp"))
return "docomo";
else if (isInDomain(address, "softbank.ne.jp") || isInDomain(address, "vodafone.ne.jp") ||
isInDomain(address, "disney.ne.jp") || isInDomain(address, "vertuclub.ne.jp"))
From ef01dc906b1b006a0bab045ebd426281407c2558 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 17 Mar 2012 18:27:17 +0100
Subject: [PATCH 42/80] Use AlertDialog's ListView on import instead of
creating our own
This fixes a display problem when using the dark theme.
---
src/com/fsck/k9/activity/Accounts.java | 52 +++++++++++---------------
1 file changed, 22 insertions(+), 30 deletions(-)
diff --git a/src/com/fsck/k9/activity/Accounts.java b/src/com/fsck/k9/activity/Accounts.java
index 339494044..d31bced32 100644
--- a/src/com/fsck/k9/activity/Accounts.java
+++ b/src/com/fsck/k9/activity/Accounts.java
@@ -21,6 +21,7 @@ import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -45,12 +46,10 @@ import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
-import android.widget.CheckedTextView;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
-import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
@@ -58,7 +57,6 @@ import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.fsck.k9.Account;
@@ -1464,8 +1462,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
private static class ImportSelectionDialog implements NonConfigurationInstance {
private ImportContents mImportContents;
private Uri mUri;
- private Dialog mDialog;
- private ListView mImportSelectionView;
+ private AlertDialog mDialog;
private SparseBooleanArray mSelection;
@@ -1483,8 +1480,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
public boolean retain() {
if (mDialog != null) {
// Save the selection state of each list item
- mSelection = mImportSelectionView.getCheckedItemPositions();
- mImportSelectionView = null;
+ mSelection = mDialog.getListView().getCheckedItemPositions();
mDialog.dismiss();
mDialog = null;
@@ -1498,8 +1494,6 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
public void show(final Accounts activity, SparseBooleanArray selection) {
- final ListView importSelectionView = new ListView(activity);
- mImportSelectionView = importSelectionView;
List contents = new ArrayList();
if (mImportContents.globalSettings) {
@@ -1510,23 +1504,15 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
contents.add(account.name);
}
- importSelectionView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- importSelectionView.setAdapter(new ArrayAdapter(activity,
- android.R.layout.simple_list_item_checked, contents));
- importSelectionView.setOnItemSelectedListener(new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView> parent, View view, int pos, long id) {
- CheckedTextView ctv = (CheckedTextView)view;
- ctv.setChecked(!ctv.isChecked());
- }
-
- @Override
- public void onNothingSelected(AdapterView> arg0) { /* Do nothing */ }
- });
-
+ int count = contents.size();
+ boolean[] checkedItems = new boolean[count];
if (selection != null) {
- for (int i = 0, end = contents.size(); i < end; i++) {
- importSelectionView.setItemChecked(i, selection.get(i));
+ for (int i = 0; i < count; i++) {
+ checkedItems[i] = selection.get(i);
+ }
+ } else {
+ for (int i = 0; i < count; i++) {
+ checkedItems[i] = true;
}
}
@@ -1534,23 +1520,29 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
//TODO: listview footer: "Select all" / "Select none" buttons?
//TODO: listview footer: "Overwrite existing accounts?" checkbox
+ OnMultiChoiceClickListener listener = new OnMultiChoiceClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+ ((AlertDialog) dialog).getListView().setItemChecked(which, isChecked);
+ }
+ };
+
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setMultiChoiceItems(contents.toArray(new String[0]), checkedItems, listener);
builder.setTitle(activity.getString(R.string.settings_import_selection));
- builder.setView(importSelectionView);
builder.setInverseBackgroundForced(true);
builder.setPositiveButton(R.string.okay_action,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- ListAdapter adapter = importSelectionView.getAdapter();
- int count = adapter.getCount();
- SparseBooleanArray pos = importSelectionView.getCheckedItemPositions();
+ ListView listView = ((AlertDialog) dialog).getListView();
+ SparseBooleanArray pos = listView.getCheckedItemPositions();
boolean includeGlobals = mImportContents.globalSettings ? pos.get(0) : false;
List accountUuids = new ArrayList();
int start = mImportContents.globalSettings ? 1 : 0;
- for (int i = start; i < count; i++) {
+ for (int i = start, end = listView.getCount(); i < end; i++) {
if (pos.get(i)) {
accountUuids.add(mImportContents.accounts.get(i-start).uuid);
}
From 69ee6a48187d7c1cde3bc3cdb292f4858d7c5c56 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 17 Mar 2012 20:12:33 +0100
Subject: [PATCH 43/80] Avoid NullPointerException in Accounts.onCreateDialog()
Also cleaned up code formatting of onCreateDialog() and
onPrepareDialog().
---
src/com/fsck/k9/activity/Accounts.java | 195 ++++++++++++++-----------
1 file changed, 108 insertions(+), 87 deletions(-)
diff --git a/src/com/fsck/k9/activity/Accounts.java b/src/com/fsck/k9/activity/Accounts.java
index d31bced32..bb8d9a96a 100644
--- a/src/com/fsck/k9/activity/Accounts.java
+++ b/src/com/fsck/k9/activity/Accounts.java
@@ -918,107 +918,128 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
@Override
public Dialog onCreateDialog(int id) {
+ // Android recreates our dialogs on configuration changes even when they have been
+ // dismissed. Make sure we have all information necessary before creating a new dialog.
switch (id) {
- case DIALOG_REMOVE_ACCOUNT:
- return ConfirmationDialog.create(this, id,
- R.string.account_delete_dlg_title,
- getString(R.string.account_delete_dlg_instructions_fmt,
- mSelectedContextAccount.getDescription()),
- R.string.okay_action,
- R.string.cancel_action,
- new Runnable() {
- @Override
- public void run() {
- if (mSelectedContextAccount instanceof Account) {
- Account realAccount = (Account)mSelectedContextAccount;
- try {
- realAccount.getLocalStore().delete();
- } catch (Exception e) {
- // Ignore, this may lead to localStores on sd-cards that are
- // currently not inserted to be left
- }
- MessagingController.getInstance(getApplication())
- .notifyAccountCancel(Accounts.this, realAccount);
- Preferences.getPreferences(Accounts.this).deleteAccount(realAccount);
- K9.setServicesEnabled(Accounts.this);
- refresh();
- }
+ case DIALOG_REMOVE_ACCOUNT: {
+ if (mSelectedContextAccount == null) {
+ return null;
}
- });
- case DIALOG_CLEAR_ACCOUNT:
- return ConfirmationDialog.create(this, id,
- R.string.account_clear_dlg_title,
- getString(R.string.account_clear_dlg_instructions_fmt,
- mSelectedContextAccount.getDescription()),
- R.string.okay_action,
- R.string.cancel_action,
- new Runnable() {
- @Override
- public void run() {
- if (mSelectedContextAccount instanceof Account) {
- Account realAccount = (Account)mSelectedContextAccount;
- mHandler.workingAccount(realAccount, R.string.clearing_account);
- MessagingController.getInstance(getApplication()).clear(realAccount, null);
- }
+ return ConfirmationDialog.create(this, id,
+ R.string.account_delete_dlg_title,
+ getString(R.string.account_delete_dlg_instructions_fmt,
+ mSelectedContextAccount.getDescription()),
+ R.string.okay_action,
+ R.string.cancel_action,
+ new Runnable() {
+ @Override
+ public void run() {
+ if (mSelectedContextAccount instanceof Account) {
+ Account realAccount = (Account) mSelectedContextAccount;
+ try {
+ realAccount.getLocalStore().delete();
+ } catch (Exception e) {
+ // Ignore, this may lead to localStores on sd-cards that
+ // are currently not inserted to be left
+ }
+ MessagingController.getInstance(getApplication())
+ .notifyAccountCancel(Accounts.this, realAccount);
+ Preferences.getPreferences(Accounts.this)
+ .deleteAccount(realAccount);
+ K9.setServicesEnabled(Accounts.this);
+ refresh();
+ }
+ }
+ });
+ }
+ case DIALOG_CLEAR_ACCOUNT: {
+ if (mSelectedContextAccount == null) {
+ return null;
}
- });
- case DIALOG_RECREATE_ACCOUNT:
- return ConfirmationDialog.create(this, id,
- R.string.account_recreate_dlg_title,
- getString(R.string.account_recreate_dlg_instructions_fmt,
- mSelectedContextAccount.getDescription()),
- R.string.okay_action,
- R.string.cancel_action,
- new Runnable() {
- @Override
- public void run() {
- if (mSelectedContextAccount instanceof Account) {
- Account realAccount = (Account)mSelectedContextAccount;
- mHandler.workingAccount(realAccount, R.string.recreating_account);
- MessagingController.getInstance(getApplication()).recreate(realAccount, null);
- }
+ return ConfirmationDialog.create(this, id,
+ R.string.account_clear_dlg_title,
+ getString(R.string.account_clear_dlg_instructions_fmt,
+ mSelectedContextAccount.getDescription()),
+ R.string.okay_action,
+ R.string.cancel_action,
+ new Runnable() {
+ @Override
+ public void run() {
+ if (mSelectedContextAccount instanceof Account) {
+ Account realAccount = (Account) mSelectedContextAccount;
+ mHandler.workingAccount(realAccount,
+ R.string.clearing_account);
+ MessagingController.getInstance(getApplication())
+ .clear(realAccount, null);
+ }
+ }
+ });
+ }
+ case DIALOG_RECREATE_ACCOUNT: {
+ if (mSelectedContextAccount == null) {
+ return null;
}
- });
- case DIALOG_NO_FILE_MANAGER:
- return ConfirmationDialog.create(this, id,
- R.string.import_dialog_error_title,
- getString(R.string.import_dialog_error_message),
- R.string.open_market,
- R.string.close,
- new Runnable() {
- @Override
- public void run() {
- Uri uri = Uri.parse(ANDROID_MARKET_URL);
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- startActivity(intent);
- }
- });
+
+ return ConfirmationDialog.create(this, id,
+ R.string.account_recreate_dlg_title,
+ getString(R.string.account_recreate_dlg_instructions_fmt,
+ mSelectedContextAccount.getDescription()),
+ R.string.okay_action,
+ R.string.cancel_action,
+ new Runnable() {
+ @Override
+ public void run() {
+ if (mSelectedContextAccount instanceof Account) {
+ Account realAccount = (Account) mSelectedContextAccount;
+ mHandler.workingAccount(realAccount,
+ R.string.recreating_account);
+ MessagingController.getInstance(getApplication())
+ .recreate(realAccount, null);
+ }
+ }
+ });
+ }
+ case DIALOG_NO_FILE_MANAGER: {
+ return ConfirmationDialog.create(this, id,
+ R.string.import_dialog_error_title,
+ getString(R.string.import_dialog_error_message),
+ R.string.open_market,
+ R.string.close,
+ new Runnable() {
+ @Override
+ public void run() {
+ Uri uri = Uri.parse(ANDROID_MARKET_URL);
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ startActivity(intent);
+ }
+ });
+ }
}
+
return super.onCreateDialog(id);
}
@Override
public void onPrepareDialog(int id, Dialog d) {
-
AlertDialog alert = (AlertDialog) d;
switch (id) {
- case DIALOG_REMOVE_ACCOUNT:
- alert.setMessage(getString(R.string.account_delete_dlg_instructions_fmt,
- mSelectedContextAccount.getDescription()));
- break;
- case DIALOG_CLEAR_ACCOUNT:
- alert.setMessage(getString(R.string.account_clear_dlg_instructions_fmt,
- mSelectedContextAccount.getDescription()));
- break;
- case DIALOG_RECREATE_ACCOUNT:
- alert.setMessage(getString(R.string.account_recreate_dlg_instructions_fmt,
- mSelectedContextAccount.getDescription()));
- break;
- case DIALOG_NO_FILE_MANAGER:
- alert.setMessage(getString(R.string.import_dialog_error_message));
- break;
+ case DIALOG_REMOVE_ACCOUNT: {
+ alert.setMessage(getString(R.string.account_delete_dlg_instructions_fmt,
+ mSelectedContextAccount.getDescription()));
+ break;
+ }
+ case DIALOG_CLEAR_ACCOUNT: {
+ alert.setMessage(getString(R.string.account_clear_dlg_instructions_fmt,
+ mSelectedContextAccount.getDescription()));
+ break;
+ }
+ case DIALOG_RECREATE_ACCOUNT: {
+ alert.setMessage(getString(R.string.account_recreate_dlg_instructions_fmt,
+ mSelectedContextAccount.getDescription()));
+ break;
+ }
}
super.onPrepareDialog(id, d);
From 482ae352c158d75eb3db820305d020b809715a32 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Mar 2012 04:51:29 +0100
Subject: [PATCH 44/80] Reverted most of the recent message header changes
Clicking the additional headers area still allows to hide that view
again.
---
res/layout/message_view_header.xml | 147 ++++++++++++------------
src/com/fsck/k9/view/MessageHeader.java | 21 ++--
2 files changed, 86 insertions(+), 82 deletions(-)
diff --git a/res/layout/message_view_header.xml b/res/layout/message_view_header.xml
index 19bd2a52d..67f8fe010 100644
--- a/res/layout/message_view_header.xml
+++ b/res/layout/message_view_header.xml
@@ -17,7 +17,7 @@
android:layout_height="wrap_content"
android:stretchColumns="1"
android:shrinkColumns="1"
- android:background="@drawable/message_view_header_background">
+ android:background="@color/message_view_header_background">
@@ -30,7 +30,6 @@
@@ -123,68 +122,16 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -231,32 +178,82 @@
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="?android:attr/textAppearanceSmall"/>
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
+
+ android:layout_height="21.5dp"
+ android:focusable="true"
+ android:clickable="true"
+ android:background="@drawable/message_view_header_background">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Date: Sun, 18 Mar 2012 18:28:03 +0100
Subject: [PATCH 45/80] Fix for Issue 4164: Force close when moving an email to
another folder
---
src/com/fsck/k9/activity/ChooseFolder.java | 34 +++++++++++++++-------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java
index dc4a88115..2525c5763 100644
--- a/src/com/fsck/k9/activity/ChooseFolder.java
+++ b/src/com/fsck/k9/activity/ChooseFolder.java
@@ -1,6 +1,11 @@
package com.fsck.k9.activity;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
@@ -19,15 +24,16 @@ import android.widget.EditText;
import android.widget.Filter;
import android.widget.ListView;
import android.widget.TextView;
-import com.fsck.k9.*;
+
+import com.fsck.k9.Account;
import com.fsck.k9.Account.FolderMode;
+import com.fsck.k9.K9;
+import com.fsck.k9.Preferences;
+import com.fsck.k9.R;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.MessagingException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
public class ChooseFolder extends K9ListActivity {
String mFolder;
@@ -40,6 +46,8 @@ public class ChooseFolder extends K9ListActivity {
boolean hideCurrentFolder = true;
boolean showOptionNone = false;
boolean showDisplayableOnly = false;
+
+ private List folderList;
/**
* What folders to display.
@@ -361,17 +369,19 @@ public class ChooseFolder extends K9ListActivity {
return aName.compareToIgnoreCase(bName);
}
});
- mAdapter.setNotifyOnChange(false);
int selectedFolder = -1;
+ // We're not allowed to change the adapter from a background thread, so we use
+ // a java.util.List to build a list of the folder names.
+ // We'll add the folder names to the adapter from the UI-thread (see the 'finally' block).
+ folderList = new ArrayList();
try {
- mAdapter.clear();
int position = 0;
for (String name : localFolders) {
if (mAccount.getInboxFolderName().equalsIgnoreCase(name)) {
- mAdapter.add(getString(R.string.special_mailbox_name_inbox));
+ folderList.add(getString(R.string.special_mailbox_name_inbox));
heldInbox = name;
} else if (!K9.ERROR_FOLDER_NAME.equals(name) && !account.getOutboxFolderName().equals(name)) {
- mAdapter.add(name);
+ folderList.add(name);
}
if (mSelectFolder != null) {
@@ -390,11 +400,13 @@ public class ChooseFolder extends K9ListActivity {
position++;
}
} finally {
- mAdapter.setNotifyOnChange(true);
runOnUiThread(new Runnable() {
public void run() {
- // runOnUiThread(
- mAdapter.notifyDataSetChanged();
+ // Now we're in the UI-thread, we can safely change the contents of the adapter.
+ mAdapter.clear();
+ for (String folderName: folderList) {
+ mAdapter.add(folderName);
+ }
}
});
}
From 6bdaac4353cfcb7bc61674cefd6b2fff5741016b Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Mar 2012 21:46:32 +0100
Subject: [PATCH 46/80] Fixed whitespace (tabs vs. spaces)
---
src/com/fsck/k9/activity/ChooseFolder.java | 88 +++++++++++-----------
1 file changed, 44 insertions(+), 44 deletions(-)
diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java
index 2525c5763..98210bc7c 100644
--- a/src/com/fsck/k9/activity/ChooseFolder.java
+++ b/src/com/fsck/k9/activity/ChooseFolder.java
@@ -46,7 +46,7 @@ public class ChooseFolder extends K9ListActivity {
boolean hideCurrentFolder = true;
boolean showOptionNone = false;
boolean showDisplayableOnly = false;
-
+
private List folderList;
/**
@@ -216,7 +216,7 @@ public class ChooseFolder extends K9ListActivity {
return true;
}
case R.id.filter_folders: {
- onEnterFilter();
+ onEnterFilter();
}
return true;
default:
@@ -236,43 +236,43 @@ public class ChooseFolder extends K9ListActivity {
* Filter {@link #mAdapter} with the user-input.
*/
private void onEnterFilter() {
- final AlertDialog.Builder filterAlert = new AlertDialog.Builder(this);
+ final AlertDialog.Builder filterAlert = new AlertDialog.Builder(this);
- final EditText input = new EditText(this);
- input.addTextChangedListener(new TextWatcher() {
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- mAdapter.getFilter().filter(input.getText().toString());
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- }
- });
- input.setHint(R.string.folder_list_filter_hint);
- filterAlert.setView(input);
+ final EditText input = new EditText(this);
+ input.addTextChangedListener(new TextWatcher() {
- filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- String value = input.getText().toString().trim();
- mAdapter.getFilter().filter(value);
- }
- });
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ mAdapter.getFilter().filter(input.getText().toString());
+ }
- filterAlert.setNegativeButton("Cancel",
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- mAdapter.getFilter().filter("");
- }
- });
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+ }
- filterAlert.show();
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ });
+ input.setHint(R.string.folder_list_filter_hint);
+ filterAlert.setView(input);
+
+ filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ String value = input.getText().toString().trim();
+ mAdapter.getFilter().filter(value);
+ }
+ });
+
+ filterAlert.setNegativeButton("Cancel",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ mAdapter.getFilter().filter("");
+ }
+ });
+
+ filterAlert.show();
}
@@ -370,18 +370,18 @@ public class ChooseFolder extends K9ListActivity {
}
});
int selectedFolder = -1;
- // We're not allowed to change the adapter from a background thread, so we use
+ // We're not allowed to change the adapter from a background thread, so we use
// a java.util.List to build a list of the folder names.
- // We'll add the folder names to the adapter from the UI-thread (see the 'finally' block).
+ // We'll add the folder names to the adapter from the UI-thread (see the 'finally' block).
folderList = new ArrayList();
try {
int position = 0;
for (String name : localFolders) {
if (mAccount.getInboxFolderName().equalsIgnoreCase(name)) {
- folderList.add(getString(R.string.special_mailbox_name_inbox));
+ folderList.add(getString(R.string.special_mailbox_name_inbox));
heldInbox = name;
} else if (!K9.ERROR_FOLDER_NAME.equals(name) && !account.getOutboxFolderName().equals(name)) {
- folderList.add(name);
+ folderList.add(name);
}
if (mSelectFolder != null) {
@@ -402,11 +402,11 @@ public class ChooseFolder extends K9ListActivity {
} finally {
runOnUiThread(new Runnable() {
public void run() {
- // Now we're in the UI-thread, we can safely change the contents of the adapter.
- mAdapter.clear();
- for (String folderName: folderList) {
- mAdapter.add(folderName);
- }
+ // Now we're in the UI-thread, we can safely change the contents of the adapter.
+ mAdapter.clear();
+ for (String folderName: folderList) {
+ mAdapter.add(folderName);
+ }
}
});
}
From 09bc07596ec7bff27ae9a912a86fc5804277fc7d Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Mar 2012 21:48:22 +0100
Subject: [PATCH 47/80] Got rid of unnecessary instance variable
---
src/com/fsck/k9/activity/ChooseFolder.java | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java
index 98210bc7c..7e7a9e2a4 100644
--- a/src/com/fsck/k9/activity/ChooseFolder.java
+++ b/src/com/fsck/k9/activity/ChooseFolder.java
@@ -47,8 +47,6 @@ public class ChooseFolder extends K9ListActivity {
boolean showOptionNone = false;
boolean showDisplayableOnly = false;
- private List folderList;
-
/**
* What folders to display.
* Initialized to whatever is configured
@@ -370,10 +368,12 @@ public class ChooseFolder extends K9ListActivity {
}
});
int selectedFolder = -1;
- // We're not allowed to change the adapter from a background thread, so we use
- // a java.util.List to build a list of the folder names.
- // We'll add the folder names to the adapter from the UI-thread (see the 'finally' block).
- folderList = new ArrayList();
+
+ /*
+ * We're not allowed to change the adapter from a background thread, so we collect the
+ * folder names and update the adapter in the UI thread (see finally block).
+ */
+ final List folderList = new ArrayList();
try {
int position = 0;
for (String name : localFolders) {
From b7c1f8ab2fb1a2be01ffa783e7491417a7bfd9c5 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Mar 2012 21:51:01 +0100
Subject: [PATCH 48/80] Prefixed instance variables with "m" to comply with K-9
code style
---
src/com/fsck/k9/activity/ChooseFolder.java | 30 +++++++++++-----------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java
index 7e7a9e2a4..746d2a17f 100644
--- a/src/com/fsck/k9/activity/ChooseFolder.java
+++ b/src/com/fsck/k9/activity/ChooseFolder.java
@@ -42,10 +42,10 @@ public class ChooseFolder extends K9ListActivity {
MessageReference mMessageReference;
ArrayAdapter mAdapter;
private ChooseFolderHandler mHandler = new ChooseFolderHandler();
- String heldInbox = null;
- boolean hideCurrentFolder = true;
- boolean showOptionNone = false;
- boolean showDisplayableOnly = false;
+ String mHeldInbox = null;
+ boolean mHideCurrentFolder = true;
+ boolean mShowOptionNone = false;
+ boolean mShowDisplayableOnly = false;
/**
* What folders to display.
@@ -59,7 +59,7 @@ public class ChooseFolder extends K9ListActivity {
* Created on the fly and invalidated if a new
* set of folders is chosen via {@link #onOptionsItemSelected(MenuItem)}
*/
- private FolderListFilter myFilter = null;
+ private FolderListFilter mMyFilter = null;
public static final String EXTRA_ACCOUNT = "com.fsck.k9.ChooseFolder_account";
public static final String EXTRA_CUR_FOLDER = "com.fsck.k9.ChooseFolder_curfolder";
@@ -85,13 +85,13 @@ public class ChooseFolder extends K9ListActivity {
mFolder = intent.getStringExtra(EXTRA_CUR_FOLDER);
mSelectFolder = intent.getStringExtra(EXTRA_SEL_FOLDER);
if (intent.getStringExtra(EXTRA_SHOW_CURRENT) != null) {
- hideCurrentFolder = false;
+ mHideCurrentFolder = false;
}
if (intent.getStringExtra(EXTRA_SHOW_FOLDER_NONE) != null) {
- showOptionNone = true;
+ mShowOptionNone = true;
}
if (intent.getStringExtra(EXTRA_SHOW_DISPLAYABLE_ONLY) != null) {
- showDisplayableOnly = true;
+ mShowDisplayableOnly = true;
}
if (mFolder == null)
mFolder = "";
@@ -121,8 +121,8 @@ public class ChooseFolder extends K9ListActivity {
intent.putExtra(EXTRA_ACCOUNT, mAccount.getUuid());
intent.putExtra(EXTRA_CUR_FOLDER, mFolder);
String destFolderName = (String)((TextView)view).getText();
- if (heldInbox != null && getString(R.string.special_mailbox_name_inbox).equals(destFolderName)) {
- destFolderName = heldInbox;
+ if (mHeldInbox != null && getString(R.string.special_mailbox_name_inbox).equals(destFolderName)) {
+ destFolderName = mHeldInbox;
}
intent.putExtra(EXTRA_NEW_FOLDER, destFolderName);
intent.putExtra(EXTRA_MESSAGE, mMessageReference);
@@ -277,8 +277,8 @@ public class ChooseFolder extends K9ListActivity {
private void setDisplayMode(FolderMode aMode) {
mMode = aMode;
// invalidate the current filter as it is working on an inval
- if (myFilter != null) {
- myFilter.invalidate();
+ if (mMyFilter != null) {
+ mMyFilter.invalidate();
}
//re-populate the list
MessagingController.getInstance(getApplication()).listFolders(mAccount,
@@ -322,7 +322,7 @@ public class ChooseFolder extends K9ListActivity {
String name = folder.getName();
// Inbox needs to be compared case-insensitively
- if (hideCurrentFolder && (name.equals(mFolder) ||
+ if (mHideCurrentFolder && (name.equals(mFolder) ||
(mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) && mAccount.getInboxFolderName().equalsIgnoreCase(name)))) {
continue;
}
@@ -345,7 +345,7 @@ public class ChooseFolder extends K9ListActivity {
}
- if (showOptionNone) {
+ if (mShowOptionNone) {
localFolders.add(K9.FOLDER_NONE);
}
@@ -379,7 +379,7 @@ public class ChooseFolder extends K9ListActivity {
for (String name : localFolders) {
if (mAccount.getInboxFolderName().equalsIgnoreCase(name)) {
folderList.add(getString(R.string.special_mailbox_name_inbox));
- heldInbox = name;
+ mHeldInbox = name;
} else if (!K9.ERROR_FOLDER_NAME.equals(name) && !account.getOutboxFolderName().equals(name)) {
folderList.add(name);
}
From 4f2412eacda3daae3181bbaaede6eaaaf4e200b2 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Mar 2012 22:06:44 +0100
Subject: [PATCH 49/80] Changed code formatting. No functional changes
---
src/com/fsck/k9/activity/ChooseFolder.java | 182 +++++++++++----------
1 file changed, 92 insertions(+), 90 deletions(-)
diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java
index 746d2a17f..170f64358 100644
--- a/src/com/fsck/k9/activity/ChooseFolder.java
+++ b/src/com/fsck/k9/activity/ChooseFolder.java
@@ -36,6 +36,16 @@ import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.MessagingException;
public class ChooseFolder extends K9ListActivity {
+ public static final String EXTRA_ACCOUNT = "com.fsck.k9.ChooseFolder_account";
+ public static final String EXTRA_CUR_FOLDER = "com.fsck.k9.ChooseFolder_curfolder";
+ public static final String EXTRA_SEL_FOLDER = "com.fsck.k9.ChooseFolder_selfolder";
+ public static final String EXTRA_NEW_FOLDER = "com.fsck.k9.ChooseFolder_newfolder";
+ public static final String EXTRA_MESSAGE = "com.fsck.k9.ChooseFolder_message";
+ public static final String EXTRA_SHOW_CURRENT = "com.fsck.k9.ChooseFolder_showcurrent";
+ public static final String EXTRA_SHOW_FOLDER_NONE = "com.fsck.k9.ChooseFolder_showOptionNone";
+ public static final String EXTRA_SHOW_DISPLAYABLE_ONLY = "com.fsck.k9.ChooseFolder_showDisplayableOnly";
+
+
String mFolder;
String mSelectFolder;
Account mAccount;
@@ -54,6 +64,7 @@ public class ChooseFolder extends K9ListActivity {
* while this activity is showing.
*/
private Account.FolderMode mMode;
+
/**
* Current filter used by our ArrayAdapter.
* Created on the fly and invalidated if a new
@@ -61,14 +72,6 @@ public class ChooseFolder extends K9ListActivity {
*/
private FolderListFilter mMyFilter = null;
- public static final String EXTRA_ACCOUNT = "com.fsck.k9.ChooseFolder_account";
- public static final String EXTRA_CUR_FOLDER = "com.fsck.k9.ChooseFolder_curfolder";
- public static final String EXTRA_SEL_FOLDER = "com.fsck.k9.ChooseFolder_selfolder";
- public static final String EXTRA_NEW_FOLDER = "com.fsck.k9.ChooseFolder_newfolder";
- public static final String EXTRA_MESSAGE = "com.fsck.k9.ChooseFolder_message";
- public static final String EXTRA_SHOW_CURRENT = "com.fsck.k9.ChooseFolder_showcurrent";
- public static final String EXTRA_SHOW_FOLDER_NONE = "com.fsck.k9.ChooseFolder_showOptionNone";
- public static final String EXTRA_SHOW_DISPLAYABLE_ONLY = "com.fsck.k9.ChooseFolder_showDisplayableOnly";
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -110,55 +113,54 @@ public class ChooseFolder extends K9ListActivity {
setListAdapter(mAdapter);
-
mMode = mAccount.getFolderTargetMode();
MessagingController.getInstance(getApplication()).listFolders(mAccount, false, mListener);
-
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
- Intent intent = new Intent();
- intent.putExtra(EXTRA_ACCOUNT, mAccount.getUuid());
- intent.putExtra(EXTRA_CUR_FOLDER, mFolder);
+ Intent result = new Intent();
+ result.putExtra(EXTRA_ACCOUNT, mAccount.getUuid());
+ result.putExtra(EXTRA_CUR_FOLDER, mFolder);
String destFolderName = (String)((TextView)view).getText();
if (mHeldInbox != null && getString(R.string.special_mailbox_name_inbox).equals(destFolderName)) {
destFolderName = mHeldInbox;
}
- intent.putExtra(EXTRA_NEW_FOLDER, destFolderName);
- intent.putExtra(EXTRA_MESSAGE, mMessageReference);
- setResult(RESULT_OK, intent);
+ result.putExtra(EXTRA_NEW_FOLDER, destFolderName);
+ result.putExtra(EXTRA_MESSAGE, mMessageReference);
+ setResult(RESULT_OK, result);
finish();
}
});
-
}
class ChooseFolderHandler extends Handler {
-
private static final int MSG_PROGRESS = 2;
-
private static final int MSG_DATA_CHANGED = 3;
private static final int MSG_SET_SELECTED_FOLDER = 4;
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
- case MSG_PROGRESS:
- setProgressBarIndeterminateVisibility(msg.arg1 != 0);
- break;
- case MSG_DATA_CHANGED:
- mAdapter.notifyDataSetChanged();
+ case MSG_PROGRESS: {
+ setProgressBarIndeterminateVisibility(msg.arg1 != 0);
+ break;
+ }
+ case MSG_DATA_CHANGED: {
+ mAdapter.notifyDataSetChanged();
- /*
- * Only enable the text filter after the list has been
- * populated to avoid possible race conditions because our
- * FolderListFilter isn't really thread-safe.
- */
- getListView().setTextFilterEnabled(true);
- break;
- case MSG_SET_SELECTED_FOLDER:
- getListView().setSelection(msg.arg1);
- break;
+ /*
+ * Only enable the text filter after the list has been
+ * populated to avoid possible race conditions because our
+ * FolderListFilter isn't really thread-safe.
+ */
+ getListView().setTextFilterEnabled(true);
+ break;
+ }
+ case MSG_SET_SELECTED_FOLDER: {
+ getListView().setSelection(msg.arg1);
+ break;
+ }
}
}
@@ -181,52 +183,48 @@ public class ChooseFolder extends K9ListActivity {
}
}
- @Override public boolean onCreateOptionsMenu(Menu menu) {
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.folder_select_option, menu);
return true;
}
- @Override public boolean onOptionsItemSelected(MenuItem item) {
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
-
-
- case R.id.display_1st_class: {
- setDisplayMode(FolderMode.FIRST_CLASS);
- return true;
- }
- case R.id.display_1st_and_2nd_class: {
- setDisplayMode(FolderMode.FIRST_AND_SECOND_CLASS);
- return true;
- }
- case R.id.display_not_second_class: {
- setDisplayMode(FolderMode.NOT_SECOND_CLASS);
- return true;
- }
- case R.id.display_all: {
- setDisplayMode(FolderMode.ALL);
- return true;
- }
-
- case R.id.list_folders: {
- onRefresh();
-
- return true;
- }
- case R.id.filter_folders: {
- onEnterFilter();
- }
- return true;
- default:
- return super.onOptionsItemSelected(item);
+ case R.id.display_1st_class: {
+ setDisplayMode(FolderMode.FIRST_CLASS);
+ return true;
+ }
+ case R.id.display_1st_and_2nd_class: {
+ setDisplayMode(FolderMode.FIRST_AND_SECOND_CLASS);
+ return true;
+ }
+ case R.id.display_not_second_class: {
+ setDisplayMode(FolderMode.NOT_SECOND_CLASS);
+ return true;
+ }
+ case R.id.display_all: {
+ setDisplayMode(FolderMode.ALL);
+ return true;
+ }
+ case R.id.list_folders: {
+ onRefresh();
+ return true;
+ }
+ case R.id.filter_folders: {
+ onEnterFilter();
+ return true;
+ }
+ default: {
+ return super.onOptionsItemSelected(item);
+ }
}
}
-
private void onRefresh() {
-
MessagingController.getInstance(getApplication()).listFolders(mAccount, true, mListener);
-
}
/**
@@ -238,40 +236,37 @@ public class ChooseFolder extends K9ListActivity {
final EditText input = new EditText(this);
input.addTextChangedListener(new TextWatcher() {
-
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mAdapter.getFilter().filter(input.getText().toString());
}
@Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ /* not used */ }
@Override
- public void afterTextChanged(Editable s) {
- }
+ public void afterTextChanged(Editable s) { /* not used */ }
});
input.setHint(R.string.folder_list_filter_hint);
filterAlert.setView(input);
filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int whichButton) {
String value = input.getText().toString().trim();
mAdapter.getFilter().filter(value);
}
});
- filterAlert.setNegativeButton("Cancel",
- new DialogInterface.OnClickListener() {
+ filterAlert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int whichButton) {
mAdapter.getFilter().filter("");
}
});
filterAlert.show();
-
}
private void setDisplayMode(FolderMode aMode) {
@@ -281,8 +276,7 @@ public class ChooseFolder extends K9ListActivity {
mMyFilter.invalidate();
}
//re-populate the list
- MessagingController.getInstance(getApplication()).listFolders(mAccount,
- false, mListener);
+ MessagingController.getInstance(getApplication()).listFolders(mAccount, false, mListener);
}
private MessagingListener mListener = new MessagingListener() {
@@ -322,23 +316,27 @@ public class ChooseFolder extends K9ListActivity {
String name = folder.getName();
// Inbox needs to be compared case-insensitively
- if (mHideCurrentFolder && (name.equals(mFolder) ||
- (mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) && mAccount.getInboxFolderName().equalsIgnoreCase(name)))) {
+ if (mHideCurrentFolder && (name.equals(mFolder) || (
+ mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) &&
+ mAccount.getInboxFolderName().equalsIgnoreCase(name)))) {
continue;
}
try {
folder.refresh(prefs);
Folder.FolderClass fMode = folder.getDisplayClass();
- if ((aMode == Account.FolderMode.FIRST_CLASS && fMode != Folder.FolderClass.FIRST_CLASS)
- || (aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
+ if ((aMode == Account.FolderMode.FIRST_CLASS &&
+ fMode != Folder.FolderClass.FIRST_CLASS) || (
+ aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
fMode != Folder.FolderClass.FIRST_CLASS &&
- fMode != Folder.FolderClass.SECOND_CLASS)
- || (aMode == Account.FolderMode.NOT_SECOND_CLASS && fMode == Folder.FolderClass.SECOND_CLASS)) {
+ fMode != Folder.FolderClass.SECOND_CLASS) || (
+ aMode == Account.FolderMode.NOT_SECOND_CLASS &&
+ fMode == Folder.FolderClass.SECOND_CLASS)) {
continue;
}
} catch (MessagingException me) {
- Log.e(K9.LOG_TAG, "Couldn't get prefs to check for displayability of folder " + folder.getName(), me);
+ Log.e(K9.LOG_TAG, "Couldn't get prefs to check for displayability of folder " +
+ folder.getName(), me);
}
localFolders.add(folder.getName());
@@ -350,6 +348,7 @@ public class ChooseFolder extends K9ListActivity {
}
Collections.sort(localFolders, new Comparator() {
+ @Override
public int compare(String aName, String bName) {
if (K9.FOLDER_NONE.equalsIgnoreCase(aName)) {
return -1;
@@ -380,7 +379,8 @@ public class ChooseFolder extends K9ListActivity {
if (mAccount.getInboxFolderName().equalsIgnoreCase(name)) {
folderList.add(getString(R.string.special_mailbox_name_inbox));
mHeldInbox = name;
- } else if (!K9.ERROR_FOLDER_NAME.equals(name) && !account.getOutboxFolderName().equals(name)) {
+ } else if (!K9.ERROR_FOLDER_NAME.equals(name) &&
+ !account.getOutboxFolderName().equals(name)) {
folderList.add(name);
}
@@ -393,14 +393,16 @@ public class ChooseFolder extends K9ListActivity {
if (name.equals(mSelectFolder)) {
selectedFolder = position;
}
- } else if (name.equals(mFolder) ||
- (mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) && mAccount.getInboxFolderName().equalsIgnoreCase(name))) {
+ } else if (name.equals(mFolder) || (
+ mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) &&
+ mAccount.getInboxFolderName().equalsIgnoreCase(name))) {
selectedFolder = position;
}
position++;
}
} finally {
runOnUiThread(new Runnable() {
+ @Override
public void run() {
// Now we're in the UI-thread, we can safely change the contents of the adapter.
mAdapter.clear();
From 16afff4dfcb6adcedb021d6753feb660a1540e5c Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Mar 2012 22:09:52 +0100
Subject: [PATCH 50/80] Notify the adapter from runOnUiThread() instead of
using Handler
---
src/com/fsck/k9/activity/ChooseFolder.java | 31 ++++++++--------------
1 file changed, 11 insertions(+), 20 deletions(-)
diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java
index 170f64358..1cfdfa976 100644
--- a/src/com/fsck/k9/activity/ChooseFolder.java
+++ b/src/com/fsck/k9/activity/ChooseFolder.java
@@ -135,9 +135,8 @@ public class ChooseFolder extends K9ListActivity {
}
class ChooseFolderHandler extends Handler {
- private static final int MSG_PROGRESS = 2;
- private static final int MSG_DATA_CHANGED = 3;
- private static final int MSG_SET_SELECTED_FOLDER = 4;
+ private static final int MSG_PROGRESS = 1;
+ private static final int MSG_SET_SELECTED_FOLDER = 2;
@Override
public void handleMessage(android.os.Message msg) {
@@ -146,17 +145,6 @@ public class ChooseFolder extends K9ListActivity {
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
break;
}
- case MSG_DATA_CHANGED: {
- mAdapter.notifyDataSetChanged();
-
- /*
- * Only enable the text filter after the list has been
- * populated to avoid possible race conditions because our
- * FolderListFilter isn't really thread-safe.
- */
- getListView().setTextFilterEnabled(true);
- break;
- }
case MSG_SET_SELECTED_FOLDER: {
getListView().setSelection(msg.arg1);
break;
@@ -177,10 +165,6 @@ public class ChooseFolder extends K9ListActivity {
msg.arg1 = position;
sendMessage(msg);
}
-
- public void dataChanged() {
- sendEmptyMessage(MSG_DATA_CHANGED);
- }
}
@Override
@@ -409,12 +393,19 @@ public class ChooseFolder extends K9ListActivity {
for (String folderName: folderList) {
mAdapter.add(folderName);
}
+
+ mAdapter.notifyDataSetChanged();
+
+ /*
+ * Only enable the text filter after the list has been
+ * populated to avoid possible race conditions because our
+ * FolderListFilter isn't really thread-safe.
+ */
+ getListView().setTextFilterEnabled(true);
}
});
}
- mHandler.dataChanged();
-
if (selectedFolder != -1) {
mHandler.setSelectedFolder(selectedFolder);
}
From 8c66a2f835b76f323682862a6f4bc4619a86907c Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Mar 2012 22:13:27 +0100
Subject: [PATCH 51/80] Replaced hardcoded strings with references to string
resources
---
src/com/fsck/k9/activity/ChooseFolder.java | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java
index 1cfdfa976..a5b8568fe 100644
--- a/src/com/fsck/k9/activity/ChooseFolder.java
+++ b/src/com/fsck/k9/activity/ChooseFolder.java
@@ -235,7 +235,8 @@ public class ChooseFolder extends K9ListActivity {
input.setHint(R.string.folder_list_filter_hint);
filterAlert.setView(input);
- filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
+ String okay = getString(R.string.okay_action);
+ filterAlert.setPositiveButton(okay, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
String value = input.getText().toString().trim();
@@ -243,7 +244,8 @@ public class ChooseFolder extends K9ListActivity {
}
});
- filterAlert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ String cancel = getString(R.string.cancel_action);
+ filterAlert.setNegativeButton(cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
mAdapter.getFilter().filter("");
From 5245191900f4568a068a1f35160d3d122c325886 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Mar 2012 22:43:47 +0100
Subject: [PATCH 52/80] Notify the listener provided as argument to
doRefreshRemote()
With this change pressing "Refresh folders" in ChooseFolder actually
refreshes the folder list.
---
src/com/fsck/k9/controller/MessagingController.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 33acd96f1..290679e86 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -449,7 +449,7 @@ public class MessagingController implements Runnable {
}
}
- private void doRefreshRemote(final Account account, MessagingListener listener) {
+ private void doRefreshRemote(final Account account, final MessagingListener listener) {
put("doRefreshRemote", listener, new Runnable() {
@Override
public void run() {
@@ -492,14 +492,14 @@ public class MessagingController implements Runnable {
localFolders = localStore.getPersonalNamespaces(false);
Folder[] folderArray = localFolders.toArray(EMPTY_FOLDER_ARRAY);
- for (MessagingListener l : getListeners()) {
+ for (MessagingListener l : getListeners(listener)) {
l.listFolders(account, folderArray);
}
- for (MessagingListener l : getListeners()) {
+ for (MessagingListener l : getListeners(listener)) {
l.listFoldersFinished(account);
}
} catch (Exception e) {
- for (MessagingListener l : getListeners()) {
+ for (MessagingListener l : getListeners(listener)) {
l.listFoldersFailed(account, "");
}
addErrorMessage(account, null, e);
From 1d28eb003df376a9ba186fece011d499ef1da96a Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 19 Mar 2012 04:44:41 +0100
Subject: [PATCH 53/80] Added a setting to disable marking messages as read on
viewing
---
res/values/strings.xml | 2 ++
res/xml/account_settings_preferences.xml | 11 +++++++++++
src/com/fsck/k9/Account.java | 13 +++++++++++++
src/com/fsck/k9/activity/MessageView.java | 13 +++++++++----
src/com/fsck/k9/activity/setup/AccountSettings.java | 11 ++++++-----
src/com/fsck/k9/controller/MessagingController.java | 2 +-
src/com/fsck/k9/preferences/AccountSettings.java | 3 +++
src/com/fsck/k9/preferences/Settings.java | 2 +-
8 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 820960b66..8d66d64ea 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -549,6 +549,8 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
Searches for unread messages when Notification is openedShow unread countShow the number of unread messages in the notification bar.
+ Mark message as read when opening
+ Mark a message as read when it is opened for viewingEnable refile buttonsShow the Archive, Move, and Spam buttons.
diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml
index 9fa5a11a6..683827258 100644
--- a/res/xml/account_settings_preferences.xml
+++ b/res/xml/account_settings_preferences.xml
@@ -81,6 +81,17 @@
+
+
+
+
+
+
diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java
index c04e89c06..98c3ddafb 100644
--- a/src/com/fsck/k9/Account.java
+++ b/src/com/fsck/k9/Account.java
@@ -149,6 +149,7 @@ public class Account implements BaseAccount {
private String mCryptoApp;
private boolean mCryptoAutoSignature;
private boolean mCryptoAutoEncrypt;
+ private boolean mMarkMessageAsReadOnView;
private CryptoProvider mCryptoProvider = null;
@@ -236,6 +237,7 @@ public class Account implements BaseAccount {
mCryptoAutoSignature = false;
mCryptoAutoEncrypt = false;
mEnabled = true;
+ mMarkMessageAsReadOnView = true;
searchableFolders = Searchable.ALL;
@@ -391,6 +393,7 @@ public class Account implements BaseAccount {
mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false);
mCryptoAutoEncrypt = prefs.getBoolean(mUuid + ".cryptoAutoEncrypt", false);
mEnabled = prefs.getBoolean(mUuid + ".enabled", true);
+ mMarkMessageAsReadOnView = prefs.getBoolean(mUuid + ".markMessageAsReadOnView", true);
}
protected synchronized void delete(Preferences preferences) {
@@ -472,6 +475,7 @@ public class Account implements BaseAccount {
editor.remove(mUuid + ".enabled");
editor.remove(mUuid + ".enableMoveButtons");
editor.remove(mUuid + ".hideMoveButtonsEnum");
+ editor.remove(mUuid + ".markMessageAsReadOnView");
for (String type : networkTypes) {
editor.remove(mUuid + ".useCompression." + type);
}
@@ -632,6 +636,7 @@ public class Account implements BaseAccount {
editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature);
editor.putBoolean(mUuid + ".cryptoAutoEncrypt", mCryptoAutoEncrypt);
editor.putBoolean(mUuid + ".enabled", mEnabled);
+ editor.putBoolean(mUuid + ".markMessageAsReadOnView", mMarkMessageAsReadOnView);
editor.putBoolean(mUuid + ".vibrate", mNotificationSetting.shouldVibrate());
editor.putInt(mUuid + ".vibratePattern", mNotificationSetting.getVibratePattern());
@@ -1500,4 +1505,12 @@ public class Account implements BaseAccount {
public synchronized void setEnabled(boolean enabled) {
mEnabled = enabled;
}
+
+ public synchronized boolean isMarkMessageAsReadOnView() {
+ return mMarkMessageAsReadOnView;
+ }
+
+ public synchronized void setMarkMessageAsReadOnView(boolean value) {
+ mMarkMessageAsReadOnView = value;
+ }
}
diff --git a/src/com/fsck/k9/activity/MessageView.java b/src/com/fsck/k9/activity/MessageView.java
index 1ffb9586e..87d968681 100644
--- a/src/com/fsck/k9/activity/MessageView.java
+++ b/src/com/fsck/k9/activity/MessageView.java
@@ -756,17 +756,16 @@ public class MessageView extends K9Activity implements OnClickListener {
mPrevious.requestFocus();
}
- private void onMarkAsUnread() {
+ private void onToggleRead() {
if (mMessage != null) {
mController.setFlag(mAccount, mMessage.getFolder().getName(),
- new Message[] { mMessage }, Flag.SEEN, false);
+ new Message[] { mMessage }, Flag.SEEN, !mMessage.isSet(Flag.SEEN));
mMessageView.setHeaders(mMessage, mAccount);
String subject = mMessage.getSubject();
setTitle(subject);
}
}
-
private void onDownloadRemainder() {
if (mMessage.isSet(Flag.X_DOWNLOADED_FULL)) {
return;
@@ -833,7 +832,7 @@ public class MessageView extends K9Activity implements OnClickListener {
onSendAlternate();
break;
case R.id.mark_as_unread:
- onMarkAsUnread();
+ onToggleRead();
break;
case R.id.flag:
onFlag();
@@ -944,6 +943,12 @@ public class MessageView extends K9Activity implements OnClickListener {
additionalHeadersItem.setTitle(mMessageView.additionalHeadersVisible() ?
R.string.hide_full_header_action : R.string.show_full_header_action);
}
+
+ if (mMessage != null) {
+ int actionTitle = mMessage.isSet(Flag.SEEN) ?
+ R.string.mark_as_unread_action : R.string.mark_as_read_action;
+ menu.findItem(R.id.mark_as_unread).setTitle(actionTitle);
+ }
}
return super.onPrepareOptionsMenu(menu);
}
diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java
index 9ac8f7058..f38cfa20f 100644
--- a/src/com/fsck/k9/activity/setup/AccountSettings.java
+++ b/src/com/fsck/k9/activity/setup/AccountSettings.java
@@ -48,6 +48,7 @@ public class AccountSettings extends K9PreferenceActivity {
private static final String PREFERENCE_SCREEN_PUSH_ADVANCED = "push_advanced";
private static final String PREFERENCE_DESCRIPTION = "account_description";
+ private static final String PREFERENCE_MARK_MESSAGE_AS_READ_ON_VIEW = "mark_message_as_read_on_view";
private static final String PREFERENCE_COMPOSITION = "composition";
private static final String PREFERENCE_MANAGE_IDENTITIES = "manage_identities";
private static final String PREFERENCE_FREQUENCY = "account_check_frequency";
@@ -94,9 +95,7 @@ public class AccountSettings extends K9PreferenceActivity {
private static final String PREFERENCE_CRYPTO_APP = "crypto_app";
private static final String PREFERENCE_CRYPTO_AUTO_SIGNATURE = "crypto_auto_signature";
private static final String PREFERENCE_CRYPTO_AUTO_ENCRYPT = "crypto_auto_encrypt";
-
private static final String PREFERENCE_LOCAL_STORAGE_PROVIDER = "local_storage_provider";
-
private static final String PREFERENCE_CATEGORY_FOLDERS = "folders";
private static final String PREFERENCE_ARCHIVE_FOLDER = "archive_folder";
private static final String PREFERENCE_DRAFTS_FOLDER = "drafts_folder";
@@ -114,6 +113,7 @@ public class AccountSettings extends K9PreferenceActivity {
private PreferenceScreen mComposingScreen;
private EditTextPreference mAccountDescription;
+ private CheckBoxPreference mMarkMessageAsReadOnView;
private ListPreference mCheckFrequency;
private ListPreference mDisplayCount;
private ListPreference mMessageAge;
@@ -157,10 +157,7 @@ public class AccountSettings extends K9PreferenceActivity {
private ListPreference mCryptoApp;
private CheckBoxPreference mCryptoAutoSignature;
private CheckBoxPreference mCryptoAutoEncrypt;
-
private ListPreference mLocalStorageProvider;
-
-
private ListPreference mArchiveFolder;
private ListPreference mDraftsFolder;
private ListPreference mSentFolder;
@@ -204,6 +201,9 @@ public class AccountSettings extends K9PreferenceActivity {
}
});
+ mMarkMessageAsReadOnView = (CheckBoxPreference) findPreference(PREFERENCE_MARK_MESSAGE_AS_READ_ON_VIEW);
+ mMarkMessageAsReadOnView.setChecked(mAccount.isMarkMessageAsReadOnView());
+
mMessageFormat = (ListPreference) findPreference(PREFERENCE_MESSAGE_FORMAT);
mMessageFormat.setValue(mAccount.getMessageFormat().name());
mMessageFormat.setSummary(mMessageFormat.getEntry());
@@ -672,6 +672,7 @@ public class AccountSettings extends K9PreferenceActivity {
}
mAccount.setDescription(mAccountDescription.getText());
+ mAccount.setMarkMessageAsReadOnView(mMarkMessageAsReadOnView.isChecked());
mAccount.setNotifyNewMail(mAccountNotify.isChecked());
mAccount.setNotifySelfNewMail(mAccountNotifySelf.isChecked());
mAccount.setShowOngoing(mAccountNotifySync.isChecked());
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 290679e86..9a7065cbd 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -2846,7 +2846,7 @@ public class MessagingController implements Runnable {
|| message.getId() == 0) {
throw new IllegalArgumentException("Message not found: folder=" + folder + ", uid=" + uid);
}
- if (!message.isSet(Flag.SEEN)) {
+ if (account.isMarkMessageAsReadOnView() && !message.isSet(Flag.SEEN)) {
message.setFlag(Flag.SEEN, true);
setFlag(new Message[] { message }, Flag.SEEN, true);
}
diff --git a/src/com/fsck/k9/preferences/AccountSettings.java b/src/com/fsck/k9/preferences/AccountSettings.java
index fdc311820..f2dcf3669 100644
--- a/src/com/fsck/k9/preferences/AccountSettings.java
+++ b/src/com/fsck/k9/preferences/AccountSettings.java
@@ -96,6 +96,9 @@ public class AccountSettings {
s.put("localStorageProvider", Settings.versions(
new V(1, new StorageProviderSetting())
));
+ s.put("markMessageAsReadOnView", Settings.versions(
+ new V(7, new BooleanSetting(true))
+ ));
s.put("maxPushFolders", Settings.versions(
new V(1, new IntegerRangeSetting(0, 100, 10))
));
diff --git a/src/com/fsck/k9/preferences/Settings.java b/src/com/fsck/k9/preferences/Settings.java
index 3b2bbb979..637d6d74d 100644
--- a/src/com/fsck/k9/preferences/Settings.java
+++ b/src/com/fsck/k9/preferences/Settings.java
@@ -35,7 +35,7 @@ public class Settings {
*
* @see SettingsExporter
*/
- public static final int VERSION = 6;
+ public static final int VERSION = 7;
public static Map validate(int version, Map> settings,
From 8180fd9ad2113c5c92a9ea7de2d19b396ffa10f8 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 22 Mar 2012 22:17:10 +0100
Subject: [PATCH 54/80] Added a button to switch the identity in MessageCompose
Originally I wanted to use a Spinner, but it doesn't support multiple
view types (see [1]). Those are necessary because we use different
layouts for accounts (section headers) and identities (selectable list
items).
Removed the ChooseAccount activity because it's now unused.
---
res/layout/choose_account.xml | 9 -
res/layout/choose_account_item.xml | 42 +--
res/layout/choose_identity_item.xml | 17 +-
res/layout/message_compose.xml | 33 ++-
res/menu/message_compose_option.xml | 6 -
src/com/fsck/k9/activity/ChooseAccount.java | 243 ------------------
.../k9/activity/K9ExpandableListActivity.java | 18 --
src/com/fsck/k9/activity/MessageCompose.java | 227 ++++++++++++----
8 files changed, 215 insertions(+), 380 deletions(-)
delete mode 100644 res/layout/choose_account.xml
delete mode 100644 src/com/fsck/k9/activity/ChooseAccount.java
delete mode 100644 src/com/fsck/k9/activity/K9ExpandableListActivity.java
diff --git a/res/layout/choose_account.xml b/res/layout/choose_account.xml
deleted file mode 100644
index 09c8fe2d8..000000000
--- a/res/layout/choose_account.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
diff --git a/res/layout/choose_account_item.xml b/res/layout/choose_account_item.xml
index d212594f0..361db3d61 100644
--- a/res/layout/choose_account_item.xml
+++ b/res/layout/choose_account_item.xml
@@ -3,37 +3,21 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
- android:paddingRight="6dip"
- android:paddingBottom="2dip"
- android:descendantFocusability="blocksDescendants"
- android:gravity="center_vertical" >
+ android:background="#cccccc"
+ android:gravity="left|center_vertical">
-
-
-
-
-
-
-
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:paddingTop="2dp"
+ android:paddingLeft="18dp"
+ android:paddingRight="4dp"
+ android:paddingBottom="2dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
diff --git a/res/layout/choose_identity_item.xml b/res/layout/choose_identity_item.xml
index 0f1999003..600bb8b75 100644
--- a/res/layout/choose_identity_item.xml
+++ b/res/layout/choose_identity_item.xml
@@ -5,25 +5,20 @@
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
- android:paddingRight="6dip"
- android:paddingBottom="2dip"
- android:descendantFocusability="blocksDescendants"
- android:gravity="center_vertical" >
+ android:gravity="center_vertical">
+ android:layout_width="6dp"/>
+ android:paddingLeft="12dp"
+ android:paddingRight="4dp">
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
diff --git a/res/layout/message_compose.xml b/res/layout/message_compose.xml
index 2cafb2428..70d3be985 100644
--- a/res/layout/message_compose.xml
+++ b/res/layout/message_compose.xml
@@ -20,17 +20,34 @@
-
+ android:orientation="horizontal">
+
+
+
+
+
+
+
- identities = account.getIdentities();
- final Identity identity = (Identity) extras.getSerializable(EXTRA_IDENTITY);
- if (identity == null) {
- expandableListView.setSelectedChild(i, 0, true);
- break;
- }
- for (int j = 0; j < identities.size(); j++) {
- final Identity loopIdentity = identities.get(j);
- if (identity.equals(loopIdentity)) {
- expandableListView.setSelectedChild(i, j, true);
- break;
- }
- }
- break;
- }
- }
- }
- }
-
- private IdentitiesAdapter createAdapter() {
- return new IdentitiesAdapter(this, getLayoutInflater());
- }
-
- /**
- * Dynamically provides accounts/identities data for
- * {@link ExpandableListView#setAdapter(ExpandableListAdapter)}:
- *
- *
- *
Groups represent {@link Account accounts}
- *
Children represent {@link Identity identities} of the parent account
- *
- */
- public static class IdentitiesAdapter extends BaseExpandableListAdapter {
-
- private Context mContext;
- private LayoutInflater mLayoutInflater;
- private Account[] mAccounts;
-
- public IdentitiesAdapter(final Context context, final LayoutInflater layoutInflater) {
- mContext = context;
- mLayoutInflater = layoutInflater;
- Preferences prefs = Preferences.getPreferences(mContext);
- mAccounts = prefs.getAvailableAccounts().toArray(EMPTY_ACCOUNT_ARRAY);
- }
-
- @Override
- public Object getChild(int groupPosition, int childPosition) {
- return getAccounts()[groupPosition].getIdentity(childPosition);
- }
-
- @Override
- public long getChildId(int groupPosition, int childPosition) {
- return Integer.valueOf(childPosition).longValue();
- }
-
- @Override
- public int getChildrenCount(int groupPosition) {
- return getAccounts()[groupPosition].getIdentities().size();
- }
-
- @Override
- public Object getGroup(int groupPosition) {
- return getAccounts()[groupPosition];
- }
-
- @Override
- public int getGroupCount() {
- return getAccounts().length;
- }
-
- @Override
- public long getGroupId(int groupPosition) {
- return Integer.valueOf(groupPosition).longValue();
- }
-
- @Override
- public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
- ViewGroup parent) {
- final View v;
- if (convertView == null) {
- v = mLayoutInflater.inflate(R.layout.choose_account_item, parent, false);
- } else {
- v = convertView;
- }
-
- final TextView description = (TextView) v.findViewById(R.id.description);
- final Account account = getAccounts()[groupPosition];
- description.setText(account.getDescription());
- description.setTextSize(TypedValue.COMPLEX_UNIT_SP, K9.getFontSizes().getAccountName());
-
- // display unavailable accounts translucent
- /*
- * 20101030/fiouzy: NullPointerException on null getBackground()
- *
- if (account.isAvailable(parent.getContext()))
- {
- description.getBackground().setAlpha(255);
- description.getBackground().setAlpha(255);
- }
- else
- {
- description.getBackground().setAlpha(127);
- description.getBackground().setAlpha(127);
- }
- */
-
- v.findViewById(R.id.chip).setBackgroundColor(account.getChipColor());
-
- return v;
- }
-
- @Override
- public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
- View convertView, ViewGroup parent) {
- final Account account = getAccounts()[groupPosition];
- final Identity identity = account.getIdentity(childPosition);
-
- final View v;
- if (convertView == null) {
- v = mLayoutInflater.inflate(R.layout.choose_identity_item, parent, false);
- } else {
- v = convertView;
- }
-
- final TextView name = (TextView) v.findViewById(R.id.name);
- final TextView description = (TextView) v.findViewById(R.id.description);
- name.setTextSize(TypedValue.COMPLEX_UNIT_SP, K9.getFontSizes().getAccountName());
- description.setTextSize(TypedValue.COMPLEX_UNIT_SP, K9.getFontSizes().getAccountDescription());
-
- name.setText(identity.getDescription());
- description.setText(String.format("%s <%s>", identity.getName(), identity.getEmail()));
-
- v.findViewById(R.id.chip).setBackgroundColor(account.getChipColor());
-
- return v;
- }
-
- @Override
- public boolean hasStableIds() {
- // returning false since accounts/identities are mutable
- return false;
- }
-
- @Override
- public boolean isChildSelectable(int groupPosition, int childPosition) {
- return true;
- }
-
- private Account[] getAccounts() {
- return mAccounts;
- }
- }
-}
diff --git a/src/com/fsck/k9/activity/K9ExpandableListActivity.java b/src/com/fsck/k9/activity/K9ExpandableListActivity.java
deleted file mode 100644
index 3e1b509a7..000000000
--- a/src/com/fsck/k9/activity/K9ExpandableListActivity.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.fsck.k9.activity;
-
-import android.app.ExpandableListActivity;
-import android.os.Bundle;
-
-import com.fsck.k9.K9;
-
-/**
- * @see ExpandableListActivity
- */
-public class K9ExpandableListActivity extends ExpandableListActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(K9.getK9Theme());
- super.onCreate(savedInstanceState);
- }
-}
diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java
index e14c34c8e..01df80ebb 100644
--- a/src/com/fsck/k9/activity/MessageCompose.java
+++ b/src/com/fsck/k9/activity/MessageCompose.java
@@ -15,6 +15,7 @@ import com.fsck.k9.mail.*;
import com.fsck.k9.view.MessageWebView;
import org.apache.james.mime4j.codec.EncoderUtil;
import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.ContentResolver;
import android.content.Context;
@@ -31,14 +32,17 @@ import android.provider.OpenableColumns;
import android.text.util.Rfc822Tokenizer;
import android.util.Log;
import android.util.TypedValue;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
import android.view.Window;
import android.webkit.WebView;
import android.widget.AutoCompleteTextView.Validator;
+import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
@@ -84,6 +88,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
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 int DIALOG_CHOOSE_IDENTITY = 5;
private static final long INVALID_DRAFT_ID = MessagingController.INVALID_MESSAGE_ID;
@@ -128,12 +133,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private static final int MSG_DISCARDED_DRAFT = 6;
private static final int ACTIVITY_REQUEST_PICK_ATTACHMENT = 1;
- private static final int ACTIVITY_CHOOSE_IDENTITY = 2;
- private static final int ACTIVITY_CHOOSE_ACCOUNT = 3;
- private static final int CONTACT_PICKER_TO = 4;
- private static final int CONTACT_PICKER_CC = 5;
- private static final int CONTACT_PICKER_BCC = 6;
+ private static final int CONTACT_PICKER_TO = 2;
+ private static final int CONTACT_PICKER_CC = 3;
+ private static final int CONTACT_PICKER_BCC = 4;
+ private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[0];
/**
* Regular expression to remove the first localized "Re:" prefix in subjects.
@@ -186,7 +190,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private QuotedTextMode mQuotedTextMode = QuotedTextMode.NONE;
- private TextView mFromView;
+ private Button mChooseIdentityButton;
private LinearLayout mCcWrapper;
private LinearLayout mBccWrapper;
private MultiAutoCompleteTextView mToView;
@@ -410,7 +414,14 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mAddressAdapter = EmailAddressAdapter.getInstance(this);
mAddressValidator = new EmailAddressValidator();
- mFromView = (TextView) findViewById(R.id.from);
+ mChooseIdentityButton = (Button) findViewById(R.id.identity);
+ mChooseIdentityButton.setOnClickListener(this);
+
+ if (mAccount.getIdentities().size() == 1 &&
+ Preferences.getPreferences(this).getAvailableAccounts().size() == 1) {
+ findViewById(R.id.identity_container).setVisibility(View.GONE);
+ }
+
mToView = (MultiAutoCompleteTextView) findViewById(R.id.to);
mCcView = (MultiAutoCompleteTextView) findViewById(R.id.cc);
mBccView = (MultiAutoCompleteTextView) findViewById(R.id.bcc);
@@ -548,8 +559,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mQuotedTextEdit.setOnClickListener(this);
mQuotedTextDelete.setOnClickListener(this);
- mFromView.setVisibility(View.GONE);
-
mToView.setAdapter(mAddressAdapter);
mToView.setTokenizer(new Rfc822Tokenizer());
mToView.setValidator(mAddressValidator);
@@ -607,8 +616,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mReadReceipt = mAccount.isMessageReadReceiptAlways();
mQuoteStyle = mAccount.getQuoteStyle();
+ updateFrom();
+
if (!mSourceMessageProcessed) {
- updateFrom();
updateSignature();
if (ACTION_REPLY.equals(action) ||
@@ -1776,12 +1786,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
addAttachment(data.getData());
mDraftNeedsSaving = true;
break;
- case ACTIVITY_CHOOSE_IDENTITY:
- onIdentityChosen(data);
- break;
- case ACTIVITY_CHOOSE_ACCOUNT:
- onAccountChosen(data);
- break;
case CONTACT_PICKER_TO:
case CONTACT_PICKER_CC:
case CONTACT_PICKER_BCC:
@@ -1811,15 +1815,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
startActivityForResult(mContacts.contactPickerIntent(), resultId);
}
-
-
- private void onAccountChosen(final Intent intent) {
- final Bundle extras = intent.getExtras();
- final String uuid = extras.getString(ChooseAccount.EXTRA_ACCOUNT);
- final Identity identity = (Identity) extras.getSerializable(ChooseAccount.EXTRA_IDENTITY);
-
- final Account account = Preferences.getPreferences(this).getAccount(uuid);
-
+ private void onAccountChosen(Account account, Identity identity) {
if (!mAccount.equals(account)) {
if (K9.DEBUG) {
Log.v(K9.LOG_TAG, "Switching account from " + mAccount + " to " + account);
@@ -1863,11 +1859,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
switchToIdentity(identity);
}
- private void onIdentityChosen(Intent intent) {
- Bundle bundle = intent.getExtras();
- switchToIdentity((Identity) bundle.getSerializable(ChooseIdentity.EXTRA_IDENTITY));
- }
-
private void switchToIdentity(Identity identity) {
mIdentity = identity;
mIdentityChanged = true;
@@ -1877,10 +1868,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
private void updateFrom() {
- if (mIdentityChanged) {
- mFromView.setVisibility(View.VISIBLE);
- }
- mFromView.setText(getString(R.string.message_view_from_format, mIdentity.getName(), mIdentity.getEmail()));
+ mChooseIdentityButton.setText(getIdentityDescription(mIdentity));
}
private void updateSignature() {
@@ -1923,6 +1911,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
MessagingController.getInstance(getApplication()).loadMessageForView(account, folderName, sourceMessageUid, null);
}
break;
+ case R.id.identity:
+ showDialog(DIALOG_CHOOSE_IDENTITY);
+ break;
}
}
@@ -1989,9 +1980,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
case R.id.add_attachment_video:
onAddAttachment2("video/*");
break;
- case R.id.choose_identity:
- onChooseIdentity();
- break;
case R.id.read_receipt:
onReadReceipt();
default:
@@ -2000,25 +1988,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
return true;
}
- private void onChooseIdentity() {
- // keep things simple: trigger account choice only if there are more
- // than 1 account
- mIgnoreOnPause = true;
- if (Preferences.getPreferences(this).getAvailableAccounts().size() > 1) {
- final Intent intent = new Intent(this, ChooseAccount.class);
- intent.putExtra(ChooseAccount.EXTRA_ACCOUNT, mAccount.getUuid());
- intent.putExtra(ChooseAccount.EXTRA_IDENTITY, mIdentity);
- startActivityForResult(intent, ACTIVITY_CHOOSE_ACCOUNT);
- } else if (mAccount.getIdentities().size() > 1) {
- Intent intent = new Intent(this, ChooseIdentity.class);
- intent.putExtra(ChooseIdentity.EXTRA_ACCOUNT, mAccount.getUuid());
- startActivityForResult(intent, ACTIVITY_CHOOSE_IDENTITY);
- } else {
- Toast.makeText(this, getString(R.string.no_identities),
- Toast.LENGTH_LONG).show();
- }
- }
-
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
@@ -2148,6 +2117,19 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
})
.create();
+ case DIALOG_CHOOSE_IDENTITY:
+ Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.send_as);
+ final IdentityAdapter adapter = new IdentityAdapter(this, getLayoutInflater());
+ builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ IdentityContainer container = (IdentityContainer) adapter.getItem(which);
+ onAccountChosen(container.account, container.identity);
+ }
+ });
+
+ return builder.create();
}
return super.onCreateDialog(id);
}
@@ -3184,4 +3166,137 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
return insertable;
}
+
+ /**
+ * Used to store an {@link Identity} instance together with the {@link Account} it belongs to.
+ *
+ * @see IdentityAdapter
+ */
+ static class IdentityContainer {
+ public final Identity identity;
+ public final Account account;
+
+ IdentityContainer(Identity identity, Account account) {
+ this.identity = identity;
+ this.account = account;
+ }
+ }
+
+ /**
+ * Adapter for the Choose identity list view.
+ *
+ *
+ * Account names are displayed as section headers, identities as selectable list items.
+ *
+ */
+ static class IdentityAdapter extends BaseAdapter {
+ private LayoutInflater mLayoutInflater;
+ private List
+
-
-
-
+
+
-
-
+
-
+
Date: Thu, 22 Mar 2012 21:25:57 +0100
Subject: [PATCH 56/80] Fixed indentation
---
res/layout/message_compose.xml | 46 ++++++++++++++++++----------------
1 file changed, 25 insertions(+), 21 deletions(-)
diff --git a/res/layout/message_compose.xml b/res/layout/message_compose.xml
index a033df2cf..4e5149a9c 100644
--- a/res/layout/message_compose.xml
+++ b/res/layout/message_compose.xml
@@ -55,6 +55,7 @@
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:layout_width="fill_parent">
+
+ android:layout_weight="5"/>
+
-
+ android:layout_marginTop="1dip"/>
+
+
+
+
-
-
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+
+
+
+
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
-
+ android:src="@drawable/ic_button_contacts"/>
+
+
Date: Thu, 22 Mar 2012 23:37:03 +0100
Subject: [PATCH 57/80] Tweaked MessageCompose layout
---
res/layout/message_compose.xml | 53 +++++++++++++++++-----------------
res/values/strings.xml | 6 ++++
2 files changed, 32 insertions(+), 27 deletions(-)
diff --git a/res/layout/message_compose.xml b/res/layout/message_compose.xml
index 4e5149a9c..b6ac2da71 100644
--- a/res/layout/message_compose.xml
+++ b/res/layout/message_compose.xml
@@ -9,8 +9,8 @@
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
- android:scrollbarStyle="outsideInset"
- android:fillViewport="true" >
+ android:scrollbarStyle="insideOverlay"
+ android:fillViewport="true">
+ android:layout_weight="1"/>
@@ -89,9 +89,9 @@
@@ -120,10 +120,10 @@
@@ -228,6 +228,7 @@
@@ -235,8 +236,8 @@
@@ -265,9 +267,7 @@
android:padding="0dip"
android:layout_gravity="right"
android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:layout_alignParentTop="true"
- android:layout_alignParentRight="true" />
+ android:layout_width="match_parent"/>
@@ -301,19 +301,17 @@
@@ -324,12 +322,13 @@
android:id="@+id/lower_signature"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_weight="1.0"
android:gravity="left|top"
android:editable="false"
android:minLines="0"
android:autoText="true"
android:capitalize="sentences"
+ android:hint="@string/message_compose_signature_hint"
+ android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
android:textColor="@android:color/primary_text_light"
android:textAppearance="?android:attr/textAppearanceMedium" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8d66d64ea..c1cfb2b26 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -260,6 +260,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
BccSubjectMessage text
+ Signature-------- Original Message --------Subject:Sent:
@@ -273,6 +274,11 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
Some attachments were not downloaded. They will be downloaded automatically before this message is sent.Some attachments cannot be forwarded because they have not been downloaded.Quote message
+ Add recipient (To)
+ Add recipient (CC)
+ Add recipient (BCC)
+ Remove quoted text
+ Edit quoted textFrom: %s <%s>To:
From 365f8e71e049f411c363ebeade991c8073bfd3a9 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 23 Mar 2012 04:20:29 +0100
Subject: [PATCH 58/80] Fixed array length calculation
---
src/com/fsck/k9/controller/MessagingController.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 9a7065cbd..bf7a3233b 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -2085,7 +2085,7 @@ public class MessagingController implements Runnable {
PendingCommand command = new PendingCommand();
command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
- int length = 3 + uids.length;
+ int length = 4 + uids.length;
command.arguments = new String[length];
command.arguments[0] = srcFolder;
command.arguments[1] = destFolder;
From 580f1639c39b10adea67cf6248141cfb9a919f20 Mon Sep 17 00:00:00 2001
From: Jesse Vincent
Date: Fri, 23 Mar 2012 21:34:29 -0400
Subject: [PATCH 59/80] UI improvements to the "select identity" button
---
res/layout/message_compose.xml | 11 +----------
src/com/fsck/k9/activity/MessageCompose.java | 2 +-
2 files changed, 2 insertions(+), 11 deletions(-)
diff --git a/res/layout/message_compose.xml b/res/layout/message_compose.xml
index b6ac2da71..18b775573 100644
--- a/res/layout/message_compose.xml
+++ b/res/layout/message_compose.xml
@@ -29,20 +29,11 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
-
-
-
diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java
index 01df80ebb..73d367409 100644
--- a/src/com/fsck/k9/activity/MessageCompose.java
+++ b/src/com/fsck/k9/activity/MessageCompose.java
@@ -1868,7 +1868,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
private void updateFrom() {
- mChooseIdentityButton.setText(getIdentityDescription(mIdentity));
+ mChooseIdentityButton.setText(mIdentity.getEmail());
}
private void updateSignature() {
From ea90e24785a3d2d1e74a3acea37183c927cde80d Mon Sep 17 00:00:00 2001
From: Jesse Vincent
Date: Fri, 23 Mar 2012 22:00:53 -0400
Subject: [PATCH 60/80] move the chips, change the sizes
---
res/layout/choose_account_item.xml | 10 +++++++---
res/layout/choose_identity_item.xml | 6 +-----
src/com/fsck/k9/activity/MessageCompose.java | 6 +-----
3 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/res/layout/choose_account_item.xml b/res/layout/choose_account_item.xml
index 361db3d61..910312441 100644
--- a/res/layout/choose_account_item.xml
+++ b/res/layout/choose_account_item.xml
@@ -6,6 +6,10 @@
android:orientation="horizontal"
android:background="#cccccc"
android:gravity="left|center_vertical">
+
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
diff --git a/res/layout/choose_identity_item.xml b/res/layout/choose_identity_item.xml
index 600bb8b75..cec5d632b 100644
--- a/res/layout/choose_identity_item.xml
+++ b/res/layout/choose_identity_item.xml
@@ -7,10 +7,6 @@
android:orientation="horizontal"
android:gravity="center_vertical">
-
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
Date: Sat, 24 Mar 2012 20:43:17 +0100
Subject: [PATCH 61/80] Added AccountHolder
---
src/com/fsck/k9/activity/MessageCompose.java | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java
index 31d22f0a5..03417e620 100644
--- a/src/com/fsck/k9/activity/MessageCompose.java
+++ b/src/com/fsck/k9/activity/MessageCompose.java
@@ -3252,18 +3252,20 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
View view = null;
if (item instanceof Account) {
- if (convertView != null && convertView.getTag() instanceof TextView) {
+ if (convertView != null && convertView.getTag() instanceof AccountHolder) {
view = convertView;
} else {
view = mLayoutInflater.inflate(R.layout.choose_account_item, parent, false);
- TextView name = (TextView) view.findViewById(R.id.name);
- view.setTag(name);
+ AccountHolder holder = new AccountHolder();
+ holder.name = (TextView) view.findViewById(R.id.name);
+ holder.chip = view.findViewById(R.id.chip);
+ view.setTag(holder);
}
Account account = (Account) item;
- TextView name = (TextView) view.getTag();
- name.setText(account.getDescription());
- view.findViewById(R.id.chip).setBackgroundColor(account.getChipColor());
+ AccountHolder holder = (AccountHolder) view.getTag();
+ holder.name.setText(account.getDescription());
+ holder.chip.setBackgroundColor(account.getChipColor());
} else if (item instanceof IdentityContainer) {
if (convertView != null && convertView.getTag() instanceof IdentityHolder) {
view = convertView;
@@ -3277,7 +3279,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
IdentityContainer identityContainer = (IdentityContainer) item;
Identity identity = identityContainer.identity;
- Account account = identityContainer.account;
IdentityHolder holder = (IdentityHolder) view.getTag();
holder.name.setText(identity.getDescription());
holder.description.setText(getIdentityDescription(identity));
@@ -3286,6 +3287,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
return view;
}
+ static class AccountHolder {
+ public TextView name;
+ public View chip;
+ }
+
static class IdentityHolder {
public TextView name;
public TextView description;
From 661ed080616188aea1e61484052bd9ff91eb467a Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 24 Mar 2012 22:51:33 +0100
Subject: [PATCH 62/80] Removed unnecessary layout containers
---
res/layout/choose_identity_item.xml | 47 ++++++++------------
res/layout/message_compose.xml | 17 +++----
src/com/fsck/k9/activity/MessageCompose.java | 2 +-
3 files changed, 25 insertions(+), 41 deletions(-)
diff --git a/res/layout/choose_identity_item.xml b/res/layout/choose_identity_item.xml
index cec5d632b..e641a4025 100644
--- a/res/layout/choose_identity_item.xml
+++ b/res/layout/choose_identity_item.xml
@@ -4,36 +4,27 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
- android:orientation="horizontal"
- android:gravity="center_vertical">
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:paddingLeft="12dp"
+ android:paddingRight="4dp">
-
-
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
-
-
-
-
-
+
diff --git a/res/layout/message_compose.xml b/res/layout/message_compose.xml
index 18b775573..d29c574db 100644
--- a/res/layout/message_compose.xml
+++ b/res/layout/message_compose.xml
@@ -24,20 +24,13 @@
android:orientation="vertical"
android:background="#ededed" >
-
-
-
-
+ android:gravity="left|center"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="6dip"/>
Date: Sat, 24 Mar 2012 22:56:51 +0100
Subject: [PATCH 63/80] Fixed a small display issue in MessageCompose
---
res/layout/message_compose.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/res/layout/message_compose.xml b/res/layout/message_compose.xml
index d29c574db..e84a3e2bd 100644
--- a/res/layout/message_compose.xml
+++ b/res/layout/message_compose.xml
@@ -20,6 +20,7 @@
@@ -212,7 +213,6 @@
From acffe973eb41d27801dec1128d147aa3bc52904f Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 25 Mar 2012 00:28:40 +0100
Subject: [PATCH 64/80] ADT 17 changes
---
.classpath | 1 +
1 file changed, 1 insertion(+)
diff --git a/.classpath b/.classpath
index 323d9666c..7c3f645a0 100644
--- a/.classpath
+++ b/.classpath
@@ -9,5 +9,6 @@
+
From 43cb78d2de6ad01cba5de33a428eb179b545078e Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 26 Mar 2012 07:29:10 +0200
Subject: [PATCH 65/80] Fixed display issue in MessageCompose
---
res/layout/message_compose.xml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/res/layout/message_compose.xml b/res/layout/message_compose.xml
index e84a3e2bd..f22928a56 100644
--- a/res/layout/message_compose.xml
+++ b/res/layout/message_compose.xml
@@ -217,10 +217,12 @@
+
Date: Mon, 26 Mar 2012 19:41:21 +0200
Subject: [PATCH 66/80] Fixed potential NullPointerException
---
src/com/fsck/k9/controller/MessagingController.java | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index bf7a3233b..090db17ac 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -2265,10 +2265,12 @@ public class MessagingController implements Runnable {
String newUid = remoteUidMap.get(remoteSrcUid);
Message localDestMessage = localDestFolder.getMessage(localDestUid);
- localDestMessage.setUid(newUid);
- localDestFolder.changeUid((LocalMessage)localDestMessage);
- for (MessagingListener l : getListeners()) {
- l.messageUidChanged(account, destFolder, localDestUid, newUid);
+ if (localDestMessage != null) {
+ localDestMessage.setUid(newUid);
+ localDestFolder.changeUid((LocalMessage)localDestMessage);
+ for (MessagingListener l : getListeners()) {
+ l.messageUidChanged(account, destFolder, localDestUid, newUid);
+ }
}
}
}
From 4e21f049d304c21a8caf6bdf655d0f0925365f0a Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 26 Mar 2012 21:36:26 +0200
Subject: [PATCH 67/80] Validate "original message" field of identity header
when loading drafts
---
src/com/fsck/k9/activity/MessageCompose.java | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java
index de47e2ce7..c85f98a12 100644
--- a/src/com/fsck/k9/activity/MessageCompose.java
+++ b/src/com/fsck/k9/activity/MessageCompose.java
@@ -2384,7 +2384,15 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
if (k9identity.containsKey(IdentityField.ORIGINAL_MESSAGE)) {
mMessageReference = null;
try {
- mMessageReference = new MessageReference(k9identity.get(IdentityField.ORIGINAL_MESSAGE));
+ String originalMessage = k9identity.get(IdentityField.ORIGINAL_MESSAGE);
+ MessageReference messageReference = new MessageReference(originalMessage);
+
+ // Check if this is a valid account in our database
+ Preferences prefs = Preferences.getPreferences(getApplicationContext());
+ Account account = prefs.getAccount(messageReference.accountUuid);
+ if (account != null) {
+ mMessageReference = messageReference;
+ }
} catch (MessagingException e) {
Log.e(K9.LOG_TAG, "Could not decode message reference in identity.", e);
}
From 1266c3c73ec332071e1d72017338bb06dccef82a Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 27 Mar 2012 20:41:43 +0200
Subject: [PATCH 68/80] Don't allow invalid values for header/footer insertion
point
---
src/com/fsck/k9/activity/InsertableHtmlContent.java | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/com/fsck/k9/activity/InsertableHtmlContent.java b/src/com/fsck/k9/activity/InsertableHtmlContent.java
index ab413e19d..851f0ca9a 100644
--- a/src/com/fsck/k9/activity/InsertableHtmlContent.java
+++ b/src/com/fsck/k9/activity/InsertableHtmlContent.java
@@ -32,11 +32,20 @@ class InsertableHtmlContent implements Serializable {
}
public void setHeaderInsertionPoint(int headerInsertionPoint) {
- this.headerInsertionPoint = headerInsertionPoint;
+ if (headerInsertionPoint < 0 || headerInsertionPoint > quotedContent.length()) {
+ this.headerInsertionPoint = 0;
+ } else {
+ this.headerInsertionPoint = headerInsertionPoint;
+ }
}
public void setFooterInsertionPoint(int footerInsertionPoint) {
- this.footerInsertionPoint = footerInsertionPoint;
+ int len = quotedContent.length();
+ if (footerInsertionPoint < 0 || footerInsertionPoint > len) {
+ this.footerInsertionPoint = len;
+ } else {
+ this.footerInsertionPoint = footerInsertionPoint;
+ }
}
/**
From d584492a6df117baec2b1aaf20138b77fc8d5744 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 29 Mar 2012 06:33:01 +0200
Subject: [PATCH 69/80] Changed internal representation of the selected theme
in the database
---
src/com/fsck/k9/K9.java | 25 ++++++++++-
src/com/fsck/k9/activity/K9Activity.java | 2 +-
src/com/fsck/k9/activity/K9ListActivity.java | 2 +-
src/com/fsck/k9/activity/setup/Prefs.java | 4 +-
.../fsck/k9/preferences/GlobalSettings.java | 43 ++++++++++++-------
.../fsck/k9/service/RemoteControlService.java | 2 +-
6 files changed, 56 insertions(+), 22 deletions(-)
diff --git a/src/com/fsck/k9/K9.java b/src/com/fsck/k9/K9.java
index 1da5b4d81..cc3065e4a 100644
--- a/src/com/fsck/k9/K9.java
+++ b/src/com/fsck/k9/K9.java
@@ -38,6 +38,9 @@ import com.fsck.k9.service.ShutdownReceiver;
import com.fsck.k9.service.StorageGoneReceiver;
public class K9 extends Application {
+ public static final int THEME_LIGHT = 0;
+ public static final int THEME_DARK = 1;
+
/**
* Components that are interested in knowing when the K9 instance is
* available and ready (Android invokes Application.onCreate() after other
@@ -72,7 +75,7 @@ public class K9 extends Application {
}
private static String language = "";
- private static int theme = android.R.style.Theme_Light;
+ private static int theme = THEME_LIGHT;
private static final FontSizes fontSizes = new FontSizes();
@@ -604,7 +607,17 @@ public class K9 extends Application {
}
K9.setK9Language(sprefs.getString("language", ""));
- K9.setK9Theme(sprefs.getInt("theme", android.R.style.Theme_Light));
+
+ int theme = sprefs.getInt("theme", THEME_LIGHT);
+
+ // We used to save the resource ID of the theme. So convert that to the new format if
+ // necessary.
+ if (theme == THEME_DARK || theme == android.R.style.Theme) {
+ theme = THEME_DARK;
+ } else {
+ theme = THEME_LIGHT;
+ }
+ K9.setK9Theme(theme);
}
private void maybeSetupStrictMode() {
@@ -663,6 +676,14 @@ public class K9 extends Application {
language = nlanguage;
}
+ public static int getK9ThemeResourceId(int theme) {
+ return (theme == THEME_LIGHT) ? android.R.style.Theme_Light : android.R.style.Theme;
+ }
+
+ public static int getK9ThemeResourceId() {
+ return getK9ThemeResourceId(theme);
+ }
+
public static int getK9Theme() {
return theme;
}
diff --git a/src/com/fsck/k9/activity/K9Activity.java b/src/com/fsck/k9/activity/K9Activity.java
index e9a68eccf..1c1a26eab 100644
--- a/src/com/fsck/k9/activity/K9Activity.java
+++ b/src/com/fsck/k9/activity/K9Activity.java
@@ -29,7 +29,7 @@ public class K9Activity extends Activity {
public void onCreate(Bundle icicle, boolean useTheme) {
setLanguage(this, K9.getK9Language());
if (useTheme) {
- setTheme(K9.getK9Theme());
+ setTheme(K9.getK9ThemeResourceId());
}
super.onCreate(icicle);
setupFormats();
diff --git a/src/com/fsck/k9/activity/K9ListActivity.java b/src/com/fsck/k9/activity/K9ListActivity.java
index 204182be2..613b22119 100644
--- a/src/com/fsck/k9/activity/K9ListActivity.java
+++ b/src/com/fsck/k9/activity/K9ListActivity.java
@@ -13,7 +13,7 @@ public class K9ListActivity extends ListActivity {
@Override
public void onCreate(Bundle icicle) {
K9Activity.setLanguage(this, K9.getK9Language());
- setTheme(K9.getK9Theme());
+ setTheme(K9.getK9ThemeResourceId());
super.onCreate(icicle);
setupFormats();
}
diff --git a/src/com/fsck/k9/activity/setup/Prefs.java b/src/com/fsck/k9/activity/setup/Prefs.java
index 1b359b808..abfa5391a 100644
--- a/src/com/fsck/k9/activity/setup/Prefs.java
+++ b/src/com/fsck/k9/activity/setup/Prefs.java
@@ -148,7 +148,7 @@ public class Prefs extends K9PreferenceActivity {
entryVector.toArray(EMPTY_CHAR_SEQUENCE_ARRAY),
entryValueVector.toArray(EMPTY_CHAR_SEQUENCE_ARRAY));
- final String theme = (K9.getK9Theme() == android.R.style.Theme) ? "dark" : "light";
+ final String theme = (K9.getK9Theme() == K9.THEME_DARK) ? "dark" : "light";
mTheme = setupListPreference(PREFERENCE_THEME, theme);
findPreference(PREFERENCE_FONT_SIZE).setOnPreferenceClickListener(
@@ -348,7 +348,7 @@ public class Prefs extends K9PreferenceActivity {
SharedPreferences preferences = Preferences.getPreferences(this).getPreferences();
K9.setK9Language(mLanguage.getValue());
- K9.setK9Theme(mTheme.getValue().equals("dark") ? android.R.style.Theme : android.R.style.Theme_Light);
+ K9.setK9Theme(mTheme.getValue().equals("dark") ? K9.THEME_DARK : K9.THEME_LIGHT);
K9.setAnimations(mAnimations.isChecked());
K9.setGesturesEnabled(mGestures.isChecked());
K9.setCompactLayouts(compactLayouts.isChecked());
diff --git a/src/com/fsck/k9/preferences/GlobalSettings.java b/src/com/fsck/k9/preferences/GlobalSettings.java
index 42ad9312d..d8087fbf4 100644
--- a/src/com/fsck/k9/preferences/GlobalSettings.java
+++ b/src/com/fsck/k9/preferences/GlobalSettings.java
@@ -181,7 +181,7 @@ public class GlobalSettings {
new V(1, new BooleanSetting(false))
));
s.put("theme", Settings.versions(
- new V(1, new ThemeSetting(android.R.style.Theme_Light))
+ new V(1, new ThemeSetting(K9.THEME_LIGHT))
));
s.put("useGalleryBugWorkaround", Settings.versions(
new V(1, new GalleryBugWorkaroundSetting())
@@ -291,34 +291,47 @@ public class GlobalSettings {
/**
* The theme setting.
*/
- public static class ThemeSetting extends PseudoEnumSetting {
- private final Map mMapping;
+ public static class ThemeSetting extends SettingsDescription {
+ private static final String THEME_LIGHT = "light";
+ private static final String THEME_DARK = "dark";
public ThemeSetting(int defaultValue) {
super(defaultValue);
-
- Map mapping = new HashMap();
- mapping.put(android.R.style.Theme_Light, "light");
- mapping.put(android.R.style.Theme, "dark");
- mMapping = Collections.unmodifiableMap(mapping);
- }
-
- @Override
- protected Map getMapping() {
- return mMapping;
}
@Override
public Object fromString(String value) throws InvalidSettingValueException {
try {
Integer theme = Integer.parseInt(value);
- if (mMapping.containsKey(theme)) {
- return theme;
+ if (theme == K9.THEME_LIGHT ||
+ // We used to store the resource ID of the theme in the preference storage,
+ // but don't use the database upgrade mechanism to update the values. So
+ // we have to deal with the old format here.
+ theme == android.R.style.Theme_Light) {
+ return K9.THEME_LIGHT;
+ } else if (theme == K9.THEME_DARK || theme == android.R.style.Theme) {
+ return K9.THEME_DARK;
}
} catch (NumberFormatException e) { /* do nothing */ }
throw new InvalidSettingValueException();
}
+
+ @Override
+ public Object fromPrettyString(String value) throws InvalidSettingValueException {
+ if (THEME_LIGHT.equals(value)) {
+ return K9.THEME_LIGHT;
+ } else if (THEME_DARK.equals(value)) {
+ return K9.THEME_DARK;
+ }
+
+ throw new InvalidSettingValueException();
+ }
+
+ @Override
+ public String toPrettyString(Object value) {
+ return (((Integer)value).intValue() == K9.THEME_LIGHT) ? THEME_LIGHT : THEME_DARK;
+ }
}
/**
diff --git a/src/com/fsck/k9/service/RemoteControlService.java b/src/com/fsck/k9/service/RemoteControlService.java
index 3cfa52a74..bd21b2061 100644
--- a/src/com/fsck/k9/service/RemoteControlService.java
+++ b/src/com/fsck/k9/service/RemoteControlService.java
@@ -123,7 +123,7 @@ public class RemoteControlService extends CoreService {
String theme = intent.getStringExtra(K9_THEME);
if (theme != null) {
- K9.setK9Theme(K9RemoteControl.K9_THEME_DARK.equals(theme) ? android.R.style.Theme : android.R.style.Theme_Light);
+ K9.setK9Theme(K9RemoteControl.K9_THEME_DARK.equals(theme) ? K9.THEME_DARK : K9.THEME_LIGHT);
}
SharedPreferences sPrefs = preferences.getPreferences();
From 2331696153dbeef1d2873c3b24e4cad5f03332b5 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 29 Mar 2012 06:39:31 +0200
Subject: [PATCH 70/80] Always use the light theme in MessageCompose
This fixes a display bug in the "Send as" dialog in MessageCompose.
---
src/com/fsck/k9/activity/MessageCompose.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java
index c85f98a12..19f94e0c3 100644
--- a/src/com/fsck/k9/activity/MessageCompose.java
+++ b/src/com/fsck/k9/activity/MessageCompose.java
@@ -377,6 +377,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setTheme(K9.getK9ThemeResourceId(K9.THEME_LIGHT));
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.message_compose);
From 240f7ea9ac743ed6d3f4391758c22ae2817c8a33 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 30 Mar 2012 05:24:44 +0200
Subject: [PATCH 71/80] Updated and improved german translation
---
res/values-de/strings.xml | 70 +++++++++++++++++++++++++--------------
1 file changed, 46 insertions(+), 24 deletions(-)
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index e6e26aae5..d22198d54 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -64,7 +64,7 @@
FertigEntfernenVerwerfen
- Als Entwurf speichern
+ SpeichernErneut versuchenAktualisierenNachrichten abrufen
@@ -218,7 +218,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
\n * Speichern von Anhängen auf SD-Karte
\n * Papierkorb leeren
\n * Sortieren der Nachrichten
-\n * ...und viele mehr
+\n * …und viele mehr
\n
\nBitte beachten Sie, dass K-9, wie viele andere E-Mail-Anwendungen auch, die meisten kostenlosen Hotmail-Accounts nicht unterstützt. Zudem gibt es einige Probleme mit Microsoft Exchange-Servern.
\n
@@ -256,6 +256,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
BCCBetreffNachrichtentext
+ Signatur-------- Original-Nachricht --------Betreff:Gesendet:
@@ -269,6 +270,11 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Einige Anhänge wurden nicht heruntergeladen. Sie werden automatisch heruntergeladen, bevor diese Nachricht gesendet wird.Einige Anhänge können nicht weitergeleitet werden, da diese nicht heruntergeladen wurden.Original-Nachricht zitieren
+ Empfänger hinzufügen
+ Empfänger hinzufügen (CC)
+ Empfänger hinzufügen (BCC)
+ Zitierten Text entfernen
+ Zitierten Text bearbeitenVon: %s <%s>An:
@@ -285,6 +291,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Anhang konnte nicht auf SD-Karte gespeichert werden.Wählen Sie \"Bilder anzeigen\", um eingebettete Bilder abzurufen.Bilder anzeigen
+ Zeige NachrichtZeige AnhängeMehr…Lade Anhang.
@@ -402,7 +409,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
TLS (falls verfügbar)TLS (immer)
- Bei Löschen von Nachrichten:
+ Beim Löschen von NachrichtenNie von Server löschenNach 7 Tagen löschenAuch auf Server löschen
@@ -426,7 +433,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Bei jedem AbrufenNur manuell
- IMAP Namensraum automatisch ermitteln
+ IMAP-Namensraum automatisch ermittelnIMAP-VerzeichnispräfixOrdner für Entwürfe
@@ -457,7 +464,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Anmeldung erforderlich.BenutzernamePasswort
- Authentifizierungstyp
+ AuthentifizierungsmethodeBenutzername & PasswortBenutzername
@@ -492,7 +499,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Abruf beim Start der Push-VerbindungPush-Mail für dieses Konto aktivierenNeue Nachrichten werden nach dem Eintreffen umgehend abgerufen, falls Ihr Server dies unterstützt. Diese Einstellung kann zur Reduzierung der Laufzeit führen oder diese verbessern.
- IDLE Verbindung refreshen
+ Push-Verbindung erneuernJede MinuteAlle 2 MinutenAlle 3 Minuten
@@ -544,6 +551,8 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Zeigt beim Öffnen einer Benachrichtigung Liste der ungelesenen Nachrichten anAnzahl ungelesener Nachrichten anzeigenZeigt die Anzahl der ungelesenen Nachrichten in der Statuszeile.
+ Nachricht beim Öffnen als gelesen markieren
+ Markiert eine Nachricht als gelesen, sobald sie zum Betrachten geöffnet wird.Spam-LeisteZeige Archivieren-, Verschieben- und Spam-Schaltfläche.
@@ -582,16 +591,15 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
OrdnerListe der NachrichtenAnzeige der Nachricht
- Prefix beim Zitieren
+ Präfix beim ZitierenKryptographieOpenPGP ProviderKeinerNicht verfügbar
- Auto-sign
- Email Adresse des Kontos verwenden um Signaturschlüssel zu schätzen.
-
- Automatische verschlüsselung
- Verschlüsselung aktivieren falls für den Empfänger ein öffentlichen Schlüssel abgespeichert ist.
+ Automatisches Signieren
+ Verwendet die E-Mail-Adresse des Kontos, um den Signaturschlüssel zu finden.
+ Automatische Verschlüsselung
+ Verschlüsselt automatisch, falls für den Empfänger ein öffentlicher Schlüssel vorhanden ist.Häufigkeit der E-Mail-AbfrageHäufigkeit der Abfrage für Nebenordner
@@ -664,7 +672,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Alle außer NebenordnerÜbernehme Löschungen vom Server
- Lösche Nachrichten wenn sie am Server gelöscht werden
+ Lösche Nachrichten, wenn sie vom Server gelöscht wurdenOrdner-Einstellungen
@@ -776,8 +784,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Nachrichten mit Anhängen zuerstNachrichten ohne Anhänge zuerst
- Sortieren nach...
+ Sortieren nach…Datum
+ AnkunftsdatumAbsenderBetreffWichtigkeit
@@ -978,6 +987,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
DatumNachrichtentext
+ Nachricht verfassen
+ Texteingabefelder
+
WinzigSehr kleinKleiner
@@ -1019,6 +1031,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Entwurf speichern?Entwurf speichern oder verwerfen?
+ Nachricht verwerfen?
+ Sind Sie sicher, dass Sie die Nachricht verwerfen möchten?
+
Speichern des Entwurfs verweigern.Die Speicherung von als verschlüsselt markierten Entwürfen verweigern.
@@ -1058,9 +1073,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Einstellungen importierenAuswahl importierenGlobale Einstellungen
- Einstellungen Exportieren...
- Einstellungen Importieren...
- Datei lesen...
+ Einstellungen exportieren…
+ Einstellungen importieren…
+ Datei lesen…Exportiere Einstellungen erfolgreich in %s gespeichertGlobale Einstellungen erfolgreich von %s importiert%s erfolgreich von %s importiert
@@ -1069,21 +1084,21 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
%s KontenExportieren der Einstellungen ist fehlgeschlagen
- Importieren der Einstellungen von %s sind fehlgeschlagen
+ Importieren der Einstellungen von %s ist fehlgeschlagenExport erfolgreichExport fehlgeschlagenImport erfolgreichImport fehlgeschlagenKonto aktivieren
- Um das Konto \"%s\" zu benutzen müssen sie das %s angeben.
+ Um das Konto \"%s\" benutzen zu können, müssen Sie %s angeben.
- Server Passwort
- Server Passwörter
+ das Server Passwort
+ die Server PasswörterPosteingangsserver (%s):Postausgangsserver (%s):
- Passwort Setzen...
+ Passwort setzen...Passwörter setzen...Passwort des Posteingangsservers benutzen
@@ -1093,12 +1108,19 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
Konto \"%s\" ist nicht verfügbar; Bitte SD-Karte prüfen.
- Anhang speichern unter...
+ Anhang speichern unter…Anhang speichernEs wurde kein Dateimanager gefunden. Wo soll der Anhang abgelegt werden?Nach oben verschiebenNach unten verschieben
- Konto verschieben...
+ Konto verschieben…
+ K-9 Ungelesen
+ Zeige die Anzahl ungelesener Nachrichten für…
+
+ Kein Dateimanager gefunden!
+ Es wurde keine geeignete Applikation gefunden, um den Import durchzuführen. Bitte installieren Sie einen Dateimanager aus dem Play Store.
+ Play Store öffnen
+ Abbrechen
From 1d25d2ff40e7db531d713ea41efbcb84555fc2a6 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 1 Apr 2012 21:08:31 +0200
Subject: [PATCH 72/80] Added helper class to use the most recent
ClipboardManager
---
src/com/fsck/k9/helper/ClipboardManager.java | 63 +++++++++++++++++++
.../fsck/k9/helper/ClipboardManagerApi1.java | 22 +++++++
.../fsck/k9/helper/ClipboardManagerApi11.java | 23 +++++++
3 files changed, 108 insertions(+)
create mode 100644 src/com/fsck/k9/helper/ClipboardManager.java
create mode 100644 src/com/fsck/k9/helper/ClipboardManagerApi1.java
create mode 100644 src/com/fsck/k9/helper/ClipboardManagerApi11.java
diff --git a/src/com/fsck/k9/helper/ClipboardManager.java b/src/com/fsck/k9/helper/ClipboardManager.java
new file mode 100644
index 000000000..7751b3b89
--- /dev/null
+++ b/src/com/fsck/k9/helper/ClipboardManager.java
@@ -0,0 +1,63 @@
+package com.fsck.k9.helper;
+
+import android.content.Context;
+import android.os.Build;
+
+
+/**
+ * Helper class to access the system clipboard
+ *
+ * @see ClipboardManagerApi1
+ * @see ClipboardManagerApi11
+ */
+public abstract class ClipboardManager {
+ /**
+ * Instance of the API-specific class that interfaces with the clipboard API.
+ */
+ private static ClipboardManager sInstance = null;
+
+ /**
+ * Get API-specific instance of the {@code ClipboardManager} class
+ *
+ * @param context
+ * A {@link Context} instance.
+ *
+ * @return Appropriate {@link ClipboardManager} instance for this device.
+ */
+ public static ClipboardManager getInstance(Context context) {
+ Context appContext = context.getApplicationContext();
+
+ if (sInstance == null) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ sInstance = new ClipboardManagerApi1(appContext);
+ } else {
+ sInstance = new ClipboardManagerApi11(appContext);
+ }
+ }
+
+ return sInstance;
+ }
+
+
+ protected Context mContext;
+
+ /**
+ * Constructor
+ *
+ * @param context
+ * A {@link Context} instance.
+ */
+ protected ClipboardManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Copy a text string to the system clipboard
+ *
+ * @param label
+ * User-visible label for the content.
+ * @param text
+ * The actual text to be copied to the clipboard.
+ */
+ public abstract void setText(String label, String text);
+}
diff --git a/src/com/fsck/k9/helper/ClipboardManagerApi1.java b/src/com/fsck/k9/helper/ClipboardManagerApi1.java
new file mode 100644
index 000000000..80bfe714c
--- /dev/null
+++ b/src/com/fsck/k9/helper/ClipboardManagerApi1.java
@@ -0,0 +1,22 @@
+package com.fsck.k9.helper;
+
+import android.content.Context;
+import android.text.ClipboardManager;
+
+/**
+ * Access the system clipboard using the now deprecated {@link ClipboardManager}
+ */
+@SuppressWarnings("deprecation")
+public class ClipboardManagerApi1 extends com.fsck.k9.helper.ClipboardManager {
+
+ public ClipboardManagerApi1(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setText(String label, String text) {
+ ClipboardManager clipboardManager =
+ (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
+ clipboardManager.setText(text);
+ }
+}
diff --git a/src/com/fsck/k9/helper/ClipboardManagerApi11.java b/src/com/fsck/k9/helper/ClipboardManagerApi11.java
new file mode 100644
index 000000000..cae25fa0f
--- /dev/null
+++ b/src/com/fsck/k9/helper/ClipboardManagerApi11.java
@@ -0,0 +1,23 @@
+package com.fsck.k9.helper;
+
+import android.content.ClipData;
+import android.content.Context;
+import android.content.ClipboardManager;
+
+/**
+ * Access the system clipboard using the new {@link ClipboardManager} introduced with API 11
+ */
+public class ClipboardManagerApi11 extends com.fsck.k9.helper.ClipboardManager {
+
+ public ClipboardManagerApi11(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setText(String label, String text) {
+ ClipboardManager clipboardManager =
+ (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText(label, text);
+ clipboardManager.setPrimaryClip(clip);
+ }
+}
From 1596ddfaaba40ba751aa4170d813a7ea3841a6e2 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 1 Apr 2012 21:14:43 +0200
Subject: [PATCH 73/80] Moved sanitizeFilename() to com.fsck.k9.helper.Utility
---
src/com/fsck/k9/helper/Utility.java | 35 ++++++++++++++++++++++++
src/com/fsck/k9/view/AttachmentView.java | 35 +-----------------------
2 files changed, 36 insertions(+), 34 deletions(-)
diff --git a/src/com/fsck/k9/helper/Utility.java b/src/com/fsck/k9/helper/Utility.java
index 340bfabe1..814692219 100644
--- a/src/com/fsck/k9/helper/Utility.java
+++ b/src/com/fsck/k9/helper/Utility.java
@@ -19,6 +19,29 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Utility {
+ /**
+ * Regular expression that represents characters we won't allow in file names.
+ *
+ *
+ * Allowed are:
+ *
+ *
word characters (letters, digits, and underscores): {@code \w}