mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-14 21:45:14 -05:00
b51bce6ebf
Fixes Issue 1577 Issue 1551: Some IMAP servers send untagged EXPUNGEs to IDLEing clients without ever haven't sent an untagged FETCH. The untagged EXPUNGEs are harder to deal with because they don't have a UID. So, if the user has elected to have the IDLE connection start with a poll, we can maintain a map of message sequence numbers to UIDs that we can use to figure out which message to delete. To mitigate the risk of the map falling out of date, we do a UID SEARCH UID before removing the local copy of the message, just to make sure the message is really gone from the server. If we detect an error, do another poll to resync the map. Issue 1577: Restore the removal of notifications for an account when the account's unread message count goes to 0.
353 lines
12 KiB
Java
353 lines
12 KiB
Java
|
|
package com.fsck.k9.activity.setup;
|
|
|
|
import android.app.Activity;
|
|
import android.app.AlertDialog;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.Process;
|
|
import android.util.Log;
|
|
import android.view.View;
|
|
import android.view.View.OnClickListener;
|
|
import android.widget.Button;
|
|
import android.widget.ProgressBar;
|
|
import android.widget.TextView;
|
|
import com.fsck.k9.*;
|
|
import com.fsck.k9.mail.AuthenticationFailedException;
|
|
import com.fsck.k9.mail.CertificateValidationException;
|
|
import com.fsck.k9.mail.Store;
|
|
import com.fsck.k9.mail.Transport;
|
|
import com.fsck.k9.mail.store.TrustManagerFactory;
|
|
import java.security.cert.CertificateException;
|
|
import java.security.cert.X509Certificate;
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
|
|
public static final int ACTIVITY_REQUEST_CODE = 1;
|
|
|
|
private static final String EXTRA_ACCOUNT = "account";
|
|
|
|
private static final String EXTRA_CHECK_INCOMING = "checkIncoming";
|
|
|
|
private static final String EXTRA_CHECK_OUTGOING = "checkOutgoing";
|
|
|
|
private Handler mHandler = new Handler();
|
|
|
|
private ProgressBar mProgressBar;
|
|
|
|
private TextView mMessageView;
|
|
|
|
private Account mAccount;
|
|
|
|
private boolean mCheckIncoming;
|
|
|
|
private boolean mCheckOutgoing;
|
|
|
|
private boolean mCanceled;
|
|
|
|
private boolean mDestroyed;
|
|
|
|
public static void actionCheckSettings(Activity context, Account account,
|
|
boolean checkIncoming, boolean checkOutgoing)
|
|
{
|
|
Intent i = new Intent(context, AccountSetupCheckSettings.class);
|
|
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
|
i.putExtra(EXTRA_CHECK_INCOMING, checkIncoming);
|
|
i.putExtra(EXTRA_CHECK_OUTGOING, checkOutgoing);
|
|
context.startActivityForResult(i, ACTIVITY_REQUEST_CODE);
|
|
}
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState)
|
|
{
|
|
super.onCreate(savedInstanceState);
|
|
setContentView(R.layout.account_setup_check_settings);
|
|
mMessageView = (TextView)findViewById(R.id.message);
|
|
mProgressBar = (ProgressBar)findViewById(R.id.progress);
|
|
((Button)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);
|
|
mCheckIncoming = (boolean)getIntent().getBooleanExtra(EXTRA_CHECK_INCOMING, false);
|
|
mCheckOutgoing = (boolean)getIntent().getBooleanExtra(EXTRA_CHECK_OUTGOING, false);
|
|
|
|
new Thread()
|
|
{
|
|
@Override
|
|
public void run()
|
|
{
|
|
Store store = null;
|
|
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
|
try
|
|
{
|
|
if (mDestroyed)
|
|
{
|
|
return;
|
|
}
|
|
if (mCanceled)
|
|
{
|
|
finish();
|
|
return;
|
|
}
|
|
if (mCheckIncoming)
|
|
{
|
|
setMessage(R.string.account_setup_check_settings_check_incoming_msg);
|
|
store = mAccount.getRemoteStore();
|
|
store.checkSettings();
|
|
|
|
MessagingController.getInstance(getApplication()).listFolders(mAccount, true, null);
|
|
MessagingController.getInstance(getApplication()).synchronizeMailbox(mAccount, K9.INBOX , null, null);
|
|
|
|
}
|
|
if (mDestroyed)
|
|
{
|
|
return;
|
|
}
|
|
if (mCanceled)
|
|
{
|
|
finish();
|
|
return;
|
|
}
|
|
if (mCheckOutgoing)
|
|
{
|
|
setMessage(R.string.account_setup_check_settings_check_outgoing_msg);
|
|
Transport transport = Transport.getInstance(mAccount);
|
|
transport.close();
|
|
transport.open();
|
|
transport.close();
|
|
}
|
|
if (mDestroyed)
|
|
{
|
|
return;
|
|
}
|
|
if (mCanceled)
|
|
{
|
|
finish();
|
|
return;
|
|
}
|
|
setResult(RESULT_OK);
|
|
finish();
|
|
}
|
|
catch (final AuthenticationFailedException afe)
|
|
{
|
|
Log.e(K9.LOG_TAG, "Error while testing settings", afe);
|
|
showErrorDialog(
|
|
R.string.account_setup_failed_dlg_auth_message_fmt,
|
|
afe.getMessage() == null ? "" : afe.getMessage());
|
|
}
|
|
catch (final CertificateValidationException cve)
|
|
{
|
|
Log.e(K9.LOG_TAG, "Error while testing settings", cve);
|
|
acceptKeyDialog(
|
|
R.string.account_setup_failed_dlg_certificate_message_fmt,
|
|
cve);
|
|
}
|
|
catch (final Throwable t)
|
|
{
|
|
Log.e(K9.LOG_TAG, "Error while testing settings", t);
|
|
showErrorDialog(
|
|
R.string.account_setup_failed_dlg_server_message_fmt,
|
|
(t.getMessage() == null ? "" : t.getMessage()));
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
.start();
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy()
|
|
{
|
|
super.onDestroy();
|
|
mDestroyed = true;
|
|
mCanceled = true;
|
|
}
|
|
|
|
private void setMessage(final int resId)
|
|
{
|
|
mHandler.post(new Runnable()
|
|
{
|
|
public void run()
|
|
{
|
|
if (mDestroyed)
|
|
{
|
|
return;
|
|
}
|
|
mMessageView.setText(getString(resId));
|
|
}
|
|
});
|
|
}
|
|
|
|
private void showErrorDialog(final int msgResId, final Object... args)
|
|
{
|
|
mHandler.post(new Runnable()
|
|
{
|
|
public void run()
|
|
{
|
|
if (mDestroyed)
|
|
{
|
|
return;
|
|
}
|
|
mProgressBar.setIndeterminate(false);
|
|
new AlertDialog.Builder(AccountSetupCheckSettings.this)
|
|
.setTitle(getString(R.string.account_setup_failed_dlg_title))
|
|
.setMessage(getString(msgResId, args))
|
|
.setCancelable(true)
|
|
.setNegativeButton(
|
|
getString(R.string.account_setup_failed_dlg_continue_action),
|
|
|
|
new DialogInterface.OnClickListener()
|
|
{
|
|
public void onClick(DialogInterface dialog, int which)
|
|
{
|
|
mCanceled=false;
|
|
setResult(RESULT_OK);
|
|
finish();
|
|
}
|
|
})
|
|
.setPositiveButton(
|
|
getString(R.string.account_setup_failed_dlg_edit_details_action),
|
|
new DialogInterface.OnClickListener()
|
|
{
|
|
public void onClick(DialogInterface dialog, int which)
|
|
{
|
|
finish();
|
|
}
|
|
})
|
|
.show();
|
|
}
|
|
});
|
|
}
|
|
private void acceptKeyDialog(final int msgResId, final Object... args)
|
|
{
|
|
mHandler.post(new Runnable()
|
|
{
|
|
public void run()
|
|
{
|
|
if (mDestroyed)
|
|
{
|
|
return;
|
|
}
|
|
final X509Certificate[] chain = TrustManagerFactory.getLastCertChain();
|
|
String exMessage = "Unknown Error";
|
|
|
|
Exception ex = ((Exception)args[0]);
|
|
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);
|
|
StringBuffer chainInfo = new StringBuffer(100);
|
|
for (int i = 0; i < chain.length; i++)
|
|
{
|
|
// display certificate chain information
|
|
chainInfo.append("Certificate chain[" + i + "]:\n");
|
|
chainInfo.append("Subject: " + chain[i].getSubjectDN().toString() + "\n");
|
|
chainInfo.append("Issuer: " + chain[i].getIssuerDN().toString() + "\n");
|
|
}
|
|
|
|
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)
|
|
{
|
|
try
|
|
{
|
|
String alias = mAccount.getUuid();
|
|
if (mCheckIncoming)
|
|
{
|
|
alias = alias + ".incoming";
|
|
}
|
|
if (mCheckOutgoing)
|
|
{
|
|
alias = alias + ".outgoing";
|
|
}
|
|
TrustManagerFactory.addCertificateChain(alias, chain);
|
|
}
|
|
catch (CertificateException e)
|
|
{
|
|
showErrorDialog(
|
|
R.string.account_setup_failed_dlg_certificate_message_fmt,
|
|
e.getMessage() == null ? "" : e.getMessage());
|
|
}
|
|
AccountSetupCheckSettings.actionCheckSettings(AccountSetupCheckSettings.this, mAccount,
|
|
mCheckIncoming, mCheckOutgoing);
|
|
}
|
|
})
|
|
.setNegativeButton(
|
|
getString(R.string.account_setup_failed_dlg_invalid_certificate_reject),
|
|
new DialogInterface.OnClickListener()
|
|
{
|
|
public void onClick(DialogInterface dialog, int which)
|
|
{
|
|
finish();
|
|
}
|
|
})
|
|
.show();
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onActivityResult(int reqCode, int resCode, Intent data)
|
|
{
|
|
setResult(resCode);
|
|
finish();
|
|
}
|
|
|
|
|
|
private void onCancel()
|
|
{
|
|
mCanceled = true;
|
|
setMessage(R.string.account_setup_check_settings_canceling_msg);
|
|
}
|
|
|
|
public void onClick(View v)
|
|
{
|
|
switch (v.getId())
|
|
{
|
|
case R.id.cancel:
|
|
onCancel();
|
|
break;
|
|
}
|
|
}
|
|
}
|