Loading build.gradle +2 −0 Original line number Diff line number Diff line Loading @@ -27,11 +27,13 @@ android { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } instrumentTest { manifest.srcFile 'tests/AndroidManifest.xml' java.srcDirs = ['tests/src'] assets.srcDirs = ['tests/assets'] } } } src/com/fsck/k9/Account.java +57 −0 Original line number Diff line number Diff line package com.fsck.k9; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; Loading @@ -22,6 +24,7 @@ import android.net.ConnectivityManager; import android.net.Uri; import android.util.Log; import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; import com.fsck.k9.crypto.Apg; import com.fsck.k9.crypto.CryptoProvider; import com.fsck.k9.helper.Utility; Loading @@ -40,6 +43,7 @@ import com.fsck.k9.search.SqlQueryBuilder; import com.fsck.k9.search.SearchSpecification.Attribute; import com.fsck.k9.search.SearchSpecification.SearchCondition; import com.fsck.k9.search.SearchSpecification.Searchfield; import com.fsck.k9.security.LocalKeyStore; import com.fsck.k9.view.ColorChip; import com.larswerkman.colorpicker.ColorPicker; Loading Loading @@ -1865,4 +1869,57 @@ public class Account implements BaseAccount { search.and(Searchfield.FOLDER, folderName, Attribute.NOT_EQUALS); } } /** * Add a new certificate for the incoming or outgoing server to the local key store. */ public void addCertificate(CheckDirection direction, X509Certificate certificate) throws CertificateException { Uri uri; if (direction.equals(CheckDirection.INCOMING)) { uri = Uri.parse(getStoreUri()); } else { uri = Uri.parse(getTransportUri()); } LocalKeyStore localKeyStore = LocalKeyStore.getInstance(); localKeyStore.addCertificate(uri.getHost(), uri.getPort(), certificate); } /** * Examine the existing settings for an account. If the old host/port is different from the * new host/port, then try and delete any (possibly non-existent) certificate stored for the * old host/port. */ public void deleteCertificate(String newHost, int newPort, CheckDirection direction) { Uri uri; if (direction.equals(CheckDirection.INCOMING)) { uri = Uri.parse(getStoreUri()); } else { uri = Uri.parse(getTransportUri()); } String oldHost = uri.getHost(); int oldPort = uri.getPort(); if (oldPort == -1) { // This occurs when a new account is created return; } if (!newHost.equals(oldHost) || newPort != oldPort) { LocalKeyStore localKeyStore = LocalKeyStore.getInstance(); localKeyStore.deleteCertificate(oldHost, oldPort); } } /** * Examine the settings for the account and attempt to delete (possibly non-existent) * certificates for the incoming and outgoing servers. */ public void deleteCertificates() { LocalKeyStore localKeyStore = LocalKeyStore.getInstance(); Uri uri = Uri.parse(getStoreUri()); localKeyStore.deleteCertificate(uri.getHost(), uri.getPort()); uri = Uri.parse(getTransportUri()); localKeyStore.deleteCertificate(uri.getHost(), uri.getPort()); } } src/com/fsck/k9/K9.java +32 −11 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.internet.BinaryTempFileBody; import com.fsck.k9.mail.store.LocalStore; import com.fsck.k9.provider.UnreadWidgetProvider; import com.fsck.k9.security.LocalKeyStore; import com.fsck.k9.service.BootReceiver; import com.fsck.k9.service.MailService; import com.fsck.k9.service.ShutdownReceiver; Loading @@ -59,7 +60,7 @@ public class K9 extends Application { * The application instance. Never <code>null</code>. * @throws Exception */ void initializeComponent(K9 application); void initializeComponent(Application application); } public static Application app = null; Loading Loading @@ -91,6 +92,15 @@ public class K9 extends Application { */ private static List<ApplicationAware> observers = new ArrayList<ApplicationAware>(); /** * This will be {@code true} once the initialization is complete and {@link #notifyObservers()} * was called. * Afterwards calls to {@link #registerApplicationAware(com.fsck.k9.K9.ApplicationAware)} will * immediately call {@link com.fsck.k9.K9.ApplicationAware#initializeComponent(K9)} for the * supplied argument. */ private static boolean sInitialized = false; public enum BACKGROUND_OPS { WHEN_CHECKED, ALWAYS, NEVER, WHEN_CHECKED_AUTO_SYNC } Loading Loading @@ -581,6 +591,8 @@ public class K9 extends Application { */ BinaryTempFileBody.setTempDirectory(getCacheDir()); LocalKeyStore.setKeyStoreLocation(getDir("KeyStore", MODE_PRIVATE).toString()); /* * Enable background sync of messages */ Loading Loading @@ -829,6 +841,7 @@ public class K9 extends Application { * component that the application is available and ready */ protected void notifyObservers() { synchronized (observers) { for (final ApplicationAware aware : observers) { if (K9.DEBUG) { Log.v(K9.LOG_TAG, "Initializing observer: " + aware); Loading @@ -839,6 +852,10 @@ public class K9 extends Application { Log.w(K9.LOG_TAG, "Failure when notifying " + aware, e); } } sInitialized = true; observers.clear(); } } /** Loading @@ -848,10 +865,14 @@ public class K9 extends Application { * Never <code>null</code>. */ public static void registerApplicationAware(final ApplicationAware component) { if (!observers.contains(component)) { synchronized (observers) { if (sInitialized) { component.initializeComponent(K9.app); } else if (!observers.contains(component)) { observers.add(component); } } } public static String getK9Language() { return language; Loading src/com/fsck/k9/Preferences.java +1 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ public class Preferences { Store.removeAccount(account); account.deleteCertificates(); account.delete(this); if (newAccount == account) { Loading src/com/fsck/k9/activity/setup/AccountSetupBasics.java +36 −16 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ import android.widget.Button; import android.widget.EditText; import com.fsck.k9.*; import com.fsck.k9.activity.K9Activity; import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; import com.fsck.k9.helper.Utility; import java.io.Serializable; import java.io.UnsupportedEncodingException; Loading @@ -37,6 +38,8 @@ public class AccountSetupBasics extends K9Activity private final static int DIALOG_NOTE = 1; private final static String STATE_KEY_PROVIDER = "com.fsck.k9.AccountSetupBasics.provider"; private final static String STATE_KEY_CHECKED_INCOMING = "com.fsck.k9.AccountSetupBasics.checkedIncoming"; private EditText mEmailView; private EditText mPasswordView; Loading @@ -46,6 +49,7 @@ public class AccountSetupBasics extends K9Activity private Provider mProvider; private EmailAddressValidator mEmailValidator = new EmailAddressValidator(); private boolean mCheckedIncoming = false; public static void actionNewAccount(Context context) { Intent i = new Intent(context, AccountSetupBasics.class); Loading @@ -66,15 +70,6 @@ public class AccountSetupBasics extends K9Activity mEmailView.addTextChangedListener(this); mPasswordView.addTextChangedListener(this); if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) { String accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT); mAccount = Preferences.getPreferences(this).getAccount(accountUuid); } if (savedInstanceState != null && savedInstanceState.containsKey(STATE_KEY_PROVIDER)) { mProvider = (Provider)savedInstanceState.getSerializable(STATE_KEY_PROVIDER); } } @Override Loading @@ -92,6 +87,23 @@ public class AccountSetupBasics extends K9Activity if (mProvider != null) { outState.putSerializable(STATE_KEY_PROVIDER, mProvider); } outState.putBoolean(STATE_KEY_CHECKED_INCOMING, mCheckedIncoming); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if (savedInstanceState.containsKey(EXTRA_ACCOUNT)) { String accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT); mAccount = Preferences.getPreferences(this).getAccount(accountUuid); } if (savedInstanceState.containsKey(STATE_KEY_PROVIDER)) { mProvider = (Provider) savedInstanceState.getSerializable(STATE_KEY_PROVIDER); } mCheckedIncoming = savedInstanceState.getBoolean(STATE_KEY_CHECKED_INCOMING); } public void afterTextChanged(Editable s) { Loading Loading @@ -229,7 +241,8 @@ public class AccountSetupBasics extends K9Activity } else if (incomingUri.toString().startsWith("pop3")) { mAccount.setDeletePolicy(Account.DELETE_POLICY_NEVER); } AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, true); // Check incoming here. Then check outgoing in onActivityResult() AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.INCOMING); } catch (UnsupportedEncodingException enc) { // This really shouldn't happen since the encoding is hardcoded to UTF-8 Log.e(K9.LOG_TAG, "Couldn't urlencode username or password.", enc); Loading Loading @@ -266,6 +279,12 @@ public class AccountSetupBasics extends K9Activity @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if (!mCheckedIncoming) { //We've successfully checked incoming. Now check outgoing. mCheckedIncoming = true; AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING); } else { //We've successfully checked outgoing as well. mAccount.setDescription(mAccount.getEmail()); mAccount.save(Preferences.getPreferences(this)); K9.setServicesEnabled(this); Loading @@ -273,6 +292,7 @@ public class AccountSetupBasics extends K9Activity finish(); } } } private void onManualSetup() { String email = mEmailView.getText().toString(); Loading Loading
build.gradle +2 −0 Original line number Diff line number Diff line Loading @@ -27,11 +27,13 @@ android { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } instrumentTest { manifest.srcFile 'tests/AndroidManifest.xml' java.srcDirs = ['tests/src'] assets.srcDirs = ['tests/assets'] } } }
src/com/fsck/k9/Account.java +57 −0 Original line number Diff line number Diff line package com.fsck.k9; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; Loading @@ -22,6 +24,7 @@ import android.net.ConnectivityManager; import android.net.Uri; import android.util.Log; import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; import com.fsck.k9.crypto.Apg; import com.fsck.k9.crypto.CryptoProvider; import com.fsck.k9.helper.Utility; Loading @@ -40,6 +43,7 @@ import com.fsck.k9.search.SqlQueryBuilder; import com.fsck.k9.search.SearchSpecification.Attribute; import com.fsck.k9.search.SearchSpecification.SearchCondition; import com.fsck.k9.search.SearchSpecification.Searchfield; import com.fsck.k9.security.LocalKeyStore; import com.fsck.k9.view.ColorChip; import com.larswerkman.colorpicker.ColorPicker; Loading Loading @@ -1865,4 +1869,57 @@ public class Account implements BaseAccount { search.and(Searchfield.FOLDER, folderName, Attribute.NOT_EQUALS); } } /** * Add a new certificate for the incoming or outgoing server to the local key store. */ public void addCertificate(CheckDirection direction, X509Certificate certificate) throws CertificateException { Uri uri; if (direction.equals(CheckDirection.INCOMING)) { uri = Uri.parse(getStoreUri()); } else { uri = Uri.parse(getTransportUri()); } LocalKeyStore localKeyStore = LocalKeyStore.getInstance(); localKeyStore.addCertificate(uri.getHost(), uri.getPort(), certificate); } /** * Examine the existing settings for an account. If the old host/port is different from the * new host/port, then try and delete any (possibly non-existent) certificate stored for the * old host/port. */ public void deleteCertificate(String newHost, int newPort, CheckDirection direction) { Uri uri; if (direction.equals(CheckDirection.INCOMING)) { uri = Uri.parse(getStoreUri()); } else { uri = Uri.parse(getTransportUri()); } String oldHost = uri.getHost(); int oldPort = uri.getPort(); if (oldPort == -1) { // This occurs when a new account is created return; } if (!newHost.equals(oldHost) || newPort != oldPort) { LocalKeyStore localKeyStore = LocalKeyStore.getInstance(); localKeyStore.deleteCertificate(oldHost, oldPort); } } /** * Examine the settings for the account and attempt to delete (possibly non-existent) * certificates for the incoming and outgoing servers. */ public void deleteCertificates() { LocalKeyStore localKeyStore = LocalKeyStore.getInstance(); Uri uri = Uri.parse(getStoreUri()); localKeyStore.deleteCertificate(uri.getHost(), uri.getPort()); uri = Uri.parse(getTransportUri()); localKeyStore.deleteCertificate(uri.getHost(), uri.getPort()); } }
src/com/fsck/k9/K9.java +32 −11 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.internet.BinaryTempFileBody; import com.fsck.k9.mail.store.LocalStore; import com.fsck.k9.provider.UnreadWidgetProvider; import com.fsck.k9.security.LocalKeyStore; import com.fsck.k9.service.BootReceiver; import com.fsck.k9.service.MailService; import com.fsck.k9.service.ShutdownReceiver; Loading @@ -59,7 +60,7 @@ public class K9 extends Application { * The application instance. Never <code>null</code>. * @throws Exception */ void initializeComponent(K9 application); void initializeComponent(Application application); } public static Application app = null; Loading Loading @@ -91,6 +92,15 @@ public class K9 extends Application { */ private static List<ApplicationAware> observers = new ArrayList<ApplicationAware>(); /** * This will be {@code true} once the initialization is complete and {@link #notifyObservers()} * was called. * Afterwards calls to {@link #registerApplicationAware(com.fsck.k9.K9.ApplicationAware)} will * immediately call {@link com.fsck.k9.K9.ApplicationAware#initializeComponent(K9)} for the * supplied argument. */ private static boolean sInitialized = false; public enum BACKGROUND_OPS { WHEN_CHECKED, ALWAYS, NEVER, WHEN_CHECKED_AUTO_SYNC } Loading Loading @@ -581,6 +591,8 @@ public class K9 extends Application { */ BinaryTempFileBody.setTempDirectory(getCacheDir()); LocalKeyStore.setKeyStoreLocation(getDir("KeyStore", MODE_PRIVATE).toString()); /* * Enable background sync of messages */ Loading Loading @@ -829,6 +841,7 @@ public class K9 extends Application { * component that the application is available and ready */ protected void notifyObservers() { synchronized (observers) { for (final ApplicationAware aware : observers) { if (K9.DEBUG) { Log.v(K9.LOG_TAG, "Initializing observer: " + aware); Loading @@ -839,6 +852,10 @@ public class K9 extends Application { Log.w(K9.LOG_TAG, "Failure when notifying " + aware, e); } } sInitialized = true; observers.clear(); } } /** Loading @@ -848,10 +865,14 @@ public class K9 extends Application { * Never <code>null</code>. */ public static void registerApplicationAware(final ApplicationAware component) { if (!observers.contains(component)) { synchronized (observers) { if (sInitialized) { component.initializeComponent(K9.app); } else if (!observers.contains(component)) { observers.add(component); } } } public static String getK9Language() { return language; Loading
src/com/fsck/k9/Preferences.java +1 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ public class Preferences { Store.removeAccount(account); account.deleteCertificates(); account.delete(this); if (newAccount == account) { Loading
src/com/fsck/k9/activity/setup/AccountSetupBasics.java +36 −16 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ import android.widget.Button; import android.widget.EditText; import com.fsck.k9.*; import com.fsck.k9.activity.K9Activity; import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; import com.fsck.k9.helper.Utility; import java.io.Serializable; import java.io.UnsupportedEncodingException; Loading @@ -37,6 +38,8 @@ public class AccountSetupBasics extends K9Activity private final static int DIALOG_NOTE = 1; private final static String STATE_KEY_PROVIDER = "com.fsck.k9.AccountSetupBasics.provider"; private final static String STATE_KEY_CHECKED_INCOMING = "com.fsck.k9.AccountSetupBasics.checkedIncoming"; private EditText mEmailView; private EditText mPasswordView; Loading @@ -46,6 +49,7 @@ public class AccountSetupBasics extends K9Activity private Provider mProvider; private EmailAddressValidator mEmailValidator = new EmailAddressValidator(); private boolean mCheckedIncoming = false; public static void actionNewAccount(Context context) { Intent i = new Intent(context, AccountSetupBasics.class); Loading @@ -66,15 +70,6 @@ public class AccountSetupBasics extends K9Activity mEmailView.addTextChangedListener(this); mPasswordView.addTextChangedListener(this); if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) { String accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT); mAccount = Preferences.getPreferences(this).getAccount(accountUuid); } if (savedInstanceState != null && savedInstanceState.containsKey(STATE_KEY_PROVIDER)) { mProvider = (Provider)savedInstanceState.getSerializable(STATE_KEY_PROVIDER); } } @Override Loading @@ -92,6 +87,23 @@ public class AccountSetupBasics extends K9Activity if (mProvider != null) { outState.putSerializable(STATE_KEY_PROVIDER, mProvider); } outState.putBoolean(STATE_KEY_CHECKED_INCOMING, mCheckedIncoming); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if (savedInstanceState.containsKey(EXTRA_ACCOUNT)) { String accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT); mAccount = Preferences.getPreferences(this).getAccount(accountUuid); } if (savedInstanceState.containsKey(STATE_KEY_PROVIDER)) { mProvider = (Provider) savedInstanceState.getSerializable(STATE_KEY_PROVIDER); } mCheckedIncoming = savedInstanceState.getBoolean(STATE_KEY_CHECKED_INCOMING); } public void afterTextChanged(Editable s) { Loading Loading @@ -229,7 +241,8 @@ public class AccountSetupBasics extends K9Activity } else if (incomingUri.toString().startsWith("pop3")) { mAccount.setDeletePolicy(Account.DELETE_POLICY_NEVER); } AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, true); // Check incoming here. Then check outgoing in onActivityResult() AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.INCOMING); } catch (UnsupportedEncodingException enc) { // This really shouldn't happen since the encoding is hardcoded to UTF-8 Log.e(K9.LOG_TAG, "Couldn't urlencode username or password.", enc); Loading Loading @@ -266,6 +279,12 @@ public class AccountSetupBasics extends K9Activity @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if (!mCheckedIncoming) { //We've successfully checked incoming. Now check outgoing. mCheckedIncoming = true; AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING); } else { //We've successfully checked outgoing as well. mAccount.setDescription(mAccount.getEmail()); mAccount.save(Preferences.getPreferences(this)); K9.setServicesEnabled(this); Loading @@ -273,6 +292,7 @@ public class AccountSetupBasics extends K9Activity finish(); } } } private void onManualSetup() { String email = mEmailView.getText().toString(); Loading