Extract code to find server settings via providers.xml
This commit is contained in:
parent
0c9bb833e5
commit
22798072fd
11 changed files with 249 additions and 140 deletions
|
@ -0,0 +1,5 @@
|
|||
package com.fsck.k9.autodiscovery
|
||||
|
||||
import com.fsck.k9.mail.ServerSettings
|
||||
|
||||
data class ConnectionSettings(val incoming: ServerSettings, val outgoing: ServerSettings)
|
|
@ -0,0 +1,5 @@
|
|||
package com.fsck.k9.autodiscovery
|
||||
|
||||
interface ConnectionSettingsDiscovery {
|
||||
fun discover(email: String): ConnectionSettings?
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.fsck.k9.autodiscovery
|
||||
|
||||
import com.fsck.k9.autodiscovery.providersxml.ProvidersXmlDiscovery
|
||||
import com.fsck.k9.autodiscovery.providersxml.ProvidersXmlProvider
|
||||
import org.koin.dsl.module.applicationContext
|
||||
|
||||
val autodiscoveryModule = applicationContext {
|
||||
factory { ProvidersXmlProvider(get()) }
|
||||
factory { ProvidersXmlDiscovery(get(), get()) }
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package com.fsck.k9.autodiscovery.providersxml;
|
||||
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import android.content.res.XmlResourceParser;
|
||||
|
||||
import com.fsck.k9.autodiscovery.ConnectionSettings;
|
||||
import com.fsck.k9.autodiscovery.ConnectionSettingsDiscovery;
|
||||
import com.fsck.k9.backend.BackendManager;
|
||||
import com.fsck.k9.helper.UrlEncodingHelper;
|
||||
import com.fsck.k9.mail.ServerSettings;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class ProvidersXmlDiscovery implements ConnectionSettingsDiscovery {
|
||||
private final BackendManager backendManager;
|
||||
private final ProvidersXmlProvider xmlProvider;
|
||||
|
||||
|
||||
public ProvidersXmlDiscovery(BackendManager backendManager, ProvidersXmlProvider xmlProvider) {
|
||||
this.backendManager = backendManager;
|
||||
this.xmlProvider = xmlProvider;
|
||||
}
|
||||
|
||||
private String[] splitEmail(String email) {
|
||||
String[] retParts = new String[2];
|
||||
String[] emailParts = email.split("@");
|
||||
retParts[0] = (emailParts.length > 0) ? emailParts[0] : "";
|
||||
retParts[1] = (emailParts.length > 1) ? emailParts[1] : "";
|
||||
return retParts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionSettings discover(String email) {
|
||||
String password = "";
|
||||
String[] emailParts = splitEmail(email);
|
||||
String user = emailParts[0];
|
||||
String domain = emailParts[1];
|
||||
Provider mProvider = findProviderForDomain(domain);
|
||||
if (mProvider == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String userEnc = UrlEncodingHelper.encodeUtf8(user);
|
||||
String passwordEnc = UrlEncodingHelper.encodeUtf8(password);
|
||||
|
||||
String incomingUsername = mProvider.incomingUsernameTemplate;
|
||||
incomingUsername = incomingUsername.replaceAll("\\$email", email);
|
||||
incomingUsername = incomingUsername.replaceAll("\\$user", userEnc);
|
||||
incomingUsername = incomingUsername.replaceAll("\\$domain", domain);
|
||||
|
||||
URI incomingUriTemplate = mProvider.incomingUriTemplate;
|
||||
URI incomingUri = new URI(incomingUriTemplate.getScheme(), incomingUsername + ":" + passwordEnc,
|
||||
incomingUriTemplate.getHost(), incomingUriTemplate.getPort(), null, null, null);
|
||||
|
||||
String outgoingUsername = mProvider.outgoingUsernameTemplate;
|
||||
|
||||
URI outgoingUriTemplate = mProvider.outgoingUriTemplate;
|
||||
|
||||
|
||||
URI outgoingUri;
|
||||
if (outgoingUsername != null) {
|
||||
outgoingUsername = outgoingUsername.replaceAll("\\$email", email);
|
||||
outgoingUsername = outgoingUsername.replaceAll("\\$user", userEnc);
|
||||
outgoingUsername = outgoingUsername.replaceAll("\\$domain", domain);
|
||||
outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUsername + ":"
|
||||
+ passwordEnc, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null,
|
||||
null, null);
|
||||
|
||||
} else {
|
||||
outgoingUri = new URI(outgoingUriTemplate.getScheme(),
|
||||
null, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null,
|
||||
null, null);
|
||||
}
|
||||
|
||||
ServerSettings incomingSettings = backendManager.decodeStoreUri(incomingUri.toString());
|
||||
ServerSettings outgoingSettings = backendManager.decodeTransportUri(outgoingUri.toString());
|
||||
return new ConnectionSettings(incomingSettings, outgoingSettings);
|
||||
} catch (URISyntaxException use) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Provider findProviderForDomain(String domain) {
|
||||
try {
|
||||
XmlResourceParser xml = xmlProvider.getXml();
|
||||
int xmlEventType;
|
||||
Provider provider = null;
|
||||
while ((xmlEventType = xml.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
if (xmlEventType == XmlPullParser.START_TAG &&
|
||||
"provider".equals(xml.getName()) &&
|
||||
domain.equalsIgnoreCase(xml.getAttributeValue(null, "domain"))) {
|
||||
provider = new Provider();
|
||||
provider.id = xml.getAttributeValue(null, "id");
|
||||
provider.label = xml.getAttributeValue(null, "label");
|
||||
provider.domain = xml.getAttributeValue(null, "domain");
|
||||
} else if (xmlEventType == XmlPullParser.START_TAG &&
|
||||
"incoming".equals(xml.getName()) &&
|
||||
provider != null) {
|
||||
provider.incomingUriTemplate = new URI(xml.getAttributeValue(null, "uri"));
|
||||
provider.incomingUsernameTemplate = xml.getAttributeValue(null, "username");
|
||||
} else if (xmlEventType == XmlPullParser.START_TAG &&
|
||||
"outgoing".equals(xml.getName()) &&
|
||||
provider != null) {
|
||||
provider.outgoingUriTemplate = new URI(xml.getAttributeValue(null, "uri"));
|
||||
provider.outgoingUsernameTemplate = xml.getAttributeValue(null, "username");
|
||||
} else if (xmlEventType == XmlPullParser.END_TAG &&
|
||||
"provider".equals(xml.getName()) &&
|
||||
provider != null) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Timber.e(e, "Error while trying to load provider settings.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static class Provider {
|
||||
String id;
|
||||
String label;
|
||||
String domain;
|
||||
URI incomingUriTemplate;
|
||||
String incomingUsernameTemplate;
|
||||
URI outgoingUriTemplate;
|
||||
String outgoingUsernameTemplate;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.fsck.k9.autodiscovery.providersxml
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.XmlResourceParser
|
||||
import com.fsck.k9.autodiscovery.R
|
||||
|
||||
class ProvidersXmlProvider(private val context: Context) {
|
||||
fun getXml(): XmlResourceParser {
|
||||
return context.resources.getXml(R.xml.providers)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.fsck.k9.autodiscovery.providersxml
|
||||
|
||||
import com.fsck.k9.RobolectricTest
|
||||
import com.fsck.k9.backend.BackendManager
|
||||
import com.fsck.k9.backend.imap.ImapStoreUriDecoder
|
||||
import com.fsck.k9.mail.AuthType
|
||||
import com.fsck.k9.mail.ConnectionSecurity
|
||||
import com.fsck.k9.mail.transport.smtp.SmtpTransportUriDecoder
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.nhaarman.mockito_kotlin.doAnswer
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
|
||||
|
||||
class ProvidersXmlDiscoveryTest : RobolectricTest() {
|
||||
val backendManager = mock<BackendManager> {
|
||||
on { decodeStoreUri(anyString()) } doAnswer { mock -> ImapStoreUriDecoder.decode(mock.getArgument(0)) }
|
||||
on { decodeTransportUri(anyString()) } doAnswer { mock ->
|
||||
SmtpTransportUriDecoder.decodeSmtpUri(mock.getArgument(0))
|
||||
}
|
||||
}
|
||||
val xmlProvider = ProvidersXmlProvider(RuntimeEnvironment.application)
|
||||
val providersXmlDiscovery = ProvidersXmlDiscovery(backendManager, xmlProvider)
|
||||
|
||||
|
||||
@Test
|
||||
fun discover_withGmailDomain_shouldReturnCorrectSettings() {
|
||||
val connectionSettings = providersXmlDiscovery.discover("user@gmail.com")
|
||||
|
||||
assertThat(connectionSettings).isNotNull()
|
||||
with(connectionSettings!!.incoming) {
|
||||
assertThat(host).isEqualTo("imap.gmail.com")
|
||||
assertThat(connectionSecurity).isEqualTo(ConnectionSecurity.SSL_TLS_REQUIRED)
|
||||
assertThat(authenticationType).isEqualTo(AuthType.PLAIN)
|
||||
assertThat(username).isEqualTo("user@gmail.com")
|
||||
}
|
||||
with(connectionSettings.outgoing) {
|
||||
assertThat(host).isEqualTo("smtp.gmail.com")
|
||||
assertThat(connectionSecurity).isEqualTo(ConnectionSecurity.SSL_TLS_REQUIRED)
|
||||
assertThat(authenticationType).isEqualTo(AuthType.PLAIN)
|
||||
assertThat(username).isEqualTo("user@gmail.com")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun discover_withUnknownDomain_shouldReturnNull() {
|
||||
val connectionSettings = providersXmlDiscovery.discover("user@not.present.in.providers.xml.example")
|
||||
|
||||
assertThat(connectionSettings).isNull()
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
mock-maker-inline
|
|
@ -9,6 +9,7 @@ dependencies {
|
|||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
|
||||
|
||||
implementation project(":app:core")
|
||||
implementation project(":app:autodiscovery")
|
||||
implementation project(":mail:common")
|
||||
|
||||
//TODO: Remove AccountSetupIncoming's dependency on these
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.fsck.k9
|
|||
|
||||
import com.fsck.k9.account.accountModule
|
||||
import com.fsck.k9.activity.activityModule
|
||||
import com.fsck.k9.autodiscovery.autodiscoveryModule
|
||||
import com.fsck.k9.contacts.contactsModule
|
||||
import com.fsck.k9.fragment.fragmentModule
|
||||
import com.fsck.k9.ui.endtoend.endToEndUiModule
|
||||
|
@ -15,5 +16,6 @@ val uiModules = listOf(
|
|||
endToEndUiModule,
|
||||
fragmentModule,
|
||||
contactsModule,
|
||||
accountModule
|
||||
accountModule,
|
||||
autodiscoveryModule
|
||||
)
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
package com.fsck.k9.activity.setup;
|
||||
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
|
@ -27,8 +23,10 @@ import com.fsck.k9.Preferences;
|
|||
import com.fsck.k9.account.AccountCreator;
|
||||
import com.fsck.k9.activity.K9Activity;
|
||||
import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection;
|
||||
import com.fsck.k9.autodiscovery.ConnectionSettings;
|
||||
import com.fsck.k9.autodiscovery.providersxml.ProvidersXmlDiscovery;
|
||||
import com.fsck.k9.backend.BackendManager;
|
||||
import com.fsck.k9.helper.UrlEncodingHelper;
|
||||
import com.fsck.k9.helper.EmailHelper;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.AuthType;
|
||||
import com.fsck.k9.mail.ConnectionSecurity;
|
||||
|
@ -53,6 +51,7 @@ public class AccountSetupBasics extends K9Activity
|
|||
|
||||
|
||||
private final BackendManager backendManager = DI.get(BackendManager.class);
|
||||
private final ProvidersXmlDiscovery providersXmlDiscovery = DI.get(ProvidersXmlDiscovery.class);
|
||||
|
||||
private EditText mEmailView;
|
||||
private EditText mPasswordView;
|
||||
|
@ -236,67 +235,30 @@ public class AccountSetupBasics extends K9Activity
|
|||
return name;
|
||||
}
|
||||
|
||||
private void finishAutoSetup(Provider provider) {
|
||||
private void finishAutoSetup(ConnectionSettings connectionSettings) {
|
||||
String email = mEmailView.getText().toString();
|
||||
String password = mPasswordView.getText().toString();
|
||||
String[] emailParts = splitEmail(email);
|
||||
String user = emailParts[0];
|
||||
String domain = emailParts[1];
|
||||
try {
|
||||
String userEnc = UrlEncodingHelper.encodeUtf8(user);
|
||||
String passwordEnc = UrlEncodingHelper.encodeUtf8(password);
|
||||
|
||||
String incomingUsername = provider.incomingUsernameTemplate;
|
||||
incomingUsername = incomingUsername.replaceAll("\\$email", email);
|
||||
incomingUsername = incomingUsername.replaceAll("\\$user", userEnc);
|
||||
incomingUsername = incomingUsername.replaceAll("\\$domain", domain);
|
||||
|
||||
URI incomingUriTemplate = provider.incomingUriTemplate;
|
||||
URI incomingUri = new URI(incomingUriTemplate.getScheme(), incomingUsername + ":" + passwordEnc,
|
||||
incomingUriTemplate.getHost(), incomingUriTemplate.getPort(), null, null, null);
|
||||
|
||||
String outgoingUsername = provider.outgoingUsernameTemplate;
|
||||
|
||||
URI outgoingUriTemplate = provider.outgoingUriTemplate;
|
||||
|
||||
|
||||
URI outgoingUri;
|
||||
if (outgoingUsername != null) {
|
||||
outgoingUsername = outgoingUsername.replaceAll("\\$email", email);
|
||||
outgoingUsername = outgoingUsername.replaceAll("\\$user", userEnc);
|
||||
outgoingUsername = outgoingUsername.replaceAll("\\$domain", domain);
|
||||
outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUsername + ":"
|
||||
+ passwordEnc, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null,
|
||||
null, null);
|
||||
|
||||
} else {
|
||||
outgoingUri = new URI(outgoingUriTemplate.getScheme(),
|
||||
null, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null,
|
||||
null, null);
|
||||
|
||||
|
||||
}
|
||||
if (mAccount == null) {
|
||||
mAccount = Preferences.getPreferences(this).newAccount();
|
||||
mAccount.setChipColor(AccountCreator.pickColor(this));
|
||||
}
|
||||
mAccount.setName(getOwnerName());
|
||||
mAccount.setEmail(email);
|
||||
mAccount.setStoreUri(incomingUri.toString());
|
||||
mAccount.setTransportUri(outgoingUri.toString());
|
||||
|
||||
ServerSettings incomingSettings = backendManager.decodeStoreUri(incomingUri.toString());
|
||||
mAccount.setDeletePolicy(AccountCreator.getDefaultDeletePolicy(incomingSettings.type));
|
||||
|
||||
// Check incoming here. Then check outgoing in onActivityResult()
|
||||
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.INCOMING);
|
||||
} catch (URISyntaxException use) {
|
||||
/*
|
||||
* If there is some problem with the URI we give up and go on to
|
||||
* manual setup.
|
||||
*/
|
||||
onManualSetup();
|
||||
if (mAccount == null) {
|
||||
mAccount = Preferences.getPreferences(this).newAccount();
|
||||
mAccount.setChipColor(AccountCreator.pickColor(this));
|
||||
}
|
||||
|
||||
mAccount.setName(getOwnerName());
|
||||
mAccount.setEmail(email);
|
||||
|
||||
ServerSettings incomingServerSettings = connectionSettings.getIncoming().newPassword(password);
|
||||
String storeUri = backendManager.createStoreUri(incomingServerSettings);
|
||||
mAccount.setStoreUri(storeUri);
|
||||
|
||||
ServerSettings outgoingServerSettings = connectionSettings.getOutgoing().newPassword(password);
|
||||
String transportUri = backendManager.createTransportUri(outgoingServerSettings);
|
||||
mAccount.setTransportUri(transportUri);
|
||||
|
||||
mAccount.setDeletePolicy(AccountCreator.getDefaultDeletePolicy(incomingServerSettings.type));
|
||||
|
||||
// Check incoming here. Then check outgoing in onActivityResult()
|
||||
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.INCOMING);
|
||||
}
|
||||
|
||||
private void onNext() {
|
||||
|
@ -308,12 +270,10 @@ public class AccountSetupBasics extends K9Activity
|
|||
}
|
||||
|
||||
String email = mEmailView.getText().toString();
|
||||
String[] emailParts = splitEmail(email);
|
||||
String domain = emailParts[1];
|
||||
|
||||
Provider provider = findProviderForDomain(domain);
|
||||
if (provider != null) {
|
||||
finishAutoSetup(provider);
|
||||
ConnectionSettings connectionSettings = providersXmlDiscovery.discover(email);
|
||||
if (connectionSettings != null) {
|
||||
finishAutoSetup(connectionSettings);
|
||||
} else {
|
||||
// We don't have default settings for this account, start the manual setup process.
|
||||
onManualSetup();
|
||||
|
@ -340,8 +300,7 @@ public class AccountSetupBasics extends K9Activity
|
|||
|
||||
private void onManualSetup() {
|
||||
String email = mEmailView.getText().toString();
|
||||
String[] emailParts = splitEmail(email);
|
||||
String domain = emailParts[1];
|
||||
String domain = EmailHelper.getDomainFromEmailAddress(email);
|
||||
|
||||
String password = null;
|
||||
String clientCertificateAlias = null;
|
||||
|
@ -385,74 +344,4 @@ public class AccountSetupBasics extends K9Activity
|
|||
onManualSetup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get the given attribute as a String resource first, and if it fails
|
||||
* returns the attribute as a simple String value.
|
||||
* @param xml
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
private String getXmlAttribute(XmlResourceParser xml, String name) {
|
||||
int resId = xml.getAttributeResourceValue(null, name, 0);
|
||||
if (resId == 0) {
|
||||
return xml.getAttributeValue(null, name);
|
||||
} else {
|
||||
return getString(resId);
|
||||
}
|
||||
}
|
||||
|
||||
private Provider findProviderForDomain(String domain) {
|
||||
try {
|
||||
XmlResourceParser xml = getResources().getXml(R.xml.providers);
|
||||
int xmlEventType;
|
||||
Provider provider = null;
|
||||
while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
|
||||
if (xmlEventType == XmlResourceParser.START_TAG
|
||||
&& "provider".equals(xml.getName())
|
||||
&& domain.equalsIgnoreCase(getXmlAttribute(xml, "domain"))) {
|
||||
provider = new Provider();
|
||||
provider.id = getXmlAttribute(xml, "id");
|
||||
provider.label = getXmlAttribute(xml, "label");
|
||||
provider.domain = getXmlAttribute(xml, "domain");
|
||||
} else if (xmlEventType == XmlResourceParser.START_TAG
|
||||
&& "incoming".equals(xml.getName())
|
||||
&& provider != null) {
|
||||
provider.incomingUriTemplate = new URI(getXmlAttribute(xml, "uri"));
|
||||
provider.incomingUsernameTemplate = getXmlAttribute(xml, "username");
|
||||
} else if (xmlEventType == XmlResourceParser.START_TAG
|
||||
&& "outgoing".equals(xml.getName())
|
||||
&& provider != null) {
|
||||
provider.outgoingUriTemplate = new URI(getXmlAttribute(xml, "uri"));
|
||||
provider.outgoingUsernameTemplate = getXmlAttribute(xml, "username");
|
||||
} else if (xmlEventType == XmlResourceParser.END_TAG
|
||||
&& "provider".equals(xml.getName())
|
||||
&& provider != null) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Timber.e(e, "Error while trying to load provider settings.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String[] splitEmail(String email) {
|
||||
String[] retParts = new String[2];
|
||||
String[] emailParts = email.split("@");
|
||||
retParts[0] = (emailParts.length > 0) ? emailParts[0] : "";
|
||||
retParts[1] = (emailParts.length > 1) ? emailParts[1] : "";
|
||||
return retParts;
|
||||
}
|
||||
|
||||
|
||||
static class Provider {
|
||||
public String id;
|
||||
public String label;
|
||||
public String domain;
|
||||
public URI incomingUriTemplate;
|
||||
public String incomingUsernameTemplate;
|
||||
public URI outgoingUriTemplate;
|
||||
public String outgoingUsernameTemplate;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue