Repository: thundernest/k-9
Issue: ClassCastException on IMAP sync

On a fresh install of k9Mail on a new phone, one of my IMAP accounts stops suddenly with the below error. It worked like a charm for a few days prior to that. I've another IMAP account on the same server which still works and isn't affected.

K9-Mail version: 5.006
Device make: motorola
Device model: MotoG3
Android version: 5.1.1

java.lang.ClassCastException: com.fsck.k9.mail.store.ImapResponseParser$ImapList cannot be cast to java.lang.String
    at com.fsck.k9.mail.store.ImapResponseParser.readTokens(ImapResponseParser.java:69)
    at com.fsck.k9.mail.store.ImapResponseParser.readResponse(ImapResponseParser.java:51)
    at com.fsck.k9.mail.store.ImapResponseParser.readResponse(ImapResponseParser.java:29)
    at com.fsck.k9.mail.store.ImapStore$ImapConnection.readStatusResponse(ImapStore.java:2775)
    at com.fsck.k9.mail.store.ImapStore$ImapConnection.saslAuthPlain(ImapStore.java:2727)
    at com.fsck.k9.mail.store.ImapStore$ImapConnection.open(ImapStore.java:2530)
    at com.fsck.k9.mail.store.ImapStore$ImapConnection.sendCommand(ImapStore.java:2872)
    at com.fsck.k9.mail.store.ImapStore$ImapConnection.executeSimpleCommand(ImapStore.java:2921)
    at com.fsck.k9.mail.store.ImapStore$ImapConnection.executeSimpleCommand(ImapStore.java:2902)
    at com.fsck.k9.mail.store.ImapStore$ImapFolder.executeSimpleCommand(ImapStore.java:858)
    at com.fsck.k9.mail.store.ImapStore$ImapFolder.internalOpen(ImapStore.java:904)
    at com.fsck.k9.mail.store.ImapStore$ImapFolder.open(ImapStore.java:867)
    at com.fsck.k9.controller.MessagingController.synchronizeMailboxSynchronous(MessagingController.java:1041)
    at com.fsck.k9.controller.MessagingController.access$400(MessagingController.java:111)
    at com.fsck.k9.controller.MessagingController$8.run(MessagingController.java:934)
    at com.fsck.k9.controller.MessagingController.run(MessagingController.java:435)
    at java.lang.Thread.run(Thread.java:818)


Changed files:
k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapResponseParser.java
k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseParserTest.java

diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapResponseParser.java b/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapResponseParser.java
index 7b70d41f4..b508bad7e 100644
--- a/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapResponseParser.java
+++ b/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapResponseParser.java
@@ -127,12 +127,16 @@ class ImapResponseParser {
     private void readTokens(ImapResponse response) throws IOException {
         response.clear();
 
-        String firstToken = (String) readToken(response);
-        response.add(firstToken);
+        Object firstToken = readToken(response);
 
-        if (isStatusResponse(firstToken)) {
+        checkTokenIsString(firstToken);
+        String symbol = (String) firstToken;
+
+        response.add(symbol);
+
+        if (isStatusResponse(symbol)) {
             parseResponseText(response);
-        } else if (equalsIgnoreCase(firstToken, Responses.LIST) || equalsIgnoreCase(firstToken, Responses.LSUB)) {
+        } else if (equalsIgnoreCase(symbol, Responses.LIST) || equalsIgnoreCase(symbol, Responses.LSUB)) {
             parseListResponse(response);
         } else {
             Object token;
@@ -452,4 +456,10 @@ class ImapResponseParser {
 
         return symbol.equalsIgnoreCase((String) token);
     }
+
+    private void checkTokenIsString(Object token) throws IOException {
+        if (!(token instanceof String)) {
+            throw new IOException("Unexpected non-string token: " + token);
+        }
+    }
 }
diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseParserTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseParserTest.java
index 82330798e..861fa2718 100644
--- a/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseParserTest.java
+++ b/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseParserTest.java
@@ -17,6 +17,7 @@ import static java.util.Arrays.asList;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 
 @RunWith(RobolectricTestRunner.class)
@@ -312,6 +313,18 @@ public class ImapResponseParserTest {
         assertEquals("TAG", responseTwo.getTag());
     }
 
+    @Test
+    public void readResponse_withListAsFirstToken_shouldThrow() throws Exception {
+        ImapResponseParser parser = createParser("* [1 2] 3\\r\\n");
+
+        try {
+            parser.readResponse();
+            fail("Expected exception");
+        } catch (IOException e) {
+            assertEquals("Unexpected non-string token: [1, 2]", e.getMessage());
+        }
+    }
+
     @Test
     public void testFetchResponse() throws Exception {
         ImapResponseParser parser = createParser("* 1 FETCH (" +