From 51c662f0d080da0f94f675467dbea49135674d73 Mon Sep 17 00:00:00 2001 From: ashley willis Date: Sat, 19 Nov 2011 00:49:04 -0600 Subject: [PATCH] pgp issues 2152, 2900, and 3673. also option to disable not-yet-encrypted drafts related to issue 1424. --- res/values/strings.xml | 4 ++ res/xml/account_settings_preferences.xml | 14 ++++++ src/com/fsck/k9/Account.java | 26 ++++++++++ src/com/fsck/k9/activity/MessageCompose.java | 49 +++++++++++++++++-- .../k9/activity/setup/AccountSettings.java | 16 ++++++ .../k9/controller/MessagingController.java | 19 +++---- src/com/fsck/k9/crypto/Apg.java | 35 +++++++++++++ src/com/fsck/k9/crypto/CryptoProvider.java | 1 + src/com/fsck/k9/crypto/None.java | 5 ++ .../fsck/k9/preferences/AccountSettings.java | 2 + 10 files changed, 157 insertions(+), 14 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 3cc393c03..a766be141 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -595,6 +595,10 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin not available Auto-sign Use the account\'s email address to guess the signature key. + Auto-encrypt + Automatically set encrypt if a public key matches a recipient. + Don\'t sync drafts + Don\'t sync drafts marked to be encrypted. Must change drafts folder\'s sync and push class to none, or these drafts will be deleted! Folder poll frequency 2nd class check frequency diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml index eb1f7b5b2..9a81c2d51 100644 --- a/res/xml/account_settings_preferences.xml +++ b/res/xml/account_settings_preferences.xml @@ -474,6 +474,20 @@ android:summary="@string/account_settings_crypto_auto_signature_summary" android:dependency="crypto_app"/> + + + + diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java index c3c0bbf99..b4aaf1908 100644 --- a/src/com/fsck/k9/Account.java +++ b/src/com/fsck/k9/Account.java @@ -149,6 +149,8 @@ public class Account implements BaseAccount { private boolean mSyncRemoteDeletions; private String mCryptoApp; private boolean mCryptoAutoSignature; + private boolean mCryptoAutoEncrypt; + private boolean mCryptoDontSyncDrafts; private CryptoProvider mCryptoProvider = null; @@ -240,6 +242,8 @@ public class Account implements BaseAccount { mSyncRemoteDeletions = true; mCryptoApp = Apg.NAME; mCryptoAutoSignature = false; + mCryptoAutoEncrypt = false; + mCryptoDontSyncDrafts = false; mEnabled = true; searchableFolders = Searchable.ALL; @@ -408,6 +412,8 @@ public class Account implements BaseAccount { mCryptoApp = prefs.getString(mUuid + ".cryptoApp", Apg.NAME); mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false); + mCryptoAutoEncrypt = prefs.getBoolean(mUuid + ".cryptoAutoEncrypt", false); + mCryptoDontSyncDrafts = prefs.getBoolean(mUuid + ".cryptoDontSyncDrafts", false); mEnabled = prefs.getBoolean(mUuid + ".enabled", true); } @@ -480,6 +486,8 @@ public class Account implements BaseAccount { editor.remove(mUuid + ".stripSignature"); editor.remove(mUuid + ".cryptoApp"); editor.remove(mUuid + ".cryptoAutoSignature"); + editor.remove(mUuid + ".cryptoAutoEncrypt"); + editor.remove(mUuid + ".cryptoDontSyncDrafts"); editor.remove(mUuid + ".enabled"); editor.remove(mUuid + ".enableMoveButtons"); editor.remove(mUuid + ".hideMoveButtonsEnum"); @@ -643,6 +651,8 @@ public class Account implements BaseAccount { editor.putBoolean(mUuid + ".stripSignature", mStripSignature); editor.putString(mUuid + ".cryptoApp", mCryptoApp); editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature); + editor.putBoolean(mUuid + ".cryptoAutoEncrypt", mCryptoAutoEncrypt); + editor.putBoolean(mUuid + ".cryptoDontSyncDrafts", mCryptoAutoEncrypt); editor.putBoolean(mUuid + ".enabled", mEnabled); editor.putBoolean(mUuid + ".vibrate", mNotificationSetting.shouldVibrate()); @@ -1466,6 +1476,22 @@ public class Account implements BaseAccount { mCryptoAutoSignature = cryptoAutoSignature; } + public boolean isCryptoAutoEncrypt() { + return mCryptoAutoEncrypt; + } + + public void setCryptoAutoEncrypt(boolean cryptoAutoEncrypt) { + mCryptoAutoEncrypt = cryptoAutoEncrypt; + } + + public boolean isCryptoDontSyncDrafts() { + return mCryptoDontSyncDrafts; + } + + public void setCryptoDontSyncDrafts(boolean cryptoDontSyncDrafts) { + mCryptoDontSyncDrafts = cryptoDontSyncDrafts; + } + public String getInboxFolderName() { return mInboxFolderName; } diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java index c4ee2c4a1..de364cdd9 100644 --- a/src/com/fsck/k9/activity/MessageCompose.java +++ b/src/com/fsck/k9/activity/MessageCompose.java @@ -208,6 +208,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc private ImageButton mAddBccFromContacts; private PgpData mPgpData = null; + private boolean mAutoEncrypt = false; + private boolean mDontSyncDrafts = false; private String mReferences; private String mInReplyTo; @@ -442,6 +444,28 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc public void afterTextChanged(android.text.Editable s) { } }; + TextWatcher recipientWatcher = new TextWatcher() { + public void beforeTextChanged(CharSequence s, int start, int before, int after) { } + + public void onTextChanged(CharSequence s, int start, int before, int count) { + mDraftNeedsSaving = true; + } + + public void afterTextChanged(android.text.Editable s) { + final CryptoProvider crypto = mAccount.getCryptoProvider(); + if (mAutoEncrypt && crypto.isAvailable(getApplicationContext())) { + for (Address address : getRecipientAddresses()) { + long ids[] = crypto.getPublicKeyIdsFromEmail(getApplicationContext(), + address.getAddress()); + if (ids != null && ids.length > 0) { + mEncryptCheckbox.setChecked(true); + break; + } + } + } + } + }; + TextWatcher sigwatcher = new TextWatcher() { public void beforeTextChanged(CharSequence s, int start, int before, int after) { } @@ -455,9 +479,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc public void afterTextChanged(android.text.Editable s) { } }; - mToView.addTextChangedListener(watcher); - mCcView.addTextChangedListener(watcher); - mBccView.addTextChangedListener(watcher); + mToView.addTextChangedListener(recipientWatcher); + mCcView.addTextChangedListener(recipientWatcher); + mBccView.addTextChangedListener(recipientWatcher); mSubjectView.addTextChangedListener(watcher); mMessageContentView.addTextChangedListener(watcher); @@ -616,6 +640,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc mCryptoSignatureUserId = (TextView)findViewById(R.id.userId); mCryptoSignatureUserIdRest = (TextView)findViewById(R.id.userIdRest); mEncryptCheckbox = (CheckBox)findViewById(R.id.cb_encrypt); + if (mSourceMessageBody != null) { + // mSourceMessageBody is set to something when replying to and forwarding decrypted + // messages, so the sender probably wants the message to be encrypted. + mEncryptCheckbox.setChecked(true); + } initializeCrypto(); final CryptoProvider crypto = mAccount.getCryptoProvider(); @@ -649,6 +678,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc } } updateEncryptLayout(); + mAutoEncrypt = mAccount.isCryptoAutoEncrypt(); + mDontSyncDrafts = mAccount.isCryptoDontSyncDrafts(); } else { mEncryptLayout.setVisibility(View.GONE); } @@ -776,6 +807,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc mCryptoSignatureUserId.setVisibility(View.INVISIBLE); mCryptoSignatureUserIdRest.setVisibility(View.INVISIBLE); } else { + mMessageFormat = MessageFormat.TEXT; // if a signature key is selected, then the checkbox itself has no text mCryptoSignatureCheckbox.setText(""); mCryptoSignatureCheckbox.setChecked(true); @@ -919,6 +951,12 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc return Address.parseUnencoded(view.getText().toString().trim()); } + private Address[] getRecipientAddresses() { + String addresses = mToView.getText().toString() + mCcView.getText().toString() + + mBccView.getText().toString(); + return Address.parseUnencoded(addresses.trim()); + } + /* * Build the Body that will contain the text of the message. We'll decide where to * include it later. Draft messages are treated somewhat differently in that signatures are not @@ -960,7 +998,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc // Place the signature immediately after the reply. if (!isDraft) { if (mQuoteStyle == QuoteStyle.HEADER || replyAfterQuote || mAccount.isSignatureBeforeQuotedText()) { - Log.d("ASH", "appending signature after new content"); text = appendSignature(text); } } @@ -1461,6 +1498,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc return; } if (mEncryptCheckbox.isChecked() && !mPgpData.hasEncryptionKeys()) { + mMessageFormat = MessageFormat.TEXT; // key selection before encryption StringBuilder emails = new StringBuilder(); Address[][] addresses = new Address[][] { getAddresses(mToView), @@ -2876,7 +2914,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc } final MessagingController messagingController = MessagingController.getInstance(getApplication()); - Message draftMessage = messagingController.saveDraft(mAccount, message); + Message draftMessage = messagingController.saveDraft(mAccount, message, + mDontSyncDrafts && mEncryptCheckbox.isChecked()); mDraftUid = draftMessage.getUid(); // Don't display the toast if the user is just changing the orientation diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java index f3acb7d15..96c715700 100644 --- a/src/com/fsck/k9/activity/setup/AccountSettings.java +++ b/src/com/fsck/k9/activity/setup/AccountSettings.java @@ -97,6 +97,8 @@ public class AccountSettings extends K9PreferenceActivity { private static final String PREFERENCE_SYNC_REMOTE_DELETIONS = "account_sync_remote_deletetions"; private static final String PREFERENCE_CRYPTO_APP = "crypto_app"; private static final String PREFERENCE_CRYPTO_AUTO_SIGNATURE = "crypto_auto_signature"; + private static final String PREFERENCE_CRYPTO_AUTO_ENCRYPT = "crypto_auto_encrypt"; + private static final String PREFERENCE_CRYPTO_DONT_SYNC_DRAFTS = "crypto_dont_sync_drafts"; private static final String PREFERENCE_LOCAL_STORAGE_PROVIDER = "local_storage_provider"; @@ -161,6 +163,8 @@ public class AccountSettings extends K9PreferenceActivity { private ListPreference mMaxPushFolders; private ListPreference mCryptoApp; private CheckBoxPreference mCryptoAutoSignature; + private CheckBoxPreference mCryptoAutoEncrypt; + private CheckBoxPreference mCryptoDontSyncDrafts; private ListPreference mLocalStorageProvider; @@ -681,14 +685,24 @@ public class AccountSettings extends K9PreferenceActivity { mCryptoAutoSignature = (CheckBoxPreference) findPreference(PREFERENCE_CRYPTO_AUTO_SIGNATURE); mCryptoAutoSignature.setChecked(mAccount.getCryptoAutoSignature()); + mCryptoAutoEncrypt = (CheckBoxPreference) findPreference(PREFERENCE_CRYPTO_AUTO_ENCRYPT); + mCryptoAutoEncrypt.setChecked(mAccount.isCryptoAutoEncrypt()); + + mCryptoDontSyncDrafts = (CheckBoxPreference) findPreference(PREFERENCE_CRYPTO_DONT_SYNC_DRAFTS); + mCryptoDontSyncDrafts.setChecked(mAccount.isCryptoDontSyncDrafts()); + handleCryptoAppDependencies(); } private void handleCryptoAppDependencies() { if ("".equals(mCryptoApp.getValue())) { mCryptoAutoSignature.setEnabled(false); + mCryptoAutoEncrypt.setEnabled(false); + mCryptoDontSyncDrafts.setEnabled(false); } else { mCryptoAutoSignature.setEnabled(true); + mCryptoAutoEncrypt.setEnabled(true); + mCryptoDontSyncDrafts.setEnabled(true); } } @@ -734,6 +748,8 @@ public class AccountSettings extends K9PreferenceActivity { mAccount.setStripSignature(mStripSignature.isChecked()); mAccount.setCryptoApp(mCryptoApp.getValue()); mAccount.setCryptoAutoSignature(mCryptoAutoSignature.isChecked()); + mAccount.setCryptoAutoEncrypt(mCryptoAutoEncrypt.isChecked()); + mAccount.setCryptoDontSyncDrafts(mCryptoDontSyncDrafts.isChecked()); mAccount.setLocalStorageProviderId(mLocalStorageProvider.getValue()); // In webdav account we use the exact folder name also for inbox, diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index 2eedc119e..d739c5fe3 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -4059,7 +4059,7 @@ public class MessagingController implements Runnable { * @param message Message to save. * @return Message representing the entry in the local store. */ - public Message saveDraft(final Account account, final Message message) { + public Message saveDraft(final Account account, final Message message, final boolean dontSyncDraft) { Message localMessage = null; try { LocalStore localStore = account.getLocalStore(); @@ -4072,14 +4072,15 @@ public class MessagingController implements Runnable { // Fetch the message back from the store. This is the Message that's returned to the caller. localMessage = localFolder.getMessage(message.getUid()); localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true); - - PendingCommand command = new PendingCommand(); - command.command = PENDING_COMMAND_APPEND; - command.arguments = new String[] { - localFolder.getName(), - localMessage.getUid() - }; - queuePendingCommand(account, command); + if (!dontSyncDraft) { + PendingCommand command = new PendingCommand(); + command.command = PENDING_COMMAND_APPEND; + command.arguments = new String[] { + localFolder.getName(), + localMessage.getUid() + }; + queuePendingCommand(account, command); + } processPendingCommands(account); } catch (MessagingException e) { diff --git a/src/com/fsck/k9/crypto/Apg.java b/src/com/fsck/k9/crypto/Apg.java index de1a2b77e..350a6c284 100644 --- a/src/com/fsck/k9/crypto/Apg.java +++ b/src/com/fsck/k9/crypto/Apg.java @@ -232,6 +232,41 @@ public class Apg extends CryptoProvider { return ids; } + /** + * Get public key ids based on a given email. + * + * @param context + * @param email The email in question. + * @return key ids + */ + @Override + public long[] getPublicKeyIdsFromEmail(Context context, String email) { + long ids[] = null; + try { + Uri contentUri = Uri.withAppendedPath(Apg.CONTENT_URI_PUBLIC_KEY_RING_BY_EMAILS, + email); + Cursor c = context.getContentResolver().query(contentUri, + new String[] { "master_key_id" }, + null, null, null); + if (c != null && c.getCount() > 0) { + ids = new long[c.getCount()]; + while (c.moveToNext()) { + ids[c.getPosition()] = c.getLong(0); + } + } + + if (c != null) { + c.close(); + } + } catch (SecurityException e) { + Toast.makeText(context, + context.getResources().getString(R.string.insufficient_apg_permissions), + Toast.LENGTH_LONG).show(); + } + + return ids; + } + /** * Get the user id based on the key id. * diff --git a/src/com/fsck/k9/crypto/CryptoProvider.java b/src/com/fsck/k9/crypto/CryptoProvider.java index 79401b154..373a62df9 100644 --- a/src/com/fsck/k9/crypto/CryptoProvider.java +++ b/src/com/fsck/k9/crypto/CryptoProvider.java @@ -24,6 +24,7 @@ abstract public class CryptoProvider { abstract public boolean encrypt(Activity activity, String data, PgpData pgpData); abstract public boolean decrypt(Activity activity, String data, PgpData pgpData); abstract public long[] getSecretKeyIdsFromEmail(Context context, String email); + abstract public long[] getPublicKeyIdsFromEmail(Context context, String email); abstract public String getUserId(Context context, long keyId); abstract public String getName(); abstract public boolean test(Context context); diff --git a/src/com/fsck/k9/crypto/None.java b/src/com/fsck/k9/crypto/None.java index eb83d9261..cf2af7bc4 100644 --- a/src/com/fsck/k9/crypto/None.java +++ b/src/com/fsck/k9/crypto/None.java @@ -37,6 +37,11 @@ public class None extends CryptoProvider { return null; } + @Override + public long[] getPublicKeyIdsFromEmail(Context context, String email) { + return null; + } + @Override public String getUserId(Context context, long keyId) { return null; diff --git a/src/com/fsck/k9/preferences/AccountSettings.java b/src/com/fsck/k9/preferences/AccountSettings.java index 167d9c914..b9a9cf593 100644 --- a/src/com/fsck/k9/preferences/AccountSettings.java +++ b/src/com/fsck/k9/preferences/AccountSettings.java @@ -27,6 +27,8 @@ public class AccountSettings { s.put("chipColor", new ColorSetting(0xFF0000FF)); s.put("cryptoApp", new StringSetting(Apg.NAME)); s.put("cryptoAutoSignature", new BooleanSetting(false)); + //s.put("cryptoAutoEncrypt", new BooleanSetting(false)); // added to version 3? + //s.put("cryptoDontSyncDrafts", new BooleanSetting(false)); // added to version 3? s.put("defaultQuotedTextShown", new BooleanSetting(Account.DEFAULT_QUOTED_TEXT_SHOWN)); s.put("deletePolicy", new DeletePolicySetting(Account.DELETE_POLICY_NEVER)); s.put("displayCount", new IntegerResourceSetting(K9.DEFAULT_VISIBLE_LIMIT,