diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/ServerSettings.java b/k9mail-library/src/main/java/com/fsck/k9/mail/ServerSettings.java index 0935b84fb..a6a519849 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/ServerSettings.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/ServerSettings.java @@ -220,4 +220,21 @@ public class ServerSettings { return new ServerSettings(type, host, port, connectionSecurity, AuthType.EXTERNAL, username, password, newAlias); } + + @Override + public boolean equals(Object obj) { + if (! (obj instanceof ServerSettings)) { + return false; + } + ServerSettings that = (ServerSettings) obj; + return type == that.type && + port == that.port && + connectionSecurity == that.connectionSecurity && + authenticationType == that.authenticationType && + (host == null ? that.host == null : host.equals(that.host)) && + (username == null ? that.username == null : username.equals(that.username)) && + (password == null ? that.password == null : password.equals(that.password)) && + (clientCertificateAlias == null ? that.clientCertificateAlias == null : + clientCertificateAlias.equals(that.clientCertificateAlias)); + } } \ No newline at end of file diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/Transport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/Transport.java index daae1f78d..5d7c407e2 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/Transport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/Transport.java @@ -16,68 +16,9 @@ public abstract class Transport { // RFC 1047 protected static final int SOCKET_READ_TIMEOUT = 300000; - /** - * Decodes the contents of transport-specific URIs and puts them into a {@link ServerSettings} - * object. - * - * @param uri - * the transport-specific URI to decode - * - * @return A {@link ServerSettings} object holding the settings contained in the URI. - * - * @see SmtpTransport#decodeUri(String) - * @see WebDavTransport#decodeUri(String) - */ - public static ServerSettings decodeTransportUri(String uri) { - if (uri.startsWith("smtp")) { - return SmtpTransport.decodeUri(uri); - } else if (uri.startsWith("webdav")) { - return WebDavTransport.decodeUri(uri); - } else { - throw new IllegalArgumentException("Not a valid transport URI"); - } - } - - /** - * Creates a transport URI from the information supplied in the {@link ServerSettings} object. - * - * @param server - * The {@link ServerSettings} object that holds the server settings. - * - * @return A transport URI that holds the same information as the {@code server} parameter. - * - * @see SmtpTransport#createUri(ServerSettings) - * @see WebDavTransport#createUri(ServerSettings) - */ - public static String createTransportUri(ServerSettings server) { - if (Type.SMTP == server.type) { - return SmtpTransport.createUri(server); - } else if (Type.WebDAV == server.type) { - return WebDavTransport.createUri(server); - } else { - throw new IllegalArgumentException("Not a valid transport URI"); - } - } - - public abstract void open() throws MessagingException; public abstract void sendMessage(Message message) throws MessagingException; public abstract void close(); - - protected static String encodeUtf8(String s) { - try { - return URLEncoder.encode(s, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 not found"); - } - } - protected static String decodeUtf8(String s) { - try { - return URLDecoder.decode(s, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 not found"); - } - } } diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/TransportProvider.java b/k9mail-library/src/main/java/com/fsck/k9/mail/TransportProvider.java index 989296243..7d9d70cae 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/TransportProvider.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/TransportProvider.java @@ -21,8 +21,7 @@ public class TransportProvider { String uri = storeConfig.getTransportUri(); if (uri.startsWith("smtp")) { OAuth2TokenProvider oauth2TokenProvider = null; - return new SmtpTransport(storeConfig, new DefaultTrustedSocketFactory(context), - oauth2TokenProvider); + return new SmtpTransport(storeConfig, new DefaultTrustedSocketFactory(context), oauth2TokenProvider); } else if (uri.startsWith("webdav")) { return new WebDavTransport(storeConfig); } else { diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/TransportUris.java b/k9mail-library/src/main/java/com/fsck/k9/mail/TransportUris.java new file mode 100644 index 000000000..3e8832702 --- /dev/null +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/TransportUris.java @@ -0,0 +1,229 @@ +package com.fsck.k9.mail; + + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.net.URLEncoder; + +import com.fsck.k9.mail.ServerSettings.Type; +import com.fsck.k9.mail.store.webdav.WebDavStore; + + +public class TransportUris { + /** + * Decodes the contents of transport-specific URIs and puts them into a {@link ServerSettings} + * object. + * + * @param uri + * the transport-specific URI to decode + * + * @return A {@link ServerSettings} object holding the settings contained in the URI. + */ + public static ServerSettings decodeTransportUri(String uri) { + if (uri.startsWith("smtp")) { + return decodeSmtpUri(uri); + } else if (uri.startsWith("webdav")) { + return decodeWebDavUri(uri); + } else { + throw new IllegalArgumentException("Not a valid transport URI"); + } + } + + /** + * Creates a transport URI from the information supplied in the {@link ServerSettings} object. + * + * @param server + * The {@link ServerSettings} object that holds the server settings. + * + * @return A transport URI that holds the same information as the {@code server} parameter. + */ + public static String createTransportUri(ServerSettings server) { + if (Type.SMTP == server.type) { + return createSmtpUri(server); + } else if (Type.WebDAV == server.type) { + return createWebDavUri(server); + } else { + throw new IllegalArgumentException("Not a valid transport URI"); + } + } + + + /** + * Decodes a SmtpTransport URI. + * + * NOTE: In contrast to ImapStore and Pop3Store, the authType is appended at the end! + * + *
Possible forms:
+ *+ * smtp://user:password:auth@server:port ConnectionSecurity.NONE + * smtp+tls+://user:password:auth@server:port ConnectionSecurity.STARTTLS_REQUIRED + * smtp+ssl+://user:password:auth@server:port ConnectionSecurity.SSL_TLS_REQUIRED + *+ */ + private static ServerSettings decodeSmtpUri(String uri) { + String host; + int port; + ConnectionSecurity connectionSecurity; + AuthType authType = null; + String username = null; + String password = null; + String clientCertificateAlias = null; + + URI smtpUri; + try { + smtpUri = new URI(uri); + } catch (URISyntaxException use) { + throw new IllegalArgumentException("Invalid SmtpTransport URI", use); + } + + String scheme = smtpUri.getScheme(); + /* + * Currently available schemes are: + * smtp + * smtp+tls+ + * smtp+ssl+ + * + * The following are obsolete schemes that may be found in pre-existing + * settings from earlier versions or that may be found when imported. We + * continue to recognize them and re-map them appropriately: + * smtp+tls + * smtp+ssl + */ + if (scheme.equals("smtp")) { + connectionSecurity = ConnectionSecurity.NONE; + port = ServerSettings.Type.SMTP.defaultPort; + } else if (scheme.startsWith("smtp+tls")) { + connectionSecurity = ConnectionSecurity.STARTTLS_REQUIRED; + port = ServerSettings.Type.SMTP.defaultPort; + } else if (scheme.startsWith("smtp+ssl")) { + connectionSecurity = ConnectionSecurity.SSL_TLS_REQUIRED; + port = ServerSettings.Type.SMTP.defaultTlsPort; + } else { + throw new IllegalArgumentException("Unsupported protocol (" + scheme + ")"); + } + + host = smtpUri.getHost(); + + if (smtpUri.getPort() != -1) { + port = smtpUri.getPort(); + } + + if (smtpUri.getUserInfo() != null) { + String[] userInfoParts = smtpUri.getUserInfo().split(":"); + if (userInfoParts.length == 1) { + authType = AuthType.PLAIN; + username = decodeUtf8(userInfoParts[0]); + } else if (userInfoParts.length == 2) { + authType = AuthType.PLAIN; + username = decodeUtf8(userInfoParts[0]); + password = decodeUtf8(userInfoParts[1]); + } else if (userInfoParts.length == 3) { + // NOTE: In SmtpTransport URIs, the authType comes last! + authType = AuthType.valueOf(userInfoParts[2]); + username = decodeUtf8(userInfoParts[0]); + if (authType == AuthType.EXTERNAL) { + clientCertificateAlias = decodeUtf8(userInfoParts[1]); + } else { + password = decodeUtf8(userInfoParts[1]); + } + } + } + + return new ServerSettings(ServerSettings.Type.SMTP, host, port, connectionSecurity, + authType, username, password, clientCertificateAlias); + } + + /** + * Creates a SmtpTransport URI with the supplied settings. + * + * @param server + * The {@link ServerSettings} object that holds the server settings. + * + * @return A SmtpTransport URI that holds the same information as the {@code server} parameter. + * + * @see com.fsck.k9.mail.store.StoreConfig#getTransportUri() + */ + private static String createSmtpUri(ServerSettings server) { + String userEnc = (server.username != null) ? + encodeUtf8(server.username) : ""; + String passwordEnc = (server.password != null) ? + encodeUtf8(server.password) : ""; + String clientCertificateAliasEnc = (server.clientCertificateAlias != null) ? + encodeUtf8(server.clientCertificateAlias) : ""; + + String scheme; + switch (server.connectionSecurity) { + case SSL_TLS_REQUIRED: + scheme = "smtp+ssl+"; + break; + case STARTTLS_REQUIRED: + scheme = "smtp+tls+"; + break; + default: + case NONE: + scheme = "smtp"; + break; + } + + String userInfo; + AuthType authType = server.authenticationType; + // NOTE: authType is append at last item, in contrast to ImapStore and Pop3Store! + if (authType != null) { + if (AuthType.EXTERNAL == authType) { + userInfo = userEnc + ":" + clientCertificateAliasEnc + ":" + authType.name(); + } else { + userInfo = userEnc + ":" + passwordEnc + ":" + authType.name(); + } + } else { + userInfo = userEnc + ":" + passwordEnc; + } + try { + return new URI(scheme, userInfo, server.host, server.port, null, null, + null).toString(); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Can't create SmtpTransport URI", e); + } + } + + /** + * Decodes a WebDavTransport URI. + * + *
+ * Note: Everything related to sending messages via WebDAV is handled by + * {@link WebDavStore}. So the transport URI is the same as the store URI. + *
+ */ + private static ServerSettings decodeWebDavUri(String uri) { + return WebDavStore.decodeUri(uri); + } + + /** + * Creates a WebDavTransport URI. + * + *+ * Note: Everything related to sending messages via WebDAV is handled by + * {@link WebDavStore}. So the transport URI is the same as the store URI. + *
+ */ + private static String createWebDavUri(ServerSettings server) { + return WebDavStore.createUri(server); + } + + private static String encodeUtf8(String s) { + try { + return URLEncoder.encode(s, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("UTF-8 not found"); + } + } + + private static String decodeUtf8(String s) { + try { + return URLDecoder.decode(s, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("UTF-8 not found"); + } + } +} diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/WebDavTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/WebDavTransport.java index 72f29c7f1..5c9a6492e 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/WebDavTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/WebDavTransport.java @@ -14,32 +14,6 @@ import timber.log.Timber; import java.util.Collections; public class WebDavTransport extends Transport { - - /** - * Decodes a WebDavTransport URI. - * - *- * Note: Everything related to sending messages via WebDAV is handled by - * {@link WebDavStore}. So the transport URI is the same as the store URI. - *
- */ - public static ServerSettings decodeUri(String uri) { - return WebDavStore.decodeUri(uri); - } - - /** - * Creates a WebDavTransport URI. - * - *- * Note: Everything related to sending messages via WebDAV is handled by - * {@link WebDavStore}. So the transport URI is the same as the store URI. - *
- */ - public static String createUri(ServerSettings server) { - return WebDavStore.createUri(server); - } - - private WebDavStore store; public WebDavTransport(StoreConfig storeConfig) throws MessagingException { diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java index 9d2aaf1b5..8748c7e8f 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/transport/smtp/SmtpTransport.java @@ -12,8 +12,6 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; -import java.net.URI; -import java.net.URISyntaxException; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Arrays; @@ -36,7 +34,9 @@ import com.fsck.k9.mail.Message; import com.fsck.k9.mail.Message.RecipientType; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.ServerSettings; +import com.fsck.k9.mail.ServerSettings.Type; import com.fsck.k9.mail.Transport; +import com.fsck.k9.mail.TransportUris; import com.fsck.k9.mail.filter.Base64; import com.fsck.k9.mail.filter.EOLConvertingOutputStream; import com.fsck.k9.mail.filter.LineWrapOutputStream; @@ -55,151 +55,12 @@ import static com.fsck.k9.mail.CertificateValidationException.Reason.MissingCapa import static com.fsck.k9.mail.K9MailLib.DEBUG_PROTOCOL_SMTP; public class SmtpTransport extends Transport { - public static final int SMTP_CONTINUE_REQUEST = 334; - public static final int SMTP_AUTHENTICATION_FAILURE_ERROR_CODE = 535; + private static final int SMTP_CONTINUE_REQUEST = 334; + private static final int SMTP_AUTHENTICATION_FAILURE_ERROR_CODE = 535; private TrustedSocketFactory mTrustedSocketFactory; private OAuth2TokenProvider oauthTokenProvider; - /** - * Decodes a SmtpTransport URI. - * - * NOTE: In contrast to ImapStore and Pop3Store, the authType is appended at the end! - * - *Possible forms:
- *- * smtp://user:password:auth@server:port ConnectionSecurity.NONE - * smtp+tls+://user:password:auth@server:port ConnectionSecurity.STARTTLS_REQUIRED - * smtp+ssl+://user:password:auth@server:port ConnectionSecurity.SSL_TLS_REQUIRED - *- */ - public static ServerSettings decodeUri(String uri) { - String host; - int port; - ConnectionSecurity connectionSecurity; - AuthType authType = null; - String username = null; - String password = null; - String clientCertificateAlias = null; - - URI smtpUri; - try { - smtpUri = new URI(uri); - } catch (URISyntaxException use) { - throw new IllegalArgumentException("Invalid SmtpTransport URI", use); - } - - String scheme = smtpUri.getScheme(); - /* - * Currently available schemes are: - * smtp - * smtp+tls+ - * smtp+ssl+ - * - * The following are obsolete schemes that may be found in pre-existing - * settings from earlier versions or that may be found when imported. We - * continue to recognize them and re-map them appropriately: - * smtp+tls - * smtp+ssl - */ - if (scheme.equals("smtp")) { - connectionSecurity = ConnectionSecurity.NONE; - port = ServerSettings.Type.SMTP.defaultPort; - } else if (scheme.startsWith("smtp+tls")) { - connectionSecurity = ConnectionSecurity.STARTTLS_REQUIRED; - port = ServerSettings.Type.SMTP.defaultPort; - } else if (scheme.startsWith("smtp+ssl")) { - connectionSecurity = ConnectionSecurity.SSL_TLS_REQUIRED; - port = ServerSettings.Type.SMTP.defaultTlsPort; - } else { - throw new IllegalArgumentException("Unsupported protocol (" + scheme + ")"); - } - - host = smtpUri.getHost(); - - if (smtpUri.getPort() != -1) { - port = smtpUri.getPort(); - } - - if (smtpUri.getUserInfo() != null) { - String[] userInfoParts = smtpUri.getUserInfo().split(":"); - if (userInfoParts.length == 1) { - authType = AuthType.PLAIN; - username = decodeUtf8(userInfoParts[0]); - } else if (userInfoParts.length == 2) { - authType = AuthType.PLAIN; - username = decodeUtf8(userInfoParts[0]); - password = decodeUtf8(userInfoParts[1]); - } else if (userInfoParts.length == 3) { - // NOTE: In SmtpTransport URIs, the authType comes last! - authType = AuthType.valueOf(userInfoParts[2]); - username = decodeUtf8(userInfoParts[0]); - if (authType == AuthType.EXTERNAL) { - clientCertificateAlias = decodeUtf8(userInfoParts[1]); - } else { - password = decodeUtf8(userInfoParts[1]); - } - } - } - - return new ServerSettings(ServerSettings.Type.SMTP, host, port, connectionSecurity, - authType, username, password, clientCertificateAlias); - } - - /** - * Creates a SmtpTransport URI with the supplied settings. - * - * @param server - * The {@link ServerSettings} object that holds the server settings. - * - * @return A SmtpTransport URI that holds the same information as the {@code server} parameter. - * - * @see com.fsck.k9.mail.store.StoreConfig#getTransportUri() - * @see SmtpTransport#decodeUri(String) - */ - public static String createUri(ServerSettings server) { - String userEnc = (server.username != null) ? - encodeUtf8(server.username) : ""; - String passwordEnc = (server.password != null) ? - encodeUtf8(server.password) : ""; - String clientCertificateAliasEnc = (server.clientCertificateAlias != null) ? - encodeUtf8(server.clientCertificateAlias) : ""; - - String scheme; - switch (server.connectionSecurity) { - case SSL_TLS_REQUIRED: - scheme = "smtp+ssl+"; - break; - case STARTTLS_REQUIRED: - scheme = "smtp+tls+"; - break; - default: - case NONE: - scheme = "smtp"; - break; - } - - String userInfo; - AuthType authType = server.authenticationType; - // NOTE: authType is append at last item, in contrast to ImapStore and Pop3Store! - if (authType != null) { - if (AuthType.EXTERNAL == authType) { - userInfo = userEnc + ":" + clientCertificateAliasEnc + ":" + authType.name(); - } else { - userInfo = userEnc + ":" + passwordEnc + ":" + authType.name(); - } - } else { - userInfo = userEnc + ":" + passwordEnc; - } - try { - return new URI(scheme, userInfo, server.host, server.port, null, null, - null).toString(); - } catch (URISyntaxException e) { - throw new IllegalArgumentException("Can't create SmtpTransport URI", e); - } - } - - private String mHost; private int mPort; private String mUsername; @@ -219,11 +80,15 @@ public class SmtpTransport extends Transport { OAuth2TokenProvider oauth2TokenProvider) throws MessagingException { ServerSettings settings; try { - settings = decodeUri(storeConfig.getTransportUri()); + settings = TransportUris.decodeTransportUri(storeConfig.getTransportUri()); } catch (IllegalArgumentException e) { throw new MessagingException("Error while decoding transport URI", e); } + if (settings.type == Type.SMTP) { + throw new IllegalArgumentException("Expected SMTP StoreConfig!"); + } + mHost = settings.host; mPort = settings.port; diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/TransportUrisTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/TransportUrisTest.java new file mode 100644 index 000000000..ce13af539 --- /dev/null +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/TransportUrisTest.java @@ -0,0 +1,181 @@ +package com.fsck.k9.mail; + + +import android.annotation.SuppressLint; + +import org.junit.Test; + +import static junit.framework.Assert.assertEquals; + + +@SuppressLint("AuthLeak") +public class TransportUrisTest { + + @Test + public void encodeThenDecode() throws Exception { + ServerSettings serverSettings = new ServerSettings( + ServerSettings.Type.SMTP, "server", 123456, + ConnectionSecurity.STARTTLS_REQUIRED, AuthType.CRAM_MD5, + "user", "password", null); + + String uri = TransportUris.createTransportUri(serverSettings); + ServerSettings decodedSettings = TransportUris.decodeTransportUri(uri); + + assertEquals(serverSettings, decodedSettings); + } + + @Test + public void encodeThenDecode_externalAuth_preservesCert() throws Exception { + ServerSettings serverSettings = new ServerSettings( + ServerSettings.Type.SMTP, "server", 123456, + ConnectionSecurity.NONE, AuthType.EXTERNAL, + "username", null, "clientcert"); + + String uri = TransportUris.createTransportUri(serverSettings); + ServerSettings decodedSettings = TransportUris.decodeTransportUri(uri); + + assertEquals(serverSettings, decodedSettings); + } + + @Test + public void decodeTransportUri_canDecodeAuthType() { + String storeUri = "smtp://user:password:PLAIN@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals(AuthType.PLAIN, result.authenticationType); + } + + @Test + public void decodeTransportUri_canDecodeUsername() { + String storeUri = "smtp://user:password:PLAIN@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals("user", result.username); + } + + @Test + public void decodeTransportUri_canDecodePassword() { + String storeUri = "smtp://user:password:PLAIN@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals("password", result.password); + } + + @Test + public void decodeTransportUri_canDecodeUsername_withNoAuthType() { + String storeUri = "smtp://user:password@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals("user", result.username); + } + + @Test + public void decodeTransportUri_canDecodeUsername_withNoPasswordOrAuthType() { + String storeUri = "smtp://user@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals("user", result.username); + } + + @Test + public void decodeTransportUri_canDecodeAuthType_withEmptyPassword() { + String storeUri = "smtp://user::PLAIN@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals(AuthType.PLAIN, result.authenticationType); + } + + @Test + public void decodeTransportUri_canDecodeHost() { + String storeUri = "smtp://user:password:PLAIN@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals("server", result.host); + } + + @Test + public void decodeTransportUri_canDecodePort() { + String storeUri = "smtp://user:password:PLAIN@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals(123456, result.port); + } + + @Test + public void decodeTransportUri_canDecodeTLS() { + String storeUri = "smtp+tls+://user:password:PLAIN@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals(ConnectionSecurity.STARTTLS_REQUIRED, result.connectionSecurity); + } + + @Test + public void decodeTransportUri_canDecodeSSL() { + String storeUri = "smtp+ssl+://user:password:PLAIN@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals(ConnectionSecurity.SSL_TLS_REQUIRED, result.connectionSecurity); + } + + @Test + public void decodeTransportUri_canDecodeClientCert() { + String storeUri = "smtp+ssl+://user:clientCert:EXTERNAL@server:123456"; + + ServerSettings result = TransportUris.decodeTransportUri(storeUri); + + assertEquals("clientCert", result.clientCertificateAlias); + } + + @Test(expected = IllegalArgumentException.class) + public void decodeTransportUri_forUnknownSchema_throwsIllegalArgumentException() { + String storeUri = "unknown://user:clientCert:EXTERNAL@server:123456"; + + TransportUris.decodeTransportUri(storeUri); + } + + @Test + public void createTransportUri_canEncodeSmtpSslUri() { + ServerSettings serverSettings = new ServerSettings( + ServerSettings.Type.SMTP, "server", 123456, + ConnectionSecurity.SSL_TLS_REQUIRED, AuthType.EXTERNAL, + "user", "password", "clientCert"); + + String result = TransportUris.createTransportUri(serverSettings); + + assertEquals("smtp+ssl+://user:clientCert:EXTERNAL@server:123456", result); + } + + @Test + public void createTransportUri_canEncodeSmtpTlsUri() { + ServerSettings serverSettings = new ServerSettings( + ServerSettings.Type.SMTP, "server", 123456, + ConnectionSecurity.STARTTLS_REQUIRED, AuthType.PLAIN, + "user", "password", "clientCert"); + + String result = TransportUris.createTransportUri(serverSettings); + + assertEquals("smtp+tls+://user:password:PLAIN@server:123456", result); + } + + @Test + public void createTransportUri_canEncodeSmtpUri() { + ServerSettings serverSettings = new ServerSettings( + ServerSettings.Type.SMTP, "server", 123456, + ConnectionSecurity.NONE, AuthType.CRAM_MD5, + "user", "password", "clientCert"); + + String result = TransportUris.createTransportUri(serverSettings); + + assertEquals("smtp://user:password:CRAM_MD5@server:123456", result); + } +} \ No newline at end of file diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java index 7cc67506d..36d490c1c 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java @@ -13,6 +13,7 @@ import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.ServerSettings; import com.fsck.k9.mail.ServerSettings.Type; +import com.fsck.k9.mail.TransportUris; import com.fsck.k9.mail.XOAuth2ChallengeParserTest; import com.fsck.k9.mail.filter.Base64; import com.fsck.k9.mail.helpers.TestMessageBuilder; @@ -718,7 +719,7 @@ public class SmtpTransportTest { USERNAME, password, CLIENT_CERTIFICATE_ALIAS); - String uri = SmtpTransport.createUri(serverSettings); + String uri = TransportUris.createTransportUri(serverSettings); StoreConfig storeConfig = createStoreConfigWithTransportUri(uri); return new TestSmtpTransport(storeConfig, socketFactory, oAuth2TokenProvider); diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportUriTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportUriTest.java deleted file mode 100644 index ecfe17e56..000000000 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportUriTest.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.fsck.k9.mail.transport.smtp; - -import android.annotation.SuppressLint; - -import com.fsck.k9.mail.AuthType; -import com.fsck.k9.mail.ConnectionSecurity; -import com.fsck.k9.mail.ServerSettings; - -import com.fsck.k9.mail.transport.smtp.SmtpTransport; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -@SuppressLint("AuthLeak") -public class SmtpTransportUriTest { - - @Test - public void decodeUri_canDecodeAuthType() { - String storeUri = "smtp://user:password:PLAIN@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals(AuthType.PLAIN, result.authenticationType); - } - - @Test - public void decodeUri_canDecodeUsername() { - String storeUri = "smtp://user:password:PLAIN@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals("user", result.username); - } - - @Test - public void decodeUri_canDecodePassword() { - String storeUri = "smtp://user:password:PLAIN@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals("password", result.password); - } - - @Test - public void decodeUri_canDecodeUsername_withNoAuthType() { - String storeUri = "smtp://user:password@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals("user", result.username); - } - - @Test - public void decodeUri_canDecodeUsername_withNoPasswordOrAuthType() { - String storeUri = "smtp://user@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals("user", result.username); - } - - @Test - public void decodeUri_canDecodeAuthType_withEmptyPassword() { - String storeUri = "smtp://user::PLAIN@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals(AuthType.PLAIN, result.authenticationType); - } - - @Test - public void decodeUri_canDecodeHost() { - String storeUri = "smtp://user:password:PLAIN@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals("server", result.host); - } - - @Test - public void decodeUri_canDecodePort() { - String storeUri = "smtp://user:password:PLAIN@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals(123456, result.port); - } - - @Test - public void decodeUri_canDecodeTLS() { - String storeUri = "smtp+tls+://user:password:PLAIN@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals(ConnectionSecurity.STARTTLS_REQUIRED, result.connectionSecurity); - } - - @Test - public void decodeUri_canDecodeSSL() { - String storeUri = "smtp+ssl+://user:password:PLAIN@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals(ConnectionSecurity.SSL_TLS_REQUIRED, result.connectionSecurity); - } - - @Test - public void decodeUri_canDecodeClientCert() { - String storeUri = "smtp+ssl+://user:clientCert:EXTERNAL@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - - assertEquals("clientCert", result.clientCertificateAlias); - } - - @Test(expected = IllegalArgumentException.class) - public void decodeUri_forUnknownSchema_throwsIllegalArgumentException() { - String storeUri = "unknown://user:clientCert:EXTERNAL@server:123456"; - - ServerSettings result = SmtpTransport.decodeUri(storeUri); - } - - @Test - public void createUri_canEncodeSmtpSslUri() { - ServerSettings serverSettings = new ServerSettings( - ServerSettings.Type.SMTP, "server", 123456, - ConnectionSecurity.SSL_TLS_REQUIRED, AuthType.EXTERNAL, - "user", "password", "clientCert"); - - String result = SmtpTransport.createUri(serverSettings); - - assertEquals("smtp+ssl+://user:clientCert:EXTERNAL@server:123456", result); - } - - @Test - public void createUri_canEncodeSmtpTlsUri() { - ServerSettings serverSettings = new ServerSettings( - ServerSettings.Type.SMTP, "server", 123456, - ConnectionSecurity.STARTTLS_REQUIRED, AuthType.PLAIN, - "user", "password", "clientCert"); - - String result = SmtpTransport.createUri(serverSettings); - - assertEquals("smtp+tls+://user:password:PLAIN@server:123456", result); - } - - @Test - public void createUri_canEncodeSmtpUri() { - ServerSettings serverSettings = new ServerSettings( - ServerSettings.Type.SMTP, "server", 123456, - ConnectionSecurity.NONE, AuthType.CRAM_MD5, - "user", "password", "clientCert"); - - String result = SmtpTransport.createUri(serverSettings); - - assertEquals("smtp://user:password:CRAM_MD5@server:123456", result); - } -} diff --git a/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java b/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java index 8acb19c3c..e079d2274 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java @@ -1,6 +1,7 @@ package com.fsck.k9.activity; + import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -34,7 +35,6 @@ import android.os.Bundle; import android.os.Handler; import android.text.Editable; import android.text.TextWatcher; -import timber.log.Timber; import android.util.SparseBooleanArray; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; @@ -79,7 +79,7 @@ import com.fsck.k9.controller.MessagingController; import com.fsck.k9.helper.SizeFormatter; import com.fsck.k9.mail.AuthType; import com.fsck.k9.mail.ServerSettings; -import com.fsck.k9.mail.Transport; +import com.fsck.k9.mail.TransportUris; import com.fsck.k9.mail.store.RemoteStore; import com.fsck.k9.mailstore.StorageManager; import com.fsck.k9.preferences.SettingsExporter; @@ -94,8 +94,8 @@ import com.fsck.k9.search.SearchAccount; import com.fsck.k9.search.SearchSpecification.Attribute; import com.fsck.k9.search.SearchSpecification.SearchField; import com.fsck.k9.view.ColorChip; - import de.cketti.library.changelog.ChangeLog; +import timber.log.Timber; public class Accounts extends K9ListActivity implements OnItemClickListener { @@ -771,7 +771,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { private void show(final Accounts activity, boolean restore) { ServerSettings incoming = RemoteStore.decodeStoreUri(mAccount.getStoreUri()); - ServerSettings outgoing = Transport.decodeTransportUri(mAccount.getTransportUri()); + ServerSettings outgoing = TransportUris.decodeTransportUri(mAccount.getTransportUri()); /* * Don't ask for the password to the outgoing server for WebDAV @@ -996,9 +996,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { if (mOutgoingPassword != null) { // Set outgoing server password String transportUri = mAccount.getTransportUri(); - ServerSettings outgoing = Transport.decodeTransportUri(transportUri); + ServerSettings outgoing = TransportUris.decodeTransportUri(transportUri); ServerSettings newOutgoing = outgoing.newPassword(mOutgoingPassword); - String newTransportUri = Transport.createTransportUri(newOutgoing); + String newTransportUri = TransportUris.createTransportUri(newOutgoing); mAccount.setTransportUri(newTransportUri); } diff --git a/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.java b/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.java index 0ce978d05..674d746c7 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.java @@ -17,7 +17,6 @@ import android.os.Bundle; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; -import timber.log.Timber; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; @@ -31,6 +30,7 @@ import com.fsck.k9.EmailAddressValidator; import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.R; +import com.fsck.k9.account.AccountCreator; import com.fsck.k9.activity.K9Activity; import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; import com.fsck.k9.helper.UrlEncodingHelper; @@ -38,11 +38,11 @@ import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.AuthType; import com.fsck.k9.mail.ConnectionSecurity; import com.fsck.k9.mail.ServerSettings; -import com.fsck.k9.mail.Transport; +import com.fsck.k9.mail.TransportUris; import com.fsck.k9.mail.store.RemoteStore; -import com.fsck.k9.account.AccountCreator; import com.fsck.k9.view.ClientCertificateSpinner; import com.fsck.k9.view.ClientCertificateSpinner.OnClientCertificateChangedListener; +import timber.log.Timber; /** * Prompts the user for the email address and password. @@ -412,7 +412,7 @@ public class AccountSetupBasics extends K9Activity ServerSettings transportServer = new ServerSettings(ServerSettings.Type.SMTP, "mail." + domain, -1, ConnectionSecurity.SSL_TLS_REQUIRED, authenticationType, user, password, clientCertificateAlias); String storeUri = RemoteStore.createStoreUri(storeServer); - String transportUri = Transport.createTransportUri(transportServer); + String transportUri = TransportUris.createTransportUri(transportServer); mAccount.setStoreUri(storeUri); mAccount.setTransportUri(transportUri); diff --git a/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java b/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java index 2fea3592a..3bf0cb660 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java @@ -1,6 +1,12 @@ package com.fsck.k9.activity.setup; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; + import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -8,37 +14,41 @@ import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.text.method.DigitsKeyListener; -import timber.log.Timber; import android.view.View; import android.view.View.OnClickListener; -import android.widget.*; +import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; -import com.fsck.k9.*; +import com.fsck.k9.Account; import com.fsck.k9.Account.FolderMode; -import com.fsck.k9.mail.NetworkType; +import com.fsck.k9.Preferences; +import com.fsck.k9.R; +import com.fsck.k9.account.AccountCreator; import com.fsck.k9.activity.K9Activity; import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.AuthType; import com.fsck.k9.mail.ConnectionSecurity; +import com.fsck.k9.mail.NetworkType; import com.fsck.k9.mail.ServerSettings; import com.fsck.k9.mail.ServerSettings.Type; import com.fsck.k9.mail.Store; -import com.fsck.k9.mail.Transport; +import com.fsck.k9.mail.TransportUris; import com.fsck.k9.mail.store.RemoteStore; import com.fsck.k9.mail.store.imap.ImapStoreSettings; import com.fsck.k9.mail.store.webdav.WebDavStoreSettings; -import com.fsck.k9.account.AccountCreator; import com.fsck.k9.service.MailService; import com.fsck.k9.view.ClientCertificateSpinner; import com.fsck.k9.view.ClientCertificateSpinner.OnClientCertificateChangedListener; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; +import timber.log.Timber; public class AccountSetupIncoming extends K9Activity implements OnClickListener { private static final String EXTRA_ACCOUNT = "account"; @@ -521,7 +531,7 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener URI oldUri = new URI(mAccount.getTransportUri()); ServerSettings transportServer = new ServerSettings(Type.SMTP, oldUri.getHost(), oldUri.getPort(), ConnectionSecurity.SSL_TLS_REQUIRED, authType, username, password, clientCertificateAlias); - String transportUri = Transport.createTransportUri(transportServer); + String transportUri = TransportUris.createTransportUri(transportServer); mAccount.setTransportUri(transportUri); } catch (URISyntaxException use) { /* diff --git a/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java b/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java index cf0ed34f7..7c53c4c65 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java @@ -1,35 +1,46 @@ package com.fsck.k9.activity.setup; + +import java.net.URI; +import java.net.URISyntaxException; + import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.text.method.DigitsKeyListener; -import timber.log.Timber; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.*; +import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; -import com.fsck.k9.*; +import com.fsck.k9.Account; +import com.fsck.k9.Preferences; +import com.fsck.k9.R; import com.fsck.k9.account.AccountCreator; import com.fsck.k9.activity.K9Activity; import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.AuthType; -import com.fsck.k9.mail.ServerSettings.Type; import com.fsck.k9.mail.ConnectionSecurity; import com.fsck.k9.mail.ServerSettings; +import com.fsck.k9.mail.ServerSettings.Type; import com.fsck.k9.mail.Transport; +import com.fsck.k9.mail.TransportUris; import com.fsck.k9.view.ClientCertificateSpinner; import com.fsck.k9.view.ClientCertificateSpinner.OnClientCertificateChangedListener; - -import java.net.URI; -import java.net.URISyntaxException; +import timber.log.Timber; public class AccountSetupOutgoing extends K9Activity implements OnClickListener, OnCheckedChangeListener { @@ -135,7 +146,7 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener, } try { - ServerSettings settings = Transport.decodeTransportUri(mAccount.getTransportUri()); + ServerSettings settings = TransportUris.decodeTransportUri(mAccount.getTransportUri()); updateAuthPlainTextFromSecurityType(settings.connectionSecurity); @@ -467,7 +478,7 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener, String newHost = mServerView.getText().toString(); int newPort = Integer.parseInt(mPortView.getText().toString()); ServerSettings server = new ServerSettings(Type.SMTP, newHost, newPort, securityType, authType, username, password, clientCertificateAlias); - uri = Transport.createTransportUri(server); + uri = TransportUris.createTransportUri(server); mAccount.deleteCertificate(newHost, newPort, CheckDirection.OUTGOING); mAccount.setTransportUri(uri); AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING); diff --git a/k9mail/src/main/java/com/fsck/k9/preferences/SettingsExporter.java b/k9mail/src/main/java/com/fsck/k9/preferences/SettingsExporter.java index 8338d90cf..4d1e5e96b 100644 --- a/k9mail/src/main/java/com/fsck/k9/preferences/SettingsExporter.java +++ b/k9mail/src/main/java/com/fsck/k9/preferences/SettingsExporter.java @@ -20,6 +20,7 @@ import android.content.Context; import android.net.Uri; import android.os.Environment; +import com.fsck.k9.mail.TransportUris; import timber.log.Timber; import android.util.Xml; @@ -266,7 +267,7 @@ public class SettingsExporter { // Write outgoing server settings - ServerSettings outgoing = Transport.decodeTransportUri(account.getTransportUri()); + ServerSettings outgoing = TransportUris.decodeTransportUri(account.getTransportUri()); serializer.startTag(null, OUTGOING_SERVER_ELEMENT); serializer.attribute(null, TYPE_ATTRIBUTE, outgoing.type.name()); diff --git a/k9mail/src/main/java/com/fsck/k9/preferences/SettingsImporter.java b/k9mail/src/main/java/com/fsck/k9/preferences/SettingsImporter.java index 001d3d5f8..27dd4ee49 100644 --- a/k9mail/src/main/java/com/fsck/k9/preferences/SettingsImporter.java +++ b/k9mail/src/main/java/com/fsck/k9/preferences/SettingsImporter.java @@ -15,6 +15,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; + +import com.fsck.k9.mail.TransportUris; import timber.log.Timber; import com.fsck.k9.Account; @@ -361,7 +363,7 @@ public class SettingsImporter { if (account.outgoing != null) { // Write outgoing server settings (transportUri) ServerSettings outgoing = new ImportedServerSettings(account.outgoing); - String transportUri = Transport.createTransportUri(outgoing); + String transportUri = TransportUris.createTransportUri(outgoing); putString(editor, accountKeyPrefix + Account.TRANSPORT_URI_KEY, Base64.encode(transportUri)); /*