diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapConnection.java b/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapConnection.java index 88482c4b6..cd679a5f8 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapConnection.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/store/imap/ImapConnection.java @@ -601,10 +601,18 @@ class ImapConnection { } private List receiveCapabilities(List responses) { - capabilities = ImapResponseParser.parseCapabilities(responses); + Set receivedCapabilities = ImapResponseParser.parseCapabilities(responses); + /* RFC 3501 6.2.3 + A server MAY include a CAPABILITY response code in the tagged OK + response to a successful LOGIN command in order to send + capabilities automatically. It is unnecessary for a client to + send a separate CAPABILITY command if it recognizes these + automatic capabilities. + */ if (K9MailLib.isDebug()) { - Log.d(LOG_TAG, "Saving " + capabilities + " capabilities for " + getLogId()); + Log.d(LOG_TAG, "Saving " + receivedCapabilities + " capabilities for " + getLogId()); } + capabilities.addAll(receivedCapabilities); return responses; } } diff --git a/k9mail/build.gradle b/k9mail/build.gradle index c99ed2f0c..bc8198a57 100644 --- a/k9mail/build.gradle +++ b/k9mail/build.gradle @@ -5,6 +5,9 @@ apply from: '../gradle/plugins/findbugs-android.gradle' repositories { jcenter() + maven { + url "https://oss.sonatype.org/content/repositories/snapshots/" + } } dependencies { @@ -21,9 +24,10 @@ dependencies { androidTestCompile 'com.android.support.test:testing-support-lib:0.1' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0' - androidTestCompile("com.icegreen:greenmail:1.3.1b") { + androidTestCompile("com.icegreen:greenmail:1.4.1-SNAPSHOT") { // Use a better, later version - exclude group: "javax.mail" + exclude group: "com.sun.mail" + exclude group: "junit" } // this version avoids some "Ignoring InnerClasses attribute for an anonymous inner class" warnings diff --git a/k9mail/src/androidTest/java/com/fsck/k9/endtoend/framework/StubMailServer.java b/k9mail/src/androidTest/java/com/fsck/k9/endtoend/framework/StubMailServer.java index d8d1df2a3..c7d5b97ec 100644 --- a/k9mail/src/androidTest/java/com/fsck/k9/endtoend/framework/StubMailServer.java +++ b/k9mail/src/androidTest/java/com/fsck/k9/endtoend/framework/StubMailServer.java @@ -37,5 +37,9 @@ public class StubMailServer { public int getImapPort() { return IMAP_SERVER_SETUP.getPort(); } + + public void stop() { + greenmail.stop(); + } } diff --git a/k9mail/src/androidTest/java/com/fsck/k9/mail/store/imap/ImapConnectionTest.java b/k9mail/src/androidTest/java/com/fsck/k9/mail/store/imap/ImapConnectionTest.java new file mode 100644 index 000000000..75074195e --- /dev/null +++ b/k9mail/src/androidTest/java/com/fsck/k9/mail/store/imap/ImapConnectionTest.java @@ -0,0 +1,160 @@ +package com.fsck.k9.mail.store.imap; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.fsck.k9.endtoend.framework.StubMailServer; +import com.fsck.k9.endtoend.framework.UserForImap; +import com.fsck.k9.mail.AuthType; +import com.fsck.k9.mail.AuthenticationFailedException; +import com.fsck.k9.mail.ConnectionSecurity; +import junit.framework.TestCase; + +import static org.junit.Assert.assertArrayEquals; + + +public class ImapConnectionTest extends TestCase { + private StubMailServer stubMailServer; + private ImapConnection connection; + private TestImapSettings settings = new TestImapSettings(UserForImap.TEST_USER); + + @Override + public void setUp() throws Exception { + super.setUp(); + stubMailServer = new StubMailServer(); + connection = new ImapConnection(settings, null, + null); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + stubMailServer.stop(); + } + + public void testOpenConnectionWithWrongCredentials() throws Exception { + connection = new ImapConnection(new TestImapSettings("wrong", "password"), null, null); + try { + connection.open(); + fail("expected exception"); + } catch (AuthenticationFailedException e) { + assertTrue(e.getMessage().contains("Invalid login/password")); + assertFalse(connection.isOpen()); + } + } + + public void testOpenConnection() throws Exception { + connection.open(); + assertTrue(connection.isOpen()); + } + + public void testOpenAndCloseConnection() throws Exception { + connection.open(); + connection.close(); + assertFalse(connection.isOpen()); + } + + public void testCapabilities() throws Exception { + connection.open(); + List capabilities = new ArrayList(connection.getCapabilities()); + Collections.sort(capabilities); + assertArrayEquals(new String[] { "IMAP4REV1", "LITERAL+", "QUOTA" }, capabilities.toArray()); + } + + public void testPathPrefixGetsSetCorrectly() throws Exception { + connection.open(); + assertEquals("", settings.getPathPrefix()); + } + + public void testPathDelimiterGetsParsedCorrectly() throws Exception { + connection.open(); + assertEquals(".", settings.getPathDelimiter()); + } + + private class TestImapSettings implements ImapSettings { + private String pathPrefix; + private String pathDelimiter; + private String username; + private String password; + + public TestImapSettings(UserForImap userForImap) { + this(userForImap.loginUsername, userForImap.password); + } + + public TestImapSettings(String username, String password) { + this.username = username; + this.password = password; + } + + @Override + public String getHost() { + return stubMailServer.getImapBindAddress(); + } + + @Override + public int getPort() { + return stubMailServer.getImapPort(); + } + + @Override + public ConnectionSecurity getConnectionSecurity() { + return ConnectionSecurity.NONE; + } + + @Override + public AuthType getAuthType() { + return AuthType.PLAIN; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getClientCertificateAlias() { + return null; + } + + @Override + public boolean useCompression(int type) { + return false; + } + + @Override + public String getPathPrefix() { + return pathPrefix; + } + + @Override + public void setPathPrefix(String prefix) { + pathPrefix = prefix; + } + + @Override + public String getPathDelimiter() { + return pathDelimiter; + } + + @Override + public void setPathDelimiter(String delimiter) { + pathDelimiter = delimiter; + } + + @Override + public String getCombinedPrefix() { + return null; + } + + @Override + public void setCombinedPrefix(String prefix) { + } + } +}