diff --git a/app/core/src/main/java/com/fsck/k9/helper/Utility.java b/app/core/src/main/java/com/fsck/k9/helper/Utility.java index 1788f8b3a013d484eefc44b589ec6a4d71172912..8775ca0db38ee0ce63c3888262f54a4380e4454c 100644 --- a/app/core/src/main/java/com/fsck/k9/helper/Utility.java +++ b/app/core/src/main/java/com/fsck/k9/helper/Utility.java @@ -295,4 +295,8 @@ public class Utility { return null; } + + public static boolean isStringEmpty(String st) { + return (st == null || st.trim().equals("")); + } } diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle index 940597d77a774a051f9c0e0e142259442d92472b..f6c923edfb4a5327643619ffef5b0419d9cbaacb 100644 --- a/app/k9mail/build.gradle +++ b/app/k9mail/build.gradle @@ -26,7 +26,7 @@ dependencies { annotationProcessor "com.github.bumptech.glide:compiler:${versions.glide}" if (project.hasProperty('k9mail.enableLeakCanary') && project.property('k9mail.enableLeakCanary') == "true") { - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4' + debugImplementation "com.squareup.leakcanary:leakcanary-android:${versions.leakcanary}" } // Required for DependencyInjectionTest to be able to resolve OpenPgpApiManager diff --git a/app/ui/legacy/build.gradle b/app/ui/legacy/build.gradle index a7504055da8a62c47ffe699dd9206f85558fae0e..eafb08efa12f8fccf0384890fc73c6f67a426832 100644 --- a/app/ui/legacy/build.gradle +++ b/app/ui/legacy/build.gradle @@ -65,6 +65,9 @@ dependencies { testImplementation "io.insert-koin:koin-test-junit4:${versions.koin}" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:${versions.kotlinCoroutines}" testImplementation "app.cash.turbine:turbine:${versions.turbine}" + + implementation "com.squareup.retrofit2:retrofit:${versions.retrofit}" + implementation "com.squareup.retrofit2:converter-simplexml:${versions.retrofit}" } android { diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloAccountCreator.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloAccountCreator.java index 7249b0d629d7fe42a2430722446ad071c1ef4a4b..b05af6f10d13605e50e3cc9df82031a9a9167a3a 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloAccountCreator.java +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloAccountCreator.java @@ -33,6 +33,10 @@ public class EeloAccountCreator { account.setName(emailId); ConnectionSettings connectionSettings = providersXmlDiscoveryDiscover(emailId); + if (connectionSettings == null) { + // connection details not predefined in the xml. Try to load from the api + connectionSettings = EeloMailAutoConfigDiscovery.retrieveConfigFromApi(emailId); + } if (connectionSettings == null) { Timber.e("Error while trying to initialise account configuration."); return; diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigApi.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigApi.java new file mode 100644 index 0000000000000000000000000000000000000000..675e6eb9266fe5234220b1ec5c1737d53732f0cf --- /dev/null +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigApi.java @@ -0,0 +1,16 @@ +package com.fsck.k9.activity.setup.accountmanager; + + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Url; + + +/** + * To retrieve /e/ cloud mail configuration settings from api + */ +public interface EeloMailAutoConfigApi { + + @GET + Call getConfig(@Url String url); +} diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigBaseServer.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigBaseServer.java new file mode 100644 index 0000000000000000000000000000000000000000..dc558cd84598a064961bf875548bde1735804dee --- /dev/null +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigBaseServer.java @@ -0,0 +1,75 @@ +package com.fsck.k9.activity.setup.accountmanager; + + +import org.simpleframework.xml.Attribute; +import org.simpleframework.xml.Element; + + +public abstract class EeloMailAutoConfigBaseServer { + + @Attribute + private String type; + + @Element + private String hostname; + + @Element(name = "port", type = Integer.class) + private int port; + + @Element + private String socketType; + + @Element + private String authentication; + + @Element + private String username; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getSocketType() { + return socketType; + } + + public void setSocketType(String socketType) { + this.socketType = socketType; + } + + public String getAuthentication() { + return authentication; + } + + public void setAuthentication(String authentication) { + this.authentication = authentication; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigDiscovery.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigDiscovery.java new file mode 100644 index 0000000000000000000000000000000000000000..9c914cbe9945d3451640590632b4ca4102755a23 --- /dev/null +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigDiscovery.java @@ -0,0 +1,177 @@ +package com.fsck.k9.activity.setup.accountmanager; + + +import java.io.IOException; + +import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings; +import com.fsck.k9.helper.EmailHelper; +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.ui.ConnectionSettings; +import retrofit2.Call; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.simplexml.SimpleXmlConverterFactory; +import timber.log.Timber; + + +public class EeloMailAutoConfigDiscovery { + + /** + * Try to retrieve /e/ cloud mail info from the api + * + * @param email retrieved from accountManager for /e/ cloud account + * @return mail's incoming & outgoing connection detail, null if failed to retrieve + */ + public static ConnectionSettings retrieveConfigFromApi(String email) { + String domain = EmailHelper.getDomainFromEmailAddress(email); + if (domain == null) { + return null; + } + + Retrofit retrofit = new Retrofit.Builder() + .baseUrl( + "https://autoconfig.e.email/") //dummy url. Retrofit required base url to configure. But we will use @Url on th api interface level + .addConverterFactory(SimpleXmlConverterFactory.create()) + .build(); + + EeloMailAutoConfigApi eeloMailAutoConfigApi = retrofit.create(EeloMailAutoConfigApi.class); + // api's basic url pattern is: https://autoconfig.${DOMAIN}/mail/config-v1.1.xml?emailaddress=${USER}@${DOMAIN} + Call + eeloMailAutoConfigResponseCall = eeloMailAutoConfigApi + .getConfig("https://autoconfig." + domain + "/mail/config-v1.1.xml?emailaddress=" + email); + try { + Response response = eeloMailAutoConfigResponseCall.execute(); + if (response.isSuccessful()) { + EeloMailAutoConfigResponse eeloMailAutoConfigResponse = response.body(); + return providersAutoConfigDiscoveryDiscover(eeloMailAutoConfigResponse); + } + } catch (IOException e) { + Timber.e(e); + } + return null; + } + + /** + * Parse connection settings from api response + */ + private static ConnectionSettings providersAutoConfigDiscoveryDiscover(EeloMailAutoConfigResponse response) { + if (response == null) { + return null; + } + + DiscoveredServerSettings incoming = getAutoConfigIncomingSettings(response); + DiscoveredServerSettings outgoing = getAutoConfigOutgoingSettings(response); + + if (incoming == null || outgoing == null) { + return null; + } + + return new ConnectionSettings( + new ServerSettings( + incoming.getProtocol(), + incoming.getHost(), + incoming.getPort(), + incoming.getSecurity(), + incoming.getAuthType(), + incoming.getUsername(), + null, + null + ), + new ServerSettings( + outgoing.getProtocol(), + outgoing.getHost(), + outgoing.getPort(), + outgoing.getSecurity(), + outgoing.getAuthType(), + outgoing.getUsername(), + null, + null + ) + ); + } + + /** + * parse common settings for incoming & outgoing mail server + */ + private static DiscoveredServerSettings getAutoConfigSettings(EeloMailAutoConfigBaseServer server) { + if (Utility.isStringEmpty(server.getType())) { + return null; + } + if (Utility.isStringEmpty(server.getHostname())) { + return null; + } + + if (Utility.isStringEmpty(server.getUsername())) { + return null; + } + + AuthType authType = getAuthType(server.getAuthentication()); + if (authType == null) { + return null; + } + + if (Utility.isStringEmpty(server.getSocketType())) { + return null; + } + + ConnectionSecurity security = getConnectionSecurity(server.getSocketType()); + if (security == null) { + return null; + } + + return new DiscoveredServerSettings(server.getType(), server.getHostname(), server.getPort(), security, + authType, server.getUsername()); + } + + private static AuthType getAuthType(String authString) { + if (Utility.isStringEmpty(authString)) { + return null; + } + authString = authString.toUpperCase(); + switch (authString) { + case "PASSWORD-CLEARTEXT": + return AuthType.PLAIN; + case "PASSWORD-ENCRYPTED": + return AuthType.CRAM_MD5; + case "OAUTH2": + return AuthType.XOAUTH2; + } + return null; + } + + private static ConnectionSecurity getConnectionSecurity(String securityString) { + if (Utility.isStringEmpty(securityString)) { + return null; + } + securityString = securityString.toUpperCase(); + switch (securityString) { + case "SSL": + return ConnectionSecurity.SSL_TLS_REQUIRED; + case "STARTTLS": + return ConnectionSecurity.STARTTLS_REQUIRED; + case "PLAIN": + return ConnectionSecurity.NONE; + } + return null; + } + + private static DiscoveredServerSettings getAutoConfigIncomingSettings(EeloMailAutoConfigResponse response) { + if (response.getEmailProvider() == null || response.getEmailProvider().getIncomingServer() == null) { + return null; + } + return getAutoConfigSettings(response.getEmailProvider().getIncomingServer()); + } + + private static DiscoveredServerSettings getAutoConfigOutgoingSettings(EeloMailAutoConfigResponse response) { + if (response.getEmailProvider() == null || response.getEmailProvider().getOutgoingServer() == null) { + return null; + } + return getAutoConfigSettings(response.getEmailProvider().getOutgoingServer()); + } + + private EeloMailAutoConfigDiscovery() { + } +} diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigEmailProvider.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigEmailProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..fdd09588cebaaf28ac2283d3d89ea82f57edfba1 --- /dev/null +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigEmailProvider.java @@ -0,0 +1,44 @@ +package com.fsck.k9.activity.setup.accountmanager; + + +import org.simpleframework.xml.Attribute; +import org.simpleframework.xml.Element; +import org.simpleframework.xml.Root; + + +@Root(name = "emailProvider", strict = false) +public class EeloMailAutoConfigEmailProvider { + + @Attribute + private String id; + + @Element + private EeloMailAutoConfigOutgoingServer outgoingServer; + + @Element + private EeloMailAutoConfigIncomingServer incomingServer; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public EeloMailAutoConfigOutgoingServer getOutgoingServer() { + return outgoingServer; + } + + public void setOutgoingServer(EeloMailAutoConfigOutgoingServer outgoingServer) { + this.outgoingServer = outgoingServer; + } + + public EeloMailAutoConfigIncomingServer getIncomingServer() { + return incomingServer; + } + + public void setIncomingServer(EeloMailAutoConfigIncomingServer incomingServer) { + this.incomingServer = incomingServer; + } +} diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigIncomingServer.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigIncomingServer.java new file mode 100644 index 0000000000000000000000000000000000000000..dee6f7dad3f8bcf96a79c02fc8f59d1528cd5d4f --- /dev/null +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigIncomingServer.java @@ -0,0 +1,9 @@ +package com.fsck.k9.activity.setup.accountmanager; + + +import org.simpleframework.xml.Root; + + +@Root(name = "incomingServer", strict = false) +public class EeloMailAutoConfigIncomingServer extends EeloMailAutoConfigBaseServer { +} diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigOutgoingServer.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigOutgoingServer.java new file mode 100644 index 0000000000000000000000000000000000000000..7da5c2a2eaf261397e489546b98cfbbdee71ad80 --- /dev/null +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigOutgoingServer.java @@ -0,0 +1,22 @@ +package com.fsck.k9.activity.setup.accountmanager; + + +import org.simpleframework.xml.Element; +import org.simpleframework.xml.Root; + + +@Root(name = "outgoingServer", strict = false) +public class EeloMailAutoConfigOutgoingServer extends EeloMailAutoConfigBaseServer { + + @Element + private String useGlobalPreferredServer; + + public String getUseGlobalPreferredServer() { + return useGlobalPreferredServer; + } + + public void setUseGlobalPreferredServer(String useGlobalPreferredServer) { + this.useGlobalPreferredServer = useGlobalPreferredServer; + } +} + diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigResponse.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..eba8eabc7a8df824c31ef45eb98e6c1e285e5bad --- /dev/null +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloMailAutoConfigResponse.java @@ -0,0 +1,33 @@ +package com.fsck.k9.activity.setup.accountmanager; + + +import org.simpleframework.xml.Attribute; +import org.simpleframework.xml.Element; +import org.simpleframework.xml.Root; + + +@Root(name = "clientConfig", strict = false) +public class EeloMailAutoConfigResponse { + + @Attribute + private String version; + + @Element + private EeloMailAutoConfigEmailProvider emailProvider; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public EeloMailAutoConfigEmailProvider getEmailProvider() { + return emailProvider; + } + + public void setEmailProvider(EeloMailAutoConfigEmailProvider emailProvider) { + this.emailProvider = emailProvider; + } +} diff --git a/build.gradle b/build.gradle index 0f209cbcd2929d0eec7091f44b43f388155b05b8..073834c7b961047a1eb23b4cc4185bb1b14cb331 100644 --- a/build.gradle +++ b/build.gradle @@ -49,8 +49,8 @@ buildscript { 'mockitoKotlin': '4.0.0', 'truth': '1.1.3', 'turbine': '0.7.0', - - 'ktlint': '0.40.0' + 'ktlint': '0.40.0', + 'leakcanary': '2.8.1' ] javaVersion = JavaVersion.VERSION_11