Convert AccountSetupCheckSettings to Kotlin

This commit is contained in:
cketti 2022-05-21 19:40:54 +02:00
parent af2d031385
commit f71615f6aa
2 changed files with 364 additions and 428 deletions

View file

@ -256,14 +256,14 @@ class AccountSetupBasics : K9Activity() {
}
if (resultCode == RESULT_OK) {
val account = this.account ?: error("Account instance missing")
if (!checkedIncoming) {
// We've successfully checked incoming. Now check outgoing.
checkedIncoming = true
AccountSetupCheckSettings.actionCheckSettings(this, account, CheckDirection.OUTGOING)
} else {
// We've successfully checked outgoing as well.
val account = this.account ?: error("Account instance missing")
preferences.saveAccount(account)
Core.setServicesEnabled(applicationContext)

View file

@ -1,408 +1,336 @@
package com.fsck.k9.activity.setup
package com.fsck.k9.activity.setup;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentTransaction;
import com.fsck.k9.Account;
import com.fsck.k9.DI;
import com.fsck.k9.LocalKeyStoreManager;
import com.fsck.k9.Preferences;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.fragment.ConfirmationDialogFragment;
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.CertificateValidationException;
import com.fsck.k9.mail.MailServerDirection;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.filter.Hex;
import com.fsck.k9.preferences.Protocols;
import com.fsck.k9.ui.R;
import com.fsck.k9.ui.base.K9Activity;
import timber.log.Timber;
import android.app.Activity
import android.app.AlertDialog
import android.content.Intent
import android.os.AsyncTask
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.ProgressBar
import android.widget.TextView
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.commit
import com.fsck.k9.Account
import com.fsck.k9.LocalKeyStoreManager
import com.fsck.k9.Preferences
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.fragment.ConfirmationDialogFragment
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener
import com.fsck.k9.mail.AuthenticationFailedException
import com.fsck.k9.mail.CertificateValidationException
import com.fsck.k9.mail.MailServerDirection
import com.fsck.k9.mail.filter.Hex
import com.fsck.k9.preferences.Protocols
import com.fsck.k9.ui.R
import com.fsck.k9.ui.base.K9Activity
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.security.cert.CertificateEncodingException
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.Locale
import org.koin.android.ext.android.inject
import timber.log.Timber
/**
* Checks the given settings to make sure that they can be used to send and
* receive mail.
*
* XXX NOTE: The manifest for this app has it ignore config changes, because
* it doesn't correctly deal with restarting while its thread is running.
* Checks the given settings to make sure that they can be used to send and receive mail.
*
* XXX NOTE: The manifest for this app has it ignore config changes, because it doesn't correctly deal with restarting
* while its thread is running.
*/
public class AccountSetupCheckSettings extends K9Activity implements OnClickListener,
ConfirmationDialogFragmentListener{
class AccountSetupCheckSettings : K9Activity(), ConfirmationDialogFragmentListener {
private val messagingController: MessagingController by inject()
private val preferences: Preferences by inject()
private val localKeyStoreManager: LocalKeyStoreManager by inject()
public static final int ACTIVITY_REQUEST_CODE = 1;
private val handler = Handler(Looper.myLooper()!!)
private static final String EXTRA_ACCOUNT = "account";
private lateinit var progressBar: ProgressBar
private lateinit var messageView: TextView
private static final String EXTRA_CHECK_DIRECTION ="checkDirection";
private lateinit var account: Account
private lateinit var direction: CheckDirection
public enum CheckDirection {
INCOMING,
OUTGOING;
@Volatile
private var canceled = false
public MailServerDirection toMailServerDirection() {
switch (this) {
case INCOMING: return MailServerDirection.INCOMING;
case OUTGOING: return MailServerDirection.OUTGOING;
}
@Volatile
private var destroyed = false
throw new AssertionError("Unknown value: " + this);
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setLayout(R.layout.account_setup_check_settings)
messageView = findViewById(R.id.message)
progressBar = findViewById(R.id.progress)
findViewById<View>(R.id.cancel).setOnClickListener { onCancel() }
setMessage(R.string.account_setup_check_settings_retr_info_msg)
progressBar.isIndeterminate = true
val accountUuid = intent.getStringExtra(EXTRA_ACCOUNT) ?: error("Missing account UUID")
account = preferences.getAccount(accountUuid) ?: error("Could not find account")
direction = intent.getSerializableExtra(EXTRA_CHECK_DIRECTION) as CheckDirection?
?: error("Missing CheckDirection")
CheckAccountTask(account).execute(direction)
}
private final MessagingController messagingController = DI.get(MessagingController.class);
private fun handleCertificateValidationException(exception: CertificateValidationException) {
Timber.e(exception, "Error while testing settings")
private Handler mHandler = new Handler();
val chain = exception.certChain
private ProgressBar mProgressBar;
private TextView mMessageView;
private Account mAccount;
private CheckDirection mDirection;
private boolean mCanceled;
private boolean mDestroyed;
public static void actionCheckSettings(Activity context, Account account,
CheckDirection direction) {
Intent i = new Intent(context, AccountSetupCheckSettings.class);
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
i.putExtra(EXTRA_CHECK_DIRECTION, direction);
context.startActivityForResult(i, ACTIVITY_REQUEST_CODE);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setLayout(R.layout.account_setup_check_settings);
mMessageView = findViewById(R.id.message);
mProgressBar = findViewById(R.id.progress);
findViewById(R.id.cancel).setOnClickListener(this);
setMessage(R.string.account_setup_check_settings_retr_info_msg);
mProgressBar.setIndeterminate(true);
String accountUuid = getIntent().getStringExtra(EXTRA_ACCOUNT);
mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
mDirection = (CheckDirection) getIntent().getSerializableExtra(EXTRA_CHECK_DIRECTION);
new CheckAccountTask(mAccount).execute(mDirection);
}
private void handleCertificateValidationException(CertificateValidationException cve) {
Timber.e(cve, "Error while testing settings");
X509Certificate[] chain = cve.getCertChain();
// Avoid NullPointerException in acceptKeyDialog()
if (chain != null) {
acceptKeyDialog(
R.string.account_setup_failed_dlg_certificate_message_fmt,
cve);
R.string.account_setup_failed_dlg_certificate_message_fmt,
exception
)
} else {
showErrorDialog(
R.string.account_setup_failed_dlg_server_message_fmt,
errorMessageForCertificateException(cve));
R.string.account_setup_failed_dlg_server_message_fmt,
errorMessageForCertificateException(exception)!!
)
}
}
override fun onDestroy() {
super.onDestroy()
@Override
public void onDestroy() {
super.onDestroy();
mDestroyed = true;
mCanceled = true;
destroyed = true
canceled = true
}
private void setMessage(final int resId) {
mMessageView.setText(getString(resId));
private fun setMessage(resId: Int) {
messageView.text = getString(resId)
}
private void acceptKeyDialog(final int msgResId, final CertificateValidationException ex) {
mHandler.post(new Runnable() {
public void run() {
if (mDestroyed) {
return;
}
String exMessage = "Unknown Error";
if (ex != null) {
if (ex.getCause() != null) {
if (ex.getCause().getCause() != null) {
exMessage = ex.getCause().getCause().getMessage();
} else {
exMessage = ex.getCause().getMessage();
}
} else {
exMessage = ex.getMessage();
}
}
mProgressBar.setIndeterminate(false);
StringBuilder chainInfo = new StringBuilder(200);
final X509Certificate[] chain = ex.getCertChain();
// We already know chain != null (tested before calling this method)
for (int i = 0; i < chain.length; i++) {
// display certificate chain information
//TODO: localize this strings
chainInfo.append("Certificate chain[").append(i).append("]:\n");
chainInfo.append("Subject: ").append(chain[i].getSubjectDN().toString()).append("\n");
// display SubjectAltNames too
// (the user may be mislead into mistrusting a certificate
// by a subjectDN not matching the server even though a
// SubjectAltName matches)
try {
final Collection < List<? >> subjectAlternativeNames = chain[i].getSubjectAlternativeNames();
if (subjectAlternativeNames != null) {
// The list of SubjectAltNames may be very long
//TODO: localize this string
StringBuilder altNamesText = new StringBuilder();
altNamesText.append("Subject has ").append(subjectAlternativeNames.size()).append(" alternative names\n");
// we need these for matching
String incomingServerHost = mAccount.getIncomingServerSettings().host;
String outgoingServerHost = mAccount.getOutgoingServerSettings().host;
for (List<?> subjectAlternativeName : subjectAlternativeNames) {
Integer type = (Integer)subjectAlternativeName.get(0);
Object value = subjectAlternativeName.get(1);
String name;
switch (type) {
case 0:
Timber.w("SubjectAltName of type OtherName not supported.");
continue;
case 1: // RFC822Name
name = (String)value;
break;
case 2: // DNSName
name = (String)value;
break;
case 3:
Timber.w("unsupported SubjectAltName of type x400Address");
continue;
case 4:
Timber.w("unsupported SubjectAltName of type directoryName");
continue;
case 5:
Timber.w("unsupported SubjectAltName of type ediPartyName");
continue;
case 6: // Uri
name = (String)value;
break;
case 7: // ip-address
name = (String)value;
break;
default:
Timber.w("unsupported SubjectAltName of unknown type");
continue;
}
// if some of the SubjectAltNames match the store or transport -host,
// display them
if (name.equalsIgnoreCase(incomingServerHost) || name.equalsIgnoreCase(outgoingServerHost)) {
//TODO: localize this string
altNamesText.append("Subject(alt): ").append(name).append(",...\n");
} else if (name.startsWith("*.") && (
incomingServerHost.endsWith(name.substring(2)) ||
outgoingServerHost.endsWith(name.substring(2)))) {
//TODO: localize this string
altNamesText.append("Subject(alt): ").append(name).append(",...\n");
}
}
chainInfo.append(altNamesText);
}
} catch (Exception e1) {
// don't fail just because of subjectAltNames
Timber.w(e1, "cannot display SubjectAltNames in dialog");
}
chainInfo.append("Issuer: ").append(chain[i].getIssuerDN().toString()).append("\n");
String[] digestAlgorithms = new String[] {"SHA-1", "SHA-256", "SHA-512"};
for (String algorithm : digestAlgorithms) {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
Timber.e(e, "Error while initializing MessageDigest (" + algorithm + ")");
}
if (digest != null) {
digest.reset();
try {
String hash = Hex.encodeHex(digest.digest(chain[i].getEncoded()));
chainInfo.append("Fingerprint ("+ algorithm +"): ").append("\n").append(hash).append("\n");
} catch (CertificateEncodingException e) {
Timber.e(e, "Error while encoding certificate");
}
}
}
}
// TODO: refactor with DialogFragment.
// This is difficult because we need to pass through chain[0] for onClick()
new AlertDialog.Builder(AccountSetupCheckSettings.this)
.setTitle(getString(R.string.account_setup_failed_dlg_invalid_certificate_title))
//.setMessage(getString(R.string.account_setup_failed_dlg_invalid_certificate)
.setMessage(getString(msgResId, exMessage)
+ " " + chainInfo.toString()
)
.setCancelable(true)
.setPositiveButton(
getString(R.string.account_setup_failed_dlg_invalid_certificate_accept),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
acceptCertificate(chain[0]);
}
})
.setNegativeButton(
getString(R.string.account_setup_failed_dlg_invalid_certificate_reject),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.show();
private fun acceptKeyDialog(msgResId: Int, exception: CertificateValidationException) {
handler.post {
if (destroyed) {
return@post
}
});
val errorMessage = exception.cause?.cause?.message ?: exception.cause?.message ?: exception.message
progressBar.isIndeterminate = false
val chainInfo = StringBuilder()
val chain = exception.certChain
// We already know chain != null (tested before calling this method)
for (i in chain.indices) {
// display certificate chain information
// TODO: localize this strings
chainInfo.append("Certificate chain[").append(i).append("]:\n")
chainInfo.append("Subject: ").append(chain[i].subjectDN.toString()).append("\n")
// display SubjectAltNames too
// (the user may be mislead into mistrusting a certificate
// by a subjectDN not matching the server even though a
// SubjectAltName matches)
try {
val subjectAlternativeNames = chain[i].subjectAlternativeNames
if (subjectAlternativeNames != null) {
// TODO: localize this string
val altNamesText = StringBuilder()
altNamesText.append("Subject has ")
.append(subjectAlternativeNames.size)
.append(" alternative names\n")
// we need these for matching
val incomingServerHost = account.incomingServerSettings.host!!
val outgoingServerHost = account.outgoingServerSettings.host!!
for (subjectAlternativeName in subjectAlternativeNames) {
val type = subjectAlternativeName[0] as Int
val value: Any? = subjectAlternativeName[1]
val name: String = when (type) {
0 -> {
Timber.w("SubjectAltName of type OtherName not supported.")
continue
}
1 -> value as String
2 -> value as String
3 -> {
Timber.w("unsupported SubjectAltName of type x400Address")
continue
}
4 -> {
Timber.w("unsupported SubjectAltName of type directoryName")
continue
}
5 -> {
Timber.w("unsupported SubjectAltName of type ediPartyName")
continue
}
6 -> value as String
7 -> value as String
else -> {
Timber.w("unsupported SubjectAltName of unknown type")
continue
}
}
// if some of the SubjectAltNames match the store or transport -host, display them
if (name.equals(incomingServerHost, ignoreCase = true) ||
name.equals(outgoingServerHost, ignoreCase = true)
) {
// TODO: localize this string
altNamesText.append("Subject(alt): ").append(name).append(",...\n")
} else if (name.startsWith("*.") &&
(
incomingServerHost.endsWith(name.substring(2)) ||
outgoingServerHost.endsWith(name.substring(2))
)
) {
// TODO: localize this string
altNamesText.append("Subject(alt): ").append(name).append(",...\n")
}
}
chainInfo.append(altNamesText)
}
} catch (e: Exception) {
// don't fail just because of subjectAltNames
Timber.w(e, "cannot display SubjectAltNames in dialog")
}
chainInfo.append("Issuer: ").append(chain[i].issuerDN.toString()).append("\n")
for (algorithm in arrayOf("SHA-1", "SHA-256", "SHA-512")) {
val digest = try {
MessageDigest.getInstance(algorithm)
} catch (e: NoSuchAlgorithmException) {
Timber.e(e, "Error while initializing MessageDigest ($algorithm)")
null
}
if (digest != null) {
digest.reset()
try {
val hash = Hex.encodeHex(digest.digest(chain[i].encoded))
chainInfo.append("Fingerprint ($algorithm): ").append("\n").append(hash).append("\n")
} catch (e: CertificateEncodingException) {
Timber.e(e, "Error while encoding certificate")
}
}
}
}
// TODO: refactor with DialogFragment.
// This is difficult because we need to pass through chain[0] for onClick()
AlertDialog.Builder(this@AccountSetupCheckSettings)
.setTitle(getString(R.string.account_setup_failed_dlg_invalid_certificate_title))
.setMessage(getString(msgResId, errorMessage) + " " + chainInfo.toString())
.setCancelable(true)
.setPositiveButton(R.string.account_setup_failed_dlg_invalid_certificate_accept) { _, _ ->
acceptCertificate(chain[0])
}
.setNegativeButton(R.string.account_setup_failed_dlg_invalid_certificate_reject) { _, _ ->
finish()
}
.show()
}
}
/**
* Permanently accepts a certificate for the INCOMING or OUTGOING direction
* by adding it to the local key store.
*
* @param certificate
* Permanently accepts a certificate for the INCOMING or OUTGOING direction by adding it to the local key store.
*/
private void acceptCertificate(X509Certificate certificate) {
private fun acceptCertificate(certificate: X509Certificate) {
try {
DI.get(LocalKeyStoreManager.class).addCertificate(mAccount, mDirection.toMailServerDirection(), certificate);
} catch (CertificateException e) {
showErrorDialog(
R.string.account_setup_failed_dlg_certificate_message_fmt,
e.getMessage() == null ? "" : e.getMessage());
localKeyStoreManager.addCertificate(account, direction.toMailServerDirection(), certificate)
} catch (e: CertificateException) {
showErrorDialog(R.string.account_setup_failed_dlg_certificate_message_fmt, e.message.orEmpty())
}
AccountSetupCheckSettings.actionCheckSettings(AccountSetupCheckSettings.this, mAccount,
mDirection);
actionCheckSettings(this@AccountSetupCheckSettings, account, direction)
}
@Override
public void onActivityResult(int reqCode, int resCode, Intent data) {
override fun onActivityResult(reqCode: Int, resCode: Int, data: Intent?) {
if (reqCode == ACTIVITY_REQUEST_CODE) {
setResult(resCode);
finish();
setResult(resCode)
finish()
} else {
super.onActivityResult(reqCode, resCode, data);
super.onActivityResult(reqCode, resCode, data)
}
}
private void onCancel() {
mCanceled = true;
setMessage(R.string.account_setup_check_settings_canceling_msg);
setResult(RESULT_CANCELED);
finish();
private fun onCancel() {
canceled = true
setMessage(R.string.account_setup_check_settings_canceling_msg)
setResult(RESULT_CANCELED)
finish()
}
public void onClick(View v) {
if (v.getId() == R.id.cancel) {
onCancel();
private fun showErrorDialog(msgResId: Int, vararg args: Any) {
handler.post {
showDialogFragment(R.id.dialog_account_setup_error, getString(msgResId, *args))
}
}
private void showErrorDialog(final int msgResId, final Object... args) {
mHandler.post(new Runnable() {
public void run() {
showDialogFragment(R.id.dialog_account_setup_error, getString(msgResId, args));
}
});
}
private fun showDialogFragment(dialogId: Int, customMessage: String) {
if (destroyed) return
private void showDialogFragment(int dialogId, String customMessage) {
if (mDestroyed) {
return;
}
mProgressBar.setIndeterminate(false);
progressBar.isIndeterminate = false
DialogFragment fragment;
if (dialogId == R.id.dialog_account_setup_error) {
fragment = ConfirmationDialogFragment.newInstance(dialogId,
getString(R.string.account_setup_failed_dlg_title),
customMessage,
getString(R.string.account_setup_failed_dlg_edit_details_action),
getString(R.string.account_setup_failed_dlg_continue_action)
);
val fragment: DialogFragment = if (dialogId == R.id.dialog_account_setup_error) {
ConfirmationDialogFragment.newInstance(
dialogId,
getString(R.string.account_setup_failed_dlg_title),
customMessage,
getString(R.string.account_setup_failed_dlg_edit_details_action),
getString(R.string.account_setup_failed_dlg_continue_action)
)
} else {
throw new RuntimeException("Called showDialog(int) with unknown dialog id.");
throw RuntimeException("Called showDialog(int) with unknown dialog id.")
}
FragmentTransaction ta = getSupportFragmentManager().beginTransaction();
ta.add(fragment, getDialogTag(dialogId));
ta.commitAllowingStateLoss();
// TODO: commitAllowingStateLoss() is used to prevent https://code.google.com/p/android/issues/detail?id=23761
// but is a bad...
//fragment.show(ta, getDialogTag(dialogId));
}
private String getDialogTag(int dialogId) {
return String.format(Locale.US, "dialog-%d", dialogId);
}
@Override
public void doPositiveClick(int dialogId) {
if (dialogId == R.id.dialog_account_setup_error) {
finish();
supportFragmentManager.commit(allowStateLoss = true) {
add(fragment, getDialogTag(dialogId))
}
}
@Override
public void doNegativeClick(int dialogId) {
private fun getDialogTag(dialogId: Int): String {
return String.format(Locale.US, "dialog-%d", dialogId)
}
override fun doPositiveClick(dialogId: Int) {
if (dialogId == R.id.dialog_account_setup_error) {
mCanceled = false;
setResult(RESULT_OK);
finish();
finish()
}
}
@Override
public void dialogCancelled(int dialogId) {
// nothing to do here...
override fun doNegativeClick(dialogId: Int) {
if (dialogId == R.id.dialog_account_setup_error) {
canceled = false
setResult(RESULT_OK)
finish()
}
}
private String errorMessageForCertificateException(CertificateValidationException e) {
switch (e.getReason()) {
case Expired: return getString(R.string.client_certificate_expired, e.getAlias(), e.getMessage());
case MissingCapability: return getString(R.string.auth_external_error);
case RetrievalFailure: return getString(R.string.client_certificate_retrieval_failure, e.getAlias());
case UseMessage: return e.getMessage();
case Unknown:
default: return "";
override fun dialogCancelled(dialogId: Int) = Unit
private fun errorMessageForCertificateException(e: CertificateValidationException): String? {
return when (e.reason) {
CertificateValidationException.Reason.Expired -> {
getString(R.string.client_certificate_expired, e.alias, e.message)
}
CertificateValidationException.Reason.MissingCapability -> {
getString(R.string.auth_external_error)
}
CertificateValidationException.Reason.RetrievalFailure -> {
getString(R.string.client_certificate_retrieval_failure, e.alias)
}
CertificateValidationException.Reason.UseMessage -> {
e.message
}
else -> {
""
}
}
}
@ -410,117 +338,125 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
* FIXME: Don't use an AsyncTask to perform network operations.
* See also discussion in https://github.com/k9mail/k-9/pull/560
*/
private class CheckAccountTask extends AsyncTask<CheckDirection, Integer, Void> {
private final Account account;
private CheckAccountTask(Account account) {
this.account = account;
}
@Override
protected Void doInBackground(CheckDirection... params) {
final CheckDirection direction = params[0];
private inner class CheckAccountTask(private val account: Account) : AsyncTask<CheckDirection, Int, Unit>() {
override fun doInBackground(vararg params: CheckDirection) {
val direction = params[0]
try {
/*
* This task could be interrupted at any point, but network operations can block,
* so relying on InterruptedException is not enough. Instead, check after
* each potentially long-running operation.
*/
if (cancelled()) {
return null;
if (isCanceled()) {
return
}
clearCertificateErrorNotifications(direction);
clearCertificateErrorNotifications(direction)
checkServerSettings(direction);
checkServerSettings(direction)
if (cancelled()) {
return null;
if (isCanceled()) {
return
}
setResult(RESULT_OK);
finish();
} catch (AuthenticationFailedException afe) {
Timber.e(afe, "Error while testing settings");
showErrorDialog(
R.string.account_setup_failed_dlg_auth_message_fmt,
afe.getMessage() == null ? "" : afe.getMessage());
} catch (CertificateValidationException cve) {
handleCertificateValidationException(cve);
} catch (Exception e) {
Timber.e(e, "Error while testing settings");
String message = e.getMessage() == null ? "" : e.getMessage();
showErrorDialog(R.string.account_setup_failed_dlg_server_message_fmt, message);
}
return null;
}
private void clearCertificateErrorNotifications(CheckDirection direction) {
final MessagingController ctrl = MessagingController.getInstance(getApplication());
boolean incoming = (direction == CheckDirection.INCOMING);
ctrl.clearCertificateErrorNotifications(account, incoming);
}
private boolean cancelled() {
if (mDestroyed) {
return true;
}
if (mCanceled) {
finish();
return true;
}
return false;
}
private void checkServerSettings(CheckDirection direction) throws MessagingException {
switch (direction) {
case INCOMING: {
checkIncoming();
break;
}
case OUTGOING: {
checkOutgoing();
break;
}
setResult(RESULT_OK)
finish()
} catch (e: AuthenticationFailedException) {
Timber.e(e, "Error while testing settings")
showErrorDialog(R.string.account_setup_failed_dlg_auth_message_fmt, e.message.orEmpty())
} catch (e: CertificateValidationException) {
handleCertificateValidationException(e)
} catch (e: Exception) {
Timber.e(e, "Error while testing settings")
showErrorDialog(R.string.account_setup_failed_dlg_server_message_fmt, e.message.orEmpty())
}
}
private void checkOutgoing() throws MessagingException {
if (!isWebDavAccount()) {
publishProgress(R.string.account_setup_check_settings_check_outgoing_msg);
}
messagingController.checkOutgoingServerSettings(account);
private fun clearCertificateErrorNotifications(direction: CheckDirection) {
val incoming = direction == CheckDirection.INCOMING
messagingController.clearCertificateErrorNotifications(account, incoming)
}
private void checkIncoming() throws MessagingException {
if (isWebDavAccount()) {
publishProgress(R.string.account_setup_check_settings_authenticate);
private fun isCanceled(): Boolean {
if (destroyed) return true
if (canceled) {
finish()
return true
}
return false
}
private fun checkServerSettings(direction: CheckDirection) {
when (direction) {
CheckDirection.INCOMING -> checkIncoming()
CheckDirection.OUTGOING -> checkOutgoing()
}
}
private fun checkOutgoing() {
if (!isWebDavAccount) {
publishProgress(R.string.account_setup_check_settings_check_outgoing_msg)
}
messagingController.checkOutgoingServerSettings(account)
}
private fun checkIncoming() {
if (isWebDavAccount) {
publishProgress(R.string.account_setup_check_settings_authenticate)
} else {
publishProgress(R.string.account_setup_check_settings_check_incoming_msg);
publishProgress(R.string.account_setup_check_settings_check_incoming_msg)
}
messagingController.checkIncomingServerSettings(account);
messagingController.checkIncomingServerSettings(account)
if (isWebDavAccount()) {
publishProgress(R.string.account_setup_check_settings_fetch);
if (isWebDavAccount) {
publishProgress(R.string.account_setup_check_settings_fetch)
}
messagingController.refreshFolderListSynchronous(account);
Long inboxFolderId = account.getInboxFolderId();
messagingController.refreshFolderListSynchronous(account)
val inboxFolderId = account.inboxFolderId
if (inboxFolderId != null) {
messagingController.synchronizeMailbox(account, inboxFolderId, false, null);
messagingController.synchronizeMailbox(account, inboxFolderId, false, null)
}
}
private boolean isWebDavAccount() {
return account.getIncomingServerSettings().type.equals(Protocols.WEBDAV);
}
private val isWebDavAccount: Boolean
get() = account.incomingServerSettings.type == Protocols.WEBDAV
@Override
protected void onProgressUpdate(Integer... values) {
setMessage(values[0]);
override fun onProgressUpdate(vararg values: Int?) {
setMessage(values[0]!!)
}
}
enum class CheckDirection {
INCOMING, OUTGOING;
fun toMailServerDirection(): MailServerDirection {
return when (this) {
INCOMING -> MailServerDirection.INCOMING
OUTGOING -> MailServerDirection.OUTGOING
}
}
}
companion object {
const val ACTIVITY_REQUEST_CODE = 1
private const val EXTRA_ACCOUNT = "account"
private const val EXTRA_CHECK_DIRECTION = "checkDirection"
@JvmStatic
fun actionCheckSettings(context: Activity, account: Account, direction: CheckDirection) {
val intent = Intent(context, AccountSetupCheckSettings::class.java).apply {
putExtra(EXTRA_ACCOUNT, account.uuid)
putExtra(EXTRA_CHECK_DIRECTION, direction)
}
context.startActivityForResult(intent, ACTIVITY_REQUEST_CODE)
}
}
}