diff --git a/app/core/src/main/AndroidManifest.xml b/app/core/src/main/AndroidManifest.xml
index e4c26a20a16b8f63ae8e50a5ff7aa8a858c4d620..a3ae99a7bb178275aa5797fd6a10ea22a7eee73f 100644
--- a/app/core/src/main/AndroidManifest.xml
+++ b/app/core/src/main/AndroidManifest.xml
@@ -2,6 +2,12 @@
+
+
diff --git a/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt b/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt
index 9229ca256520e8bb69897b7f022fb4e189c66e56..3c2330118ea03c1c81accaa97112d0a8cca05e38 100644
--- a/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt
+++ b/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt
@@ -32,30 +32,35 @@ object OsAccountManagerUtil {
fun isSyncEnable(context: Context, email: String): Boolean {
val accountManager = AccountManager.get(context)
- val murenaAccounts = accountManager.getAccountsByType(AccountManagerConstants.EELO_ACCOUNT_TYPE)
- var syncEnable = isSyncEnable(accountManager, murenaAccounts, email)
- if (syncEnable.isAccountFound()) {
- return syncEnable.getStatus()
- }
+ var syncStatus = true
- val googleAccounts = accountManager.getAccountsByType(AccountManagerConstants.GOOGLE_ACCOUNT_TYPE)
- syncEnable = isSyncEnable(accountManager, googleAccounts, email)
- if (syncEnable.isAccountFound()) {
- return syncEnable.getStatus()
+ AccountManagerConstants.ALL_ACCOUNT_TYPES.forEach {
+ val accounts = accountManager.getAccountsByType(it)
+ val syncEnable = isSyncEnable(accountManager, accounts, email)
+ if (syncEnable.isAccountFound()) {
+ syncStatus = syncEnable.getStatus()
+ return@forEach
+ }
}
- return true
+ return syncStatus
}
private fun isSyncEnable(accountManager: AccountManager, accounts: Array, email: String): Syncable {
accounts.forEach {
try {
- val accountEmail: String = accountManager.getUserData(it, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY)
+ val accountEmail: String =
+ accountManager.getUserData(it, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY)
if (accountEmail == email) {
// if master sync disable, then account sync is disable
return if (!ContentResolver.getMasterSyncAutomatically()) {
Syncable.NOT_SYNCABLE
- } else Syncable.getSyncable(ContentResolver.getSyncAutomatically(it, AccountManagerConstants.MAIL_CONTENT_AUTHORITY))
+ } else Syncable.getSyncable(
+ ContentResolver.getSyncAutomatically(
+ it,
+ AccountManagerConstants.MAIL_CONTENT_AUTHORITY,
+ ),
+ )
}
} catch (e: Throwable) {
Timber.e(e)
@@ -78,4 +83,4 @@ object OsAccountManagerUtil {
fun isAccountFound() = this != ACCOUNT_NOT_FOUND
}
-}
\ No newline at end of file
+}
diff --git a/app/core/src/main/java/com/fsck/k9/setup/AccountManagerConstants.kt b/app/core/src/main/java/com/fsck/k9/setup/AccountManagerConstants.kt
index b70aad6478f429b13042a57ab6a054e5d46a2f52..2cb7c4bc013d9385871ce662a33f83b57a1ba800 100644
--- a/app/core/src/main/java/com/fsck/k9/setup/AccountManagerConstants.kt
+++ b/app/core/src/main/java/com/fsck/k9/setup/AccountManagerConstants.kt
@@ -19,6 +19,7 @@ package com.fsck.k9.setup
object AccountManagerConstants {
const val EELO_ACCOUNT_TYPE = "e.foundation.webdav.eelo"
const val GOOGLE_ACCOUNT_TYPE = "e.foundation.webdav.google"
+ const val YAHOO_ACCOUNT_TYPE = "e.foundation.webdav.yahoo"
const val ACCOUNT_EMAIL_ADDRESS_KEY = "email_address"
const val MAIL_CONTENT_AUTHORITY = "foundation.e.mail.provider.AppContentProvider"
const val AUTH_TOKEN_TYPE = "oauth2-access-token"
@@ -28,4 +29,15 @@ object AccountManagerConstants {
const val OPEN_APP_ACTIVITY_AFTER_AUTH = "open_app_activity_after_auth"
const val IGNORE_ACCOUNT_SETUP = "ignore_account_setup"
+
+ val OPENID_ACCOUNT_TYPES = listOf(GOOGLE_ACCOUNT_TYPE, YAHOO_ACCOUNT_TYPE)
+ val ALL_ACCOUNT_TYPES = listOf(EELO_ACCOUNT_TYPE, GOOGLE_ACCOUNT_TYPE, YAHOO_ACCOUNT_TYPE)
+
+ fun getOpenIdAccountTypeByHostName(hostname: String): String? {
+ return when(hostname) {
+ in listOf("imap.gmail.com", "imap.googlemail.com", "smtp.gmail.com", "smtp.googlemail.com") -> GOOGLE_ACCOUNT_TYPE
+ in listOf("imap.mail.yahoo.com", "smtp.mail.yahoo.com") -> YAHOO_ACCOUNT_TYPE
+ else -> null
+ }
+ }
}
diff --git a/app/core/src/main/java/com/fsck/k9/setup/EeloAccountHelper.kt b/app/core/src/main/java/com/fsck/k9/setup/EeloAccountHelper.kt
index 10b69fbe9ed9866d7b8792eeca12fa6088ee11e2..e273661fcd54f52ec9f098b28c075d10b2e50382 100644
--- a/app/core/src/main/java/com/fsck/k9/setup/EeloAccountHelper.kt
+++ b/app/core/src/main/java/com/fsck/k9/setup/EeloAccountHelper.kt
@@ -16,13 +16,13 @@
package com.fsck.k9.setup
-import android.accounts.Account as OsAccount
-import android.accounts.AccountManager as OsAccountManager
import android.content.Context
import com.fsck.k9.Account
import com.fsck.k9.mail.AuthType
import com.fsck.k9.preferences.AccountManager
import timber.log.Timber
+import android.accounts.Account as OsAccount
+import android.accounts.AccountManager as OsAccountManager
object EeloAccountHelper {
@@ -44,10 +44,28 @@ object EeloAccountHelper {
}
val osAccountManager = OsAccountManager.get(context)
- val googleAccount = retrieveGoogleAccountFromAccountManager(osAccountManager, account.email) ?: return false
+
+ var result = false
+ AccountManagerConstants.OPENID_ACCOUNT_TYPES.forEach {
+ val openIdAccount = retrieveOpenIdAccountFromAccountManager(osAccountManager, it, account.email)
+ if (openIdAccount != null) {
+ updateOAuthState(account, osAccountManager, openIdAccount, accountManager)
+ result = true
+ return@forEach
+ }
+ }
+
+ return result
+ }
+
+ private fun updateOAuthState(
+ account: Account,
+ osAccountManager: android.accounts.AccountManager,
+ googleAccount: android.accounts.Account?,
+ accountManager: AccountManager,
+ ) {
account.oAuthState = osAccountManager.getUserData(googleAccount, AccountManagerConstants.KEY_AUTH_STATE)
accountManager.saveAccount(account)
- return true
}
// If token is updated by mail, also update the accountManager
@@ -55,7 +73,7 @@ object EeloAccountHelper {
context: Context?,
account: OsAccount?,
authState: String?,
- accessToken: String?
+ accessToken: String?,
) {
if (context == null || account == null || authState == null || accessToken == null) {
Timber.w("updating account for accountManager failed, invalid param.")
@@ -67,30 +85,44 @@ object EeloAccountHelper {
accountManager.setUserData(account, AccountManagerConstants.KEY_AUTH_STATE, authState)
}
- fun retrieveGoogleAccountFromAccountManager(context: Context?, email: String?): OsAccount? {
+ fun retrieveOpenIdAccountFromAccountManager(context: Context?, email: String?): OsAccount? {
if (context == null) {
Timber.w("retrieve google accounts from accountManager failed, null context.")
return null
}
val accountManager = OsAccountManager.get(context)
- return retrieveGoogleAccountFromAccountManager(accountManager, email)
+
+ var resultAccount: OsAccount? = null
+
+ AccountManagerConstants.OPENID_ACCOUNT_TYPES.forEach {
+ resultAccount = retrieveOpenIdAccountFromAccountManager(accountManager, it, email)
+ if (resultAccount != null) {
+ return@forEach
+ }
+ }
+
+ return resultAccount
}
- private fun retrieveGoogleAccountFromAccountManager(accountManager: OsAccountManager?, email: String?): OsAccount? {
- if (accountManager == null || email == null || email.isEmpty()) {
- Timber.w("retrieve google account from accountManager failed, invalid param")
+ private fun retrieveOpenIdAccountFromAccountManager(
+ accountManager: OsAccountManager?,
+ accountType: String,
+ email: String?,
+ ): OsAccount? {
+ if (accountManager == null || email.isNullOrEmpty()) {
+ Timber.w("retrieve $accountType account from accountManager failed, invalid param")
return null
}
- val googleAccounts = accountManager.getAccountsByType(AccountManagerConstants.GOOGLE_ACCOUNT_TYPE)
- for (googleAccount in googleAccounts) {
- val emailId = accountManager.getUserData(googleAccount, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY)
+ val openIdAccounts = accountManager.getAccountsByType(accountType)
+ for (openIdAccount in openIdAccounts) {
+ val emailId = accountManager.getUserData(openIdAccount, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY)
if (email.equals(emailId, ignoreCase = true)) {
- return googleAccount
+ return openIdAccount
}
}
return null
}
-}
\ No newline at end of file
+}
diff --git a/app/k9mail/src/main/java/com/fsck/k9/backends/RealOAuth2TokenProvider.kt b/app/k9mail/src/main/java/com/fsck/k9/backends/RealOAuth2TokenProvider.kt
index be4ac7f6576cd354795a7a92b8ded77ab5084d97..ed65f485a15d297f3446ecb7dfca887b1b24fe45 100644
--- a/app/k9mail/src/main/java/com/fsck/k9/backends/RealOAuth2TokenProvider.kt
+++ b/app/k9mail/src/main/java/com/fsck/k9/backends/RealOAuth2TokenProvider.kt
@@ -31,7 +31,7 @@ class RealOAuth2TokenProvider(
?: throw AuthenticationFailedException("Login required")
}
- val accountManagerAccount = EeloAccountHelper.retrieveGoogleAccountFromAccountManager(context, email)
+ val accountManagerAccount = EeloAccountHelper.retrieveOpenIdAccountFromAccountManager(context, email)
val latch = CountDownLatch(1)
var token: String? = null
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt
index a1f9617c8019569988fd36bdac4fda6c9b5250a4..f34820adb7e16bae642c24baa0c263ccbf5f4af4 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt
@@ -20,6 +20,8 @@ import android.accounts.AccountManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
+import android.os.Build
+import androidx.annotation.RequiresApi
import com.fsck.k9.Account
import com.fsck.k9.Preferences
import com.fsck.k9.activity.setup.accountmanager.EeloAccountCreator
@@ -29,7 +31,6 @@ import com.fsck.k9.setup.AccountManagerConstants
import java.util.concurrent.Executors
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
-import timber.log.Timber
class AccountSyncReceiver : BroadcastReceiver(), KoinComponent {
@@ -39,7 +40,6 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent {
private const val ACCOUNT_CREATION_ACTION = "$ACTION_PREFIX.create"
private const val ACCOUNT_REMOVAL_ACTION = "android.accounts.action.ACCOUNT_REMOVED"
- private val ACCOUNT_TYPES = listOf(AccountManagerConstants.EELO_ACCOUNT_TYPE, AccountManagerConstants.GOOGLE_ACCOUNT_TYPE)
}
private val pushController: PushController by inject()
@@ -47,6 +47,7 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent {
private val accountRemover: BackgroundAccountRemover by inject()
private val jobManager: K9JobManager by inject()
+ @RequiresApi(Build.VERSION_CODES.N)
override fun onReceive(context: Context?, intent: Intent?) {
if (intent == null) {
return
@@ -58,6 +59,7 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent {
}
}
+ @RequiresApi(Build.VERSION_CODES.N)
private fun createNewAccount(context: Context?) {
pushController.init()
context?.let {
@@ -81,7 +83,7 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent {
private fun getAccount(intent: Intent) : Account? {
val accountType = intent.extras?.getString(AccountManager.KEY_ACCOUNT_TYPE)
- if (!ACCOUNT_TYPES.contains(accountType)) {
+ if (!AccountManagerConstants.ALL_ACCOUNT_TYPES.contains(accountType)) {
return null
}
@@ -95,4 +97,4 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent {
return null
}
-}
\ No newline at end of file
+}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt
index 5d528da898ff2b5794c037b7dcb6c781df04aa0e..97a18c9241274ba072694663c88049893a0edfdb 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt
@@ -137,6 +137,7 @@ class AccountSetupBasics : K9Activity() {
advancedOptionsContainer.isVisible = false
nextButton.setOnClickListener { attemptAutoSetupUsingOnlyEmailAddress() }
}
+
UiState.PASSWORD_FLOW -> {
passwordLayout.isVisible = true
advancedOptionsContainer.isVisible = true
@@ -211,8 +212,7 @@ class AccountSetupBasics : K9Activity() {
}
private fun startOAuthFlow(connectionSettings: ConnectionSettings) {
- if (oAuthConfigurationProvider.isGoogle(connectionSettings.incoming.host!!)) {
- startGoogleOAuthFlow()
+ if (handleOpenIdAuthFlow(connectionSettings.incoming.host!!)) {
return
}
@@ -222,12 +222,19 @@ class AccountSetupBasics : K9Activity() {
startActivityForResult(intent, REQUEST_CODE_OAUTH)
}
- private fun startGoogleOAuthFlow() {
+ private fun handleOpenIdAuthFlow(hostname: String): Boolean {
+ val accountType = AccountManagerConstants.getOpenIdAccountTypeByHostName(hostname) ?: return false
+
+ startOpenIdOAuthFlow(accountType)
+ return true
+ }
+
+ private fun startOpenIdOAuthFlow(accountType: String) {
val osAccountManager = AccountManager.get(this)
val options = Bundle()
options.putString(AccountManagerConstants.OPEN_APP_PACKAGE_AFTER_AUTH, packageName)
options.putString(AccountManagerConstants.OPEN_APP_ACTIVITY_AFTER_AUTH, MessageList::class.java.name)
- osAccountManager.addAccount(AccountManagerConstants.GOOGLE_ACCOUNT_TYPE, null, null, options, this, null, null)
+ osAccountManager.addAccount(accountType, null, null, options, this, null, null)
}
private fun startPasswordFlow() {
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 7d550abfcab54a43c277d9c782bf78a82f0bf588..4cc9cd0077e21b0713baf522f499337af551c1f0 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
@@ -65,7 +65,8 @@ public class EeloAccountCreator {
deleteIncompleteAccounts(accounts, accountRemover);
loadEeloAccounts(context, accounts, accountManager, jobManager);
- loadGoogleAccounts(context, accounts, accountManager, jobManager);
+
+ AccountManagerConstants.INSTANCE.getOPENID_ACCOUNT_TYPES().forEach(accountType -> loadOpenIdAccounts(context, accountType, accounts, accountManager, jobManager));
} catch (SecurityException e) {
Timber.e(e, "Failed to load accounts from accountManager because of security violation");
}
@@ -89,18 +90,18 @@ public class EeloAccountCreator {
}
@RequiresApi(api = VERSION_CODES.N)
- private static void loadGoogleAccounts(@NonNull Context context, List accounts,
+ private static void loadOpenIdAccounts(@NonNull Context context, @NonNull String accountType, List accounts,
@NonNull AccountManager accountManager, @NonNull K9JobManager jobManager) {
- android.accounts.Account[] googleAccounts =
- accountManager.getAccountsByType(AccountManagerConstants.GOOGLE_ACCOUNT_TYPE);
- for (android.accounts.Account googleAccount : googleAccounts) {
+ android.accounts.Account[] openIdAccounts =
+ accountManager.getAccountsByType(accountType);
+ for (android.accounts.Account openIdAccount : openIdAccounts) {
String emailId =
- accountManager.getUserData(googleAccount, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY);
+ accountManager.getUserData(openIdAccount, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY);
if (isInvalidEmail(emailId)) {
continue;
}
- if (!isSyncable(googleAccount)) {
+ if (!isSyncable(openIdAccount)) {
continue;
}
@@ -110,7 +111,7 @@ public class EeloAccountCreator {
.findAny();
if (!existenceAccount.isPresent()) {
- String authState = accountManager.getUserData(googleAccount, AccountManagerConstants.KEY_AUTH_STATE);
+ String authState = accountManager.getUserData(openIdAccount, AccountManagerConstants.KEY_AUTH_STATE);
createAccount(context, emailId, "", authState);
continue;
}