Clean up code
This commit is contained in:
parent
b7652205ae
commit
d6423ff85e
4 changed files with 161 additions and 133 deletions
|
@ -1,26 +1,40 @@
|
|||
package com.fsck.k9.autodiscovery.thunderbird
|
||||
|
||||
import com.fsck.k9.helper.EmailHelper
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.io.InputStream
|
||||
import java.net.URLEncoder
|
||||
|
||||
class ThunderbirdAutoconfigFetcher(private val client: OkHttpClient) {
|
||||
class ThunderbirdAutoconfigFetcher(private val okHttpClient: OkHttpClient) {
|
||||
|
||||
fun fetchAutoconfigFile(email: String): InputStream? {
|
||||
val url = getAutodiscoveryAddress(email)
|
||||
val request = Request.Builder().url(url).build()
|
||||
|
||||
return client.newCall(request).execute().body()?.byteStream()
|
||||
val response = okHttpClient.newCall(request).execute()
|
||||
|
||||
return if (response.isSuccessful) {
|
||||
response.body()?.byteStream()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
// address described at:
|
||||
// https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration#Configuration_server_at_ISP
|
||||
internal fun getAutodiscoveryAddress(email: String): String {
|
||||
internal fun getAutodiscoveryAddress(email: String): HttpUrl {
|
||||
val domain = EmailHelper.getDomainFromEmailAddress(email)
|
||||
return "https://${domain}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=" + URLEncoder.encode(email, "UTF-8")
|
||||
requireNotNull(domain) { "Couldn't extract domain from email address: $email" }
|
||||
|
||||
return HttpUrl.Builder()
|
||||
.scheme("https")
|
||||
.host(domain)
|
||||
.addEncodedPathSegments(".well-known/autoconfig/mail/config-v1.1.xml")
|
||||
.addQueryParameter("emailaddress", email)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,12 @@ import java.io.IOException
|
|||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
|
||||
/**
|
||||
* Parser for Thunderbird's
|
||||
* [Autoconfig file format](https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat)
|
||||
*/
|
||||
class ThunderbirdAutoconfigParser {
|
||||
// structure described at:
|
||||
// https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat
|
||||
fun parseSettings(stream: InputStream?, email: String): ConnectionSettings? {
|
||||
if (stream == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
fun parseSettings(stream: InputStream, email: String): ConnectionSettings? {
|
||||
var incoming: ServerSettings? = null
|
||||
var outgoing: ServerSettings? = null
|
||||
|
||||
|
@ -30,10 +28,13 @@ class ThunderbirdAutoconfigParser {
|
|||
var eventType = xpp.eventType
|
||||
while (eventType != XmlPullParser.END_DOCUMENT) {
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
if ("incomingServer" == xpp.name) {
|
||||
incoming = parseServer(xpp, "incomingServer", email)
|
||||
} else if ("outgoingServer" == xpp.name) {
|
||||
outgoing = parseServer(xpp, "outgoingServer", email)
|
||||
when (xpp.name) {
|
||||
"incomingServer" -> {
|
||||
incoming = parseServer(xpp, "incomingServer", email)
|
||||
}
|
||||
"outgoingServer" -> {
|
||||
outgoing = parseServer(xpp, "outgoingServer", email)
|
||||
}
|
||||
}
|
||||
|
||||
if (incoming != null && outgoing != null) {
|
||||
|
@ -56,16 +57,22 @@ class ThunderbirdAutoconfigParser {
|
|||
var eventType = xpp.eventType
|
||||
while (!(eventType == XmlPullParser.END_TAG && nodeName == xpp.name)) {
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
if (xpp.name == "hostname") {
|
||||
host = getText(xpp)
|
||||
} else if (xpp.name == "port") {
|
||||
port = getText(xpp).toInt()
|
||||
} else if (xpp.name == "username") {
|
||||
username = getText(xpp).replace("%EMAILADDRESS%", email)
|
||||
} else if (xpp.name == "authentication" && authType == null) {
|
||||
authType = parseAuthType(getText(xpp))
|
||||
} else if (xpp.name == "socketType") {
|
||||
connectionSecurity = parseSocketType(getText(xpp))
|
||||
when (xpp.name) {
|
||||
"hostname" -> {
|
||||
host = getText(xpp)
|
||||
}
|
||||
"port" -> {
|
||||
port = getText(xpp).toInt()
|
||||
}
|
||||
"username" -> {
|
||||
username = getText(xpp).replace("%EMAILADDRESS%", email)
|
||||
}
|
||||
"authentication" -> {
|
||||
if (authType == null) authType = parseAuthType(getText(xpp))
|
||||
}
|
||||
"socketType" -> {
|
||||
connectionSecurity = parseSocketType(getText(xpp))
|
||||
}
|
||||
}
|
||||
}
|
||||
eventType = xpp.next()
|
||||
|
@ -95,8 +102,6 @@ class ThunderbirdAutoconfigParser {
|
|||
@Throws(XmlPullParserException::class, IOException::class)
|
||||
private fun getText(xpp: XmlPullParser): String {
|
||||
val eventType = xpp.next()
|
||||
return if (eventType != XmlPullParser.TEXT) {
|
||||
""
|
||||
} else xpp.text
|
||||
return if (eventType != XmlPullParser.TEXT) "" else xpp.text
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ class ThunderbirdDiscovery(
|
|||
): ConnectionSettingsDiscovery {
|
||||
|
||||
override fun discover(email: String): ConnectionSettings? {
|
||||
return fetcher.fetchAutoconfigFile(email).use {
|
||||
val autoconfigInputStream = fetcher.fetchAutoconfigFile(email) ?: return null
|
||||
|
||||
return autoconfigInputStream.use {
|
||||
parser.parseSettings(it, email)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package com.fsck.k9.autodiscovery.thunderbird
|
||||
|
||||
import com.fsck.k9.RobolectricTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class ThunderbirdAutoconfigTest : RobolectricTest() {
|
||||
|
@ -11,133 +9,142 @@ class ThunderbirdAutoconfigTest : RobolectricTest() {
|
|||
|
||||
@Test
|
||||
fun settingsExtract() {
|
||||
val settings = parser.parseSettings("""<?xml version="1.0"?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="metacode.biz">
|
||||
<domain>metacode.biz</domain>
|
||||
val input = """<?xml version="1.0"?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="metacode.biz">
|
||||
<domain>metacode.biz</domain>
|
||||
|
||||
<incomingServer type="imap">
|
||||
<hostname>imap.googlemail.com</hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
<incomingServer type="imap">
|
||||
<hostname>imap.googlemail.com</hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
|
||||
<outgoingServer type="smtp">
|
||||
<hostname>smtp.googlemail.com</hostname>
|
||||
<port>465</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<addThisServer>true</addThisServer>
|
||||
</outgoingServer>
|
||||
</emailProvider>
|
||||
<outgoingServer type="smtp">
|
||||
<hostname>smtp.googlemail.com</hostname>
|
||||
<port>465</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<addThisServer>true</addThisServer>
|
||||
</outgoingServer>
|
||||
</emailProvider>
|
||||
</clientConfig>
|
||||
""".trimIndent().byteInputStream()
|
||||
|
||||
</clientConfig>""".byteInputStream(), "test@metacode.biz")
|
||||
val connectionSettings = parser.parseSettings(input, "test@metacode.biz")
|
||||
|
||||
assertNotNull(settings)
|
||||
assertNotNull(settings?.outgoing)
|
||||
assertNotNull(settings?.incoming)
|
||||
|
||||
assertEquals("imap.googlemail.com", settings?.incoming?.host)
|
||||
assertEquals(993, settings?.incoming?.port)
|
||||
assertEquals("test@metacode.biz", settings?.incoming?.username)
|
||||
|
||||
assertEquals("smtp.googlemail.com", settings?.outgoing?.host)
|
||||
assertEquals(465, settings?.outgoing?.port)
|
||||
assertEquals("test@metacode.biz", settings?.outgoing?.username)
|
||||
assertThat(connectionSettings).isNotNull()
|
||||
assertThat(connectionSettings!!.incoming).isNotNull()
|
||||
assertThat(connectionSettings.outgoing).isNotNull()
|
||||
with(connectionSettings.incoming) {
|
||||
assertThat(host).isEqualTo("imap.googlemail.com")
|
||||
assertThat(port).isEqualTo(993)
|
||||
assertThat(username).isEqualTo("test@metacode.biz")
|
||||
}
|
||||
with(connectionSettings.outgoing) {
|
||||
assertThat(host).isEqualTo("smtp.googlemail.com")
|
||||
assertThat(port).isEqualTo(465)
|
||||
assertThat(username).isEqualTo("test@metacode.biz")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pickFirstServer() {
|
||||
val settings = parser.parseSettings("""<?xml version="1.0"?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="metacode.biz">
|
||||
<domain>metacode.biz</domain>
|
||||
val input = """<?xml version="1.0"?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="metacode.biz">
|
||||
<domain>metacode.biz</domain>
|
||||
|
||||
<incomingServer type="imap">
|
||||
<hostname>imap.googlemail.com</hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
<incomingServer type="imap">
|
||||
<hostname>imap.googlemail.com</hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
|
||||
<outgoingServer type="smtp">
|
||||
<hostname>first</hostname>
|
||||
<port>465</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<addThisServer>true</addThisServer>
|
||||
</outgoingServer>
|
||||
<outgoingServer type="smtp">
|
||||
<hostname>first</hostname>
|
||||
<port>465</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<addThisServer>true</addThisServer>
|
||||
</outgoingServer>
|
||||
|
||||
<outgoingServer type="smtp">
|
||||
<hostname>second</hostname>
|
||||
<port>465</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<addThisServer>true</addThisServer>
|
||||
</outgoingServer>
|
||||
</emailProvider>
|
||||
<outgoingServer type="smtp">
|
||||
<hostname>second</hostname>
|
||||
<port>465</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<addThisServer>true</addThisServer>
|
||||
</outgoingServer>
|
||||
</emailProvider>
|
||||
</clientConfig>
|
||||
""".trimIndent().byteInputStream()
|
||||
|
||||
</clientConfig>""".byteInputStream(), "test@metacode.biz")
|
||||
val connectionSettings = parser.parseSettings(input, "test@metacode.biz")
|
||||
|
||||
assertNotNull(settings)
|
||||
assertNotNull(settings?.outgoing)
|
||||
assertNotNull(settings?.incoming)
|
||||
|
||||
assertEquals("first", settings?.outgoing?.host)
|
||||
assertEquals(465, settings?.outgoing?.port)
|
||||
assertEquals("test@metacode.biz", settings?.outgoing?.username)
|
||||
assertThat(connectionSettings).isNotNull()
|
||||
assertThat(connectionSettings!!.outgoing).isNotNull()
|
||||
with(connectionSettings.outgoing) {
|
||||
assertThat(host).isEqualTo("first")
|
||||
assertThat(port).isEqualTo(465)
|
||||
assertThat(username).isEqualTo("test@metacode.biz")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invalidResponse() {
|
||||
val settings = parser.parseSettings("""<?xml version="1.0"?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="metacode.biz">
|
||||
<domain>metacode.biz</domain>""".byteInputStream(), "test@metacode.biz")
|
||||
val input = """<?xml version="1.0"?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="metacode.biz">
|
||||
<domain>metacode.biz</domain>
|
||||
""".trimIndent().byteInputStream()
|
||||
|
||||
assertNull(settings)
|
||||
val connectionSettings = parser.parseSettings(input, "test@metacode.biz")
|
||||
|
||||
assertThat(connectionSettings).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun notCompleteConfiguration() {
|
||||
val settings = parser.parseSettings("""<?xml version="1.0"?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="metacode.biz">
|
||||
<domain>metacode.biz</domain>
|
||||
fun incompleteConfiguration() {
|
||||
val input = """<?xml version="1.0"?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="metacode.biz">
|
||||
<domain>metacode.biz</domain>
|
||||
|
||||
<incomingServer type="imap">
|
||||
<hostname>imap.googlemail.com</hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
</emailProvider>
|
||||
</clientConfig>""".byteInputStream(), "test@metacode.biz")
|
||||
<incomingServer type="imap">
|
||||
<hostname>imap.googlemail.com</hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>OAuth2</authentication>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
</emailProvider>
|
||||
</clientConfig>
|
||||
""".trimIndent().byteInputStream()
|
||||
|
||||
assertNull(settings)
|
||||
val connectionSettings = parser.parseSettings(input, "test@metacode.biz")
|
||||
|
||||
assertThat(connectionSettings).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun generatedUrls() {
|
||||
val email = "test@metacode.biz"
|
||||
val autoDiscoveryAddress = ThunderbirdAutoconfigFetcher.getAutodiscoveryAddress("test@metacode.biz")
|
||||
|
||||
val actual = ThunderbirdAutoconfigFetcher.getAutodiscoveryAddress(email)
|
||||
|
||||
val expected = "https://metacode.biz/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=test%40metacode.biz"
|
||||
|
||||
assertEquals(expected, actual)
|
||||
assertThat(autoDiscoveryAddress.toString()).isEqualTo("https://metacode.biz/" +
|
||||
".well-known/autoconfig/mail/config-v1.1.xml?emailaddress=test%40metacode.biz")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue