Repository: thunderbird/thunderbird-android (language: kotlin)

Issue:
Manual account setup ignores password
When server settings discovery doesn't return any results, the app is asking for a password and then enters the manual setup flow. 
The password entered in the first screen is currently not used by the incoming and outgoing server settings screens. However, it should be.


Discussion hints:
nan

Pull request: Use password from incoming server for outgoing server if necessary
Once #7376 is merged, when no server settings could be found, we don't ask for the password before entering the incoming server settings screen. In that case we want the password entered there to also be used in the outgoing server settings screen.

Fixes #7360

Test command: ./gradlew :feature:account:server:settings:testDebugUnitTest --tests "app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsStateMapperKtTest"

Fix patch:
diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsStateMapper.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsStateMapper.kt
index e33ff408d25..75f211e88e9 100644
--- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsStateMapper.kt
+++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsStateMapper.kt
@@ -10,17 +10,28 @@ import app.k9mail.feature.account.common.domain.input.StringInputField
 import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.State
 import com.fsck.k9.mail.ServerSettings
 
-fun AccountState.toOutgoingServerSettingsState() = outgoingServerSettings?.toOutgoingServerSettingsState()
-    ?: State(username = StringInputField(value = emailAddress ?: ""))
+fun AccountState.toOutgoingServerSettingsState(): State {
+    val password = getOutgoingServerPassword()
 
-private fun ServerSettings.toOutgoingServerSettingsState(): State {
+    return outgoingServerSettings?.toOutgoingServerSettingsState(password)
+        ?: State(
+            username = StringInputField(value = emailAddress ?: ""),
+            password = StringInputField(value = password),
+        )
+}
+
+private fun AccountState.getOutgoingServerPassword(): String {
+    return outgoingServerSettings?.password ?: incomingServerSettings?.password ?: ""
+}
+
+private fun ServerSettings.toOutgoingServerSettingsState(password: String): State {
     return State(
         server = StringInputField(value = host ?: ""),
         security = connectionSecurity.toConnectionSecurity(),
         port = NumberInputField(value = port.toLong()),
         authenticationType = authenticationType.toAuthenticationType(),
         username = StringInputField(value = username),
-        password = StringInputField(value = password ?: ""),
+        password = StringInputField(value = password),
     )
 }
 


Test patch:
diff --git a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsStateMapperKtTest.kt b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsStateMapperKtTest.kt
index 84f5a9d9cc9..57b932d914f 100644
--- a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsStateMapperKtTest.kt
+++ b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsStateMapperKtTest.kt
@@ -27,6 +27,24 @@ class OutgoingServerSettingsStateMapperKtTest {
         assertThat(result).isEqualTo(State(username = StringInputField(value = "test@example.com")))
     }
 
+    @Test
+    fun `should map to state with password from incomingServerSettings when outgoingServerSettings is null`() {
+        val accountState = AccountState(
+            emailAddress = "test@domain.example",
+            incomingServerSettings = IMAP_SERVER_SETTINGS,
+            outgoingServerSettings = null,
+        )
+
+        val result = accountState.toOutgoingServerSettingsState()
+
+        assertThat(result).isEqualTo(
+            State(
+                username = StringInputField(value = "test@domain.example"),
+                password = StringInputField(value = INCOMING_SERVER_PASSWORD),
+            ),
+        )
+    }
+
     @Test
     fun `should map from SMTP server settings to state`() {
         val accountState = AccountState(
@@ -38,6 +56,37 @@ class OutgoingServerSettingsStateMapperKtTest {
         assertThat(result).isEqualTo(OUTGOING_STATE)
     }
 
+    @Test
+    fun `should use password from incomingServerSettings when outgoingServerSettings contains no password`() {
+        val accountState = AccountState(
+            incomingServerSettings = IMAP_SERVER_SETTINGS,
+            outgoingServerSettings = SMTP_SERVER_SETTINGS.copy(password = null),
+        )
+
+        val result = accountState.toOutgoingServerSettingsState()
+
+        assertThat(result).isEqualTo(
+            OUTGOING_STATE.copy(
+                password = StringInputField(value = INCOMING_SERVER_PASSWORD),
+            ),
+        )
+    }
+
+    @Test
+    fun `should use empty password if neither incomingServerSettings nor outgoingServerSettings contain passwords`() {
+        val accountState = AccountState(
+            outgoingServerSettings = SMTP_SERVER_SETTINGS.copy(password = null),
+        )
+
+        val result = accountState.toOutgoingServerSettingsState()
+
+        assertThat(result).isEqualTo(
+            OUTGOING_STATE.copy(
+                password = StringInputField(value = ""),
+            ),
+        )
+    }
+
     @Test
     fun `should map state to server settings`() {
         val outgoingState = OUTGOING_STATE
@@ -68,5 +117,17 @@ class OutgoingServerSettingsStateMapperKtTest {
             password = "password",
             clientCertificateAlias = null,
         )
+
+        private const val INCOMING_SERVER_PASSWORD = "incoming-password"
+        private val IMAP_SERVER_SETTINGS = ServerSettings(
+            type = "imap",
+            host = "imap.domain.example",
+            port = 993,
+            connectionSecurity = MailConnectionSecurity.SSL_TLS_REQUIRED,
+            authenticationType = AuthType.PLAIN,
+            username = "user",
+            password = INCOMING_SERVER_PASSWORD,
+            clientCertificateAlias = null,
+        )
     }
 }