From 45d50a1ccffff5dd256a139497ac900f0eb5276b Mon Sep 17 00:00:00 2001 From: Andy Stadler Date: Wed, 2 Mar 2011 01:18:43 -0800 Subject: [PATCH] Don't send ID command to *.secureserver.net Fixes connection failures with GoDaddy IMAP. Bug: 3497713 Change-Id: I327d9b24598d7dead2d1b74f4e37d1e5885822a6 --- .../android/email/mail/store/ImapStore.java | 10 +++- .../email/mail/store/ImapStoreUnitTests.java | 60 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/com/android/email/mail/store/ImapStore.java b/src/com/android/email/mail/store/ImapStore.java index bf9e5f260..53078b248 100644 --- a/src/com/android/email/mail/store/ImapStore.java +++ b/src/com/android/email/mail/store/ImapStore.java @@ -1641,14 +1641,20 @@ public class ImapStore extends Store { /** * Sends client identification information to the IMAP server per RFC 2971. If * the server does not support the ID command, this will perform no operation. + * + * Interoperability hack: Never send ID to *.secureserver.net, which sends back a + * malformed response that our parser can't deal with. */ private void doSendId(boolean hasIdCapability, String capabilities) throws MessagingException { if (!hasIdCapability) return; + // Never send ID to *.secureserver.net + String host = mRootTransport.getHost(); + if (host.toLowerCase().endsWith(".secureserver.net")) return; + // Assign user-agent string (for RFC2971 ID command) - String mUserAgent = - getImapId(mContext, mUsername, mRootTransport.getHost(), capabilities); + String mUserAgent = getImapId(mContext, mUsername, host, capabilities); if (mUserAgent != null) { mIdPhrase = ImapConstants.ID + " (" + mUserAgent + ")"; diff --git a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java index d2e7929ea..e8d52302a 100644 --- a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java +++ b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java @@ -380,6 +380,57 @@ public class ImapStoreUnitTests extends AndroidTestCase { mFolder.open(OpenMode.READ_WRITE, null); } + /** + * Confirm that the non-conformant IMAP ID result seen on imap.secureserver.net fails + * to properly parse. + * 2 ID ("name" "com.google.android.email") + * * ID( "name" "Godaddy IMAP" ... "version" "3.1.0") + * 2 OK ID completed + */ + public void testImapIdSecureServerParseFail() { + MockTransport mockTransport = openAndInjectMockTransport(); + + // configure mock server to return malformed ID response + setupOpenFolder(mockTransport, new String[] { + "* ID( \"name\" \"Godaddy IMAP\" \"version\" \"3.1.0\")", + "oK"}, "rEAD-wRITE"); + try { + mFolder.open(OpenMode.READ_WRITE, null); + fail("Expected MessagingException"); + } catch (MessagingException expected) { + } + } + + /** + * Confirm that the connections to *.secureserver.net never send IMAP ID (see + * testImapIdSecureServerParseFail() for the reason why.) + */ + public void testImapIdSecureServerNotSent() throws MessagingException { + // Note, this is injected into mStore (which we don't use for this test) + MockTransport mockTransport = openAndInjectMockTransport(); + mockTransport.setMockHost("eMail.sEcurEserVer.nEt"); + + // Prime the expects pump as if the server wants IMAP ID, but we should not actually expect + // to send it, because the login code in the store should never actually send it (to this + // particular server). This sequence is a minimized version of expectLogin(). + + // Respond to the initial connection + mockTransport.expect(null, "* oK Imap 2000 Ready To Assist You"); + // Return "ID" in the capability + expectCapability(mockTransport, true); + // No TLS + // No ID (the special case for this server) + // LOGIN + mockTransport.expect(getNextTag(false) + " LOGIN user \"password\"", + getNextTag(true) + " " + "oK user authenticated (Success)"); + // SELECT + expectSelect(mockTransport, "rEAD-wRITE"); + + // Now open the folder. Although the server indicates ID in the capabilities, + // we are not expecting the store to send the ID command (to this particular server). + mFolder.open(OpenMode.READ_WRITE, null); + } + /** * Test small Folder functions that don't really do anything in Imap */ @@ -482,6 +533,15 @@ public class ImapStoreUnitTests extends AndroidTestCase { private void setupOpenFolder(MockTransport mockTransport, String[] imapIdResponse, String readWriteMode) { expectLogin(mockTransport, imapIdResponse); + expectSelect(mockTransport, readWriteMode); + } + + /** + * Helper which stuffs the mock with the strings to satisfy a typical SELECT. + * @param mockTransport the mock transport we're using + * @param readWriteMode "READ-WRITE" or "READ-ONLY" + */ + private void expectSelect(MockTransport mockTransport, String readWriteMode) { mockTransport.expect( getNextTag(false) + " SELECT \"" + FOLDER_ENCODED + "\"", new String[] { "* fLAGS (\\Answered \\Flagged \\Draft \\Deleted \\Seen)",