1
0
mirror of https://github.com/moparisthebest/k-9 synced 2025-01-10 13:18:09 -05:00

Merge branch 'master' into ms-eas. Format cleanup with astyle.

This commit is contained in:
wongk 2011-11-30 12:06:30 -05:00
commit 4d032a861e
59 changed files with 3116 additions and 1726 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest <manifest
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="14013" android:versionCode="15002"
android:versionName="3.913" package="com.fsck.k9" android:versionName="4.102" package="com.fsck.k9"
> >
<uses-sdk <uses-sdk
android:minSdkVersion="7" android:minSdkVersion="7"

1111
res/values-da/strings.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -491,6 +491,7 @@
<item></item> <item></item>
<item>ca</item> <item>ca</item>
<item>cs</item> <item>cs</item>
<item>da</item>
<item>de</item> <item>de</item>
<item>en</item> <item>en</item>
<item>es</item> <item>es</item>

View File

@ -61,6 +61,7 @@
<string name="forward_action">Forward</string> <string name="forward_action">Forward</string>
<string name="move_action">Move</string> <string name="move_action">Move</string>
<string name="continue_action">Continue</string> <string name="continue_action">Continue</string>
<string name="back_action">Back</string>
<string name="done_action">Done</string> <!-- Used to complete a multi-step process --> <string name="done_action">Done</string> <!-- Used to complete a multi-step process -->
<string name="remove_action">Remove</string> <string name="remove_action">Remove</string>
<string name="discard_action">Discard</string> <string name="discard_action">Discard</string>
@ -597,6 +598,8 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
<string name="account_settings_crypto_app_not_available">not available</string> <string name="account_settings_crypto_app_not_available">not available</string>
<string name="account_settings_crypto_auto_signature">Auto-sign</string> <string name="account_settings_crypto_auto_signature">Auto-sign</string>
<string name="account_settings_crypto_auto_signature_summary">Use the account\'s email address to guess the signature key.</string> <string name="account_settings_crypto_auto_signature_summary">Use the account\'s email address to guess the signature key.</string>
<string name="account_settings_crypto_auto_encrypt">Auto-encrypt</string>
<string name="account_settings_crypto_auto_encrypt_summary">Automatically set encrypt if a public key matches a recipient.</string>
<string name="account_settings_mail_check_frequency_label">Folder poll frequency</string> <string name="account_settings_mail_check_frequency_label">Folder poll frequency</string>
<string name="account_settings_second_class_check_frequency_label">2nd class check frequency</string> <string name="account_settings_second_class_check_frequency_label">2nd class check frequency</string>
@ -1023,6 +1026,12 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
<string name="save_or_discard_draft_message_dlg_title">Save draft message?</string> <string name="save_or_discard_draft_message_dlg_title">Save draft message?</string>
<string name="save_or_discard_draft_message_instructions_fmt">Save or Discard this message?</string> <string name="save_or_discard_draft_message_instructions_fmt">Save or Discard this message?</string>
<string name="refuse_to_save_draft_marked_encrypted_dlg_title">Refuse to save draft message.</string>
<string name="refuse_to_save_draft_marked_encrypted_instructions_fmt">Refuse to save draft message marked encrypted.</string>
<string name="continue_without_public_key_dlg_title">Continue without public key?</string>
<string name="continue_without_public_key_instructions_fmt">One or more recipients do not have a saved public key. Continue?</string>
<string name="charset_not_found">This message can\'t be displayed because the charset \"<xliff:g id="charset">%s</xliff:g>\" wasn\'t found.</string> <string name="charset_not_found">This message can\'t be displayed because the charset \"<xliff:g id="charset">%s</xliff:g>\" wasn\'t found.</string>
<string name="select_text_now">Select text to copy.</string> <string name="select_text_now">Select text to copy.</string>

View File

@ -474,6 +474,13 @@
android:summary="@string/account_settings_crypto_auto_signature_summary" android:summary="@string/account_settings_crypto_auto_signature_summary"
android:dependency="crypto_app"/> android:dependency="crypto_app"/>
<CheckBoxPreference
android:persistent="false"
android:key="crypto_auto_encrypt"
android:title="@string/account_settings_crypto_auto_encrypt"
android:summary="@string/account_settings_crypto_auto_encrypt_summary"
android:dependency="crypto_app"/>
</PreferenceScreen> </PreferenceScreen>
</PreferenceScreen> </PreferenceScreen>

View File

@ -152,6 +152,7 @@ public class Account implements BaseAccount {
// The following 2 settings are currently only used by the EasStore. // The following 2 settings are currently only used by the EasStore.
private String mSyncKey; private String mSyncKey;
private String mSecurityKey; private String mSecurityKey;
private boolean mCryptoAutoEncrypt;
private CryptoProvider mCryptoProvider = null; private CryptoProvider mCryptoProvider = null;
@ -243,6 +244,7 @@ public class Account implements BaseAccount {
mSyncRemoteDeletions = true; mSyncRemoteDeletions = true;
mCryptoApp = Apg.NAME; mCryptoApp = Apg.NAME;
mCryptoAutoSignature = false; mCryptoAutoSignature = false;
mCryptoAutoEncrypt = false;
mEnabled = true; mEnabled = true;
searchableFolders = Searchable.ALL; searchableFolders = Searchable.ALL;
@ -411,6 +413,7 @@ public class Account implements BaseAccount {
mCryptoApp = prefs.getString(mUuid + ".cryptoApp", Apg.NAME); mCryptoApp = prefs.getString(mUuid + ".cryptoApp", Apg.NAME);
mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false); mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false);
mCryptoAutoEncrypt = prefs.getBoolean(mUuid + ".cryptoAutoEncrypt", false);
mEnabled = prefs.getBoolean(mUuid + ".enabled", true); mEnabled = prefs.getBoolean(mUuid + ".enabled", true);
mSyncKey = prefs.getString(mUuid + ".syncKey", ""); mSyncKey = prefs.getString(mUuid + ".syncKey", "");
mSecurityKey = prefs.getString(mUuid + ".securityKey", ""); mSecurityKey = prefs.getString(mUuid + ".securityKey", "");
@ -487,6 +490,7 @@ public class Account implements BaseAccount {
editor.remove(mUuid + ".stripSignature"); editor.remove(mUuid + ".stripSignature");
editor.remove(mUuid + ".cryptoApp"); editor.remove(mUuid + ".cryptoApp");
editor.remove(mUuid + ".cryptoAutoSignature"); editor.remove(mUuid + ".cryptoAutoSignature");
editor.remove(mUuid + ".cryptoAutoEncrypt");
editor.remove(mUuid + ".enabled"); editor.remove(mUuid + ".enabled");
editor.remove(mUuid + ".syncKey"); editor.remove(mUuid + ".syncKey");
editor.remove(mUuid + ".securityKey"); editor.remove(mUuid + ".securityKey");
@ -533,21 +537,18 @@ public class Account implements BaseAccount {
if (moveUp) { if (moveUp) {
for (int i = 0; i < uuids.length; i++) { for (int i = 0; i < uuids.length; i++) {
if (i > 0 && uuids[i].equals(mUuid)) { if (i > 0 && uuids[i].equals(mUuid)) {
newUuids[i] = newUuids[i-1]; newUuids[i] = newUuids[i - 1];
newUuids[i-1] = mUuid; newUuids[i - 1] = mUuid;
} } else {
else {
newUuids[i] = uuids[i]; newUuids[i] = uuids[i];
} }
} }
} } else {
else {
for (int i = uuids.length - 1; i >= 0; i--) { for (int i = uuids.length - 1; i >= 0; i--) {
if (i < uuids.length - 1 && uuids[i].equals(mUuid)) { if (i < uuids.length - 1 && uuids[i].equals(mUuid)) {
newUuids[i] = newUuids[i+1]; newUuids[i] = newUuids[i + 1];
newUuids[i+1] = mUuid; newUuids[i + 1] = mUuid;
} } else {
else {
newUuids[i] = uuids[i]; newUuids[i] = uuids[i];
} }
} }
@ -653,6 +654,7 @@ public class Account implements BaseAccount {
editor.putBoolean(mUuid + ".stripSignature", mStripSignature); editor.putBoolean(mUuid + ".stripSignature", mStripSignature);
editor.putString(mUuid + ".cryptoApp", mCryptoApp); editor.putString(mUuid + ".cryptoApp", mCryptoApp);
editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature); editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature);
editor.putBoolean(mUuid + ".cryptoAutoEncrypt", mCryptoAutoEncrypt);
editor.putBoolean(mUuid + ".enabled", mEnabled); editor.putBoolean(mUuid + ".enabled", mEnabled);
editor.putString(mUuid + ".syncKey", mSyncKey); editor.putString(mUuid + ".syncKey", mSyncKey);
editor.putString(mUuid + ".securityKey", mSecurityKey); editor.putString(mUuid + ".securityKey", mSecurityKey);
@ -1494,6 +1496,14 @@ public class Account implements BaseAccount {
mSecurityKey = key; mSecurityKey = key;
} }
public boolean isCryptoAutoEncrypt() {
return mCryptoAutoEncrypt;
}
public void setCryptoAutoEncrypt(boolean cryptoAutoEncrypt) {
mCryptoAutoEncrypt = cryptoAutoEncrypt;
}
public String getInboxFolderName() { public String getInboxFolderName() {
return mInboxFolderName; return mInboxFolderName;
} }

View File

@ -1218,19 +1218,16 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
item.setVisible(false); item.setVisible(false);
} }
} }
} } else {
else {
EnumSet<ACCOUNT_LOCATION> accountLocation = accountLocation(account); EnumSet<ACCOUNT_LOCATION> accountLocation = accountLocation(account);
if (accountLocation.contains(ACCOUNT_LOCATION.TOP)) { if (accountLocation.contains(ACCOUNT_LOCATION.TOP)) {
menu.findItem(R.id.move_up).setEnabled(false); menu.findItem(R.id.move_up).setEnabled(false);
} } else {
else {
menu.findItem(R.id.move_up).setEnabled(true); menu.findItem(R.id.move_up).setEnabled(true);
} }
if (accountLocation.contains(ACCOUNT_LOCATION.BOTTOM)) { if (accountLocation.contains(ACCOUNT_LOCATION.BOTTOM)) {
menu.findItem(R.id.move_down).setEnabled(false); menu.findItem(R.id.move_down).setEnabled(false);
} } else {
else {
menu.findItem(R.id.move_down).setEnabled(true); menu.findItem(R.id.move_down).setEnabled(true);
} }
} }
@ -1476,7 +1473,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
} }
@Override @Override
public void onNothingSelected(AdapterView<?> arg0) { /* Do nothing */ } public void onNothingSelected(AdapterView<?> arg0) {
/* Do nothing */
}
}); });
if (selection != null) { if (selection != null) {
@ -1507,7 +1506,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
int start = mImportContents.globalSettings ? 1 : 0; int start = mImportContents.globalSettings ? 1 : 0;
for (int i = start; i < count; i++) { for (int i = start; i < count; i++) {
if (pos.get(i)) { if (pos.get(i)) {
accountUuids.add(mImportContents.accounts.get(i-start).uuid); accountUuids.add(mImportContents.accounts.get(i - start).uuid);
} }
} }
@ -1853,7 +1852,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
} finally { } finally {
try { try {
is.close(); is.close();
} catch (IOException e) { /* Ignore */ } } catch (IOException e) {
/* Ignore */
}
} }
} catch (SettingsImportExportException e) { } catch (SettingsImportExportException e) {
Log.w(K9.LOG_TAG, "Exception during import", e); Log.w(K9.LOG_TAG, "Exception during import", e);
@ -1924,13 +1925,14 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
} finally { } finally {
try { try {
is.close(); is.close();
} catch (IOException e) { /* Ignore */ } } catch (IOException e) {
/* Ignore */
}
} }
} catch (SettingsImportExportException e) { } catch (SettingsImportExportException e) {
Log.w(K9.LOG_TAG, "Exception during export", e); Log.w(K9.LOG_TAG, "Exception during export", e);
return false; return false;
} } catch (FileNotFoundException e) {
catch (FileNotFoundException e) {
Log.w(K9.LOG_TAG, "Couldn't read content from URI " + mUri); Log.w(K9.LOG_TAG, "Couldn't read content from URI " + mUri);
return false; return false;
} }

View File

@ -367,8 +367,7 @@ public class FolderList extends K9ListActivity {
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
//Shortcuts that work no matter what is selected //Shortcuts that work no matter what is selected
switch (keyCode) { switch (keyCode) {
case KeyEvent.KEYCODE_Q: case KeyEvent.KEYCODE_Q: {
{
onAccounts(); onAccounts();
return true; return true;
} }

View File

@ -79,6 +79,8 @@ import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBody;
public class MessageCompose extends K9Activity implements OnClickListener, OnFocusChangeListener { public class MessageCompose extends K9Activity implements OnClickListener, OnFocusChangeListener {
private static final int DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE = 1; private static final int DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE = 1;
private static final int DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED = 2;
private static final int DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY = 3;
private static final String ACTION_COMPOSE = "com.fsck.k9.intent.action.COMPOSE"; private static final String ACTION_COMPOSE = "com.fsck.k9.intent.action.COMPOSE";
private static final String ACTION_REPLY = "com.fsck.k9.intent.action.REPLY"; private static final String ACTION_REPLY = "com.fsck.k9.intent.action.REPLY";
@ -112,6 +114,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private static final String STATE_REFERENCES = "com.fsck.k9.activity.MessageCompose.references"; private static final String STATE_REFERENCES = "com.fsck.k9.activity.MessageCompose.references";
private static final String STATE_KEY_MESSAGE_FORMAT = "com.fsck.k9.activity.MessageCompose.messageFormat"; private static final String STATE_KEY_MESSAGE_FORMAT = "com.fsck.k9.activity.MessageCompose.messageFormat";
private static final String STATE_KEY_READ_RECEIPT = "com.fsck.k9.activity.MessageCompose.messageReadReceipt"; private static final String STATE_KEY_READ_RECEIPT = "com.fsck.k9.activity.MessageCompose.messageReadReceipt";
private static final String STATE_KEY_DRAFT_NEEDS_SAVING = "com.fsck.k9.activity.MessageCompose.mDraftNeedsSaving";
private static final int MSG_PROGRESS_ON = 1; private static final int MSG_PROGRESS_ON = 1;
private static final int MSG_PROGRESS_OFF = 2; private static final int MSG_PROGRESS_OFF = 2;
@ -207,6 +210,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private ImageButton mAddBccFromContacts; private ImageButton mAddBccFromContacts;
private PgpData mPgpData = null; private PgpData mPgpData = null;
private boolean mAutoEncrypt = false;
private boolean mContinueWithoutPublicKey = false;
private String mReferences; private String mReferences;
private String mInReplyTo; private String mInReplyTo;
@ -218,6 +223,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private boolean mDraftNeedsSaving = false; private boolean mDraftNeedsSaving = false;
private boolean mPreventDraftSaving = false; private boolean mPreventDraftSaving = false;
private boolean mIgnoreOnStop = false;
/** /**
* The draft uid of this message. This is used when saving drafts so that the same draft is * The draft uid of this message. This is used when saving drafts so that the same draft is
* overwritten instead of being created anew. This property is null until the first save. * overwritten instead of being created anew. This property is null until the first save.
@ -441,6 +448,30 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
public void afterTextChanged(android.text.Editable s) { } public void afterTextChanged(android.text.Editable s) { }
}; };
// For watching changes to the To:, Cc:, and Bcc: fields for auto-encryption on a matching
// address.
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()) {
if (crypto.hasPublicKeyForEmail(getApplicationContext(),
address.getAddress())) {
mEncryptCheckbox.setChecked(true);
mContinueWithoutPublicKey = false;
break;
}
}
}
}
};
TextWatcher sigwatcher = new TextWatcher() { TextWatcher sigwatcher = new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, public void beforeTextChanged(CharSequence s, int start,
int before, int after) { } int before, int after) { }
@ -454,9 +485,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
public void afterTextChanged(android.text.Editable s) { } public void afterTextChanged(android.text.Editable s) { }
}; };
mToView.addTextChangedListener(watcher); mToView.addTextChangedListener(recipientWatcher);
mCcView.addTextChangedListener(watcher); mCcView.addTextChangedListener(recipientWatcher);
mBccView.addTextChangedListener(watcher); mBccView.addTextChangedListener(recipientWatcher);
mSubjectView.addTextChangedListener(watcher); mSubjectView.addTextChangedListener(watcher);
mMessageContentView.addTextChangedListener(watcher); mMessageContentView.addTextChangedListener(watcher);
@ -615,6 +646,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mCryptoSignatureUserId = (TextView)findViewById(R.id.userId); mCryptoSignatureUserId = (TextView)findViewById(R.id.userId);
mCryptoSignatureUserIdRest = (TextView)findViewById(R.id.userIdRest); mCryptoSignatureUserIdRest = (TextView)findViewById(R.id.userIdRest);
mEncryptCheckbox = (CheckBox)findViewById(R.id.cb_encrypt); 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(); initializeCrypto();
final CryptoProvider crypto = mAccount.getCryptoProvider(); final CryptoProvider crypto = mAccount.getCryptoProvider();
@ -648,6 +684,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
} }
} }
updateEncryptLayout(); updateEncryptLayout();
mAutoEncrypt = mAccount.isCryptoAutoEncrypt();
} else { } else {
mEncryptLayout.setVisibility(View.GONE); mEncryptLayout.setVisibility(View.GONE);
} }
@ -681,8 +718,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
* Dear developer, if your application is using those EXTRAs you're doing * Dear developer, if your application is using those EXTRAs you're doing
* it wrong! So go fix your program or get AOSP to change the documentation. * it wrong! So go fix your program or get AOSP to change the documentation.
*/ */
} } else if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
else if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
/* /*
* Note: Here we allow a slight deviation from the documentated behavior. * Note: Here we allow a slight deviation from the documentated behavior.
* EXTRA_TEXT is used as message body (if available) regardless of the MIME * EXTRA_TEXT is used as message body (if available) regardless of the MIME
@ -773,6 +809,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mCryptoSignatureUserId.setVisibility(View.INVISIBLE); mCryptoSignatureUserId.setVisibility(View.INVISIBLE);
mCryptoSignatureUserIdRest.setVisibility(View.INVISIBLE); mCryptoSignatureUserIdRest.setVisibility(View.INVISIBLE);
} else { } else {
mMessageFormat = MessageFormat.TEXT;
// if a signature key is selected, then the checkbox itself has no text // if a signature key is selected, then the checkbox itself has no text
mCryptoSignatureCheckbox.setText(""); mCryptoSignatureCheckbox.setText("");
mCryptoSignatureCheckbox.setChecked(true); mCryptoSignatureCheckbox.setChecked(true);
@ -800,14 +837,23 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
mIgnoreOnStop = false;
MessagingController.getInstance(getApplication()).addListener(mListener); MessagingController.getInstance(getApplication()).addListener(mListener);
} }
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
saveIfNeeded();
MessagingController.getInstance(getApplication()).removeListener(mListener); MessagingController.getInstance(getApplication()).removeListener(mListener);
// Save email as draft when activity is changed (go to home screen, call received) or screen locked
// don't do this if only changing orientations
if ((getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
// don't do this if selecting signature or if "Encrypt" is checked or if adding an attachment
if (!mPreventDraftSaving && !mEncryptCheckbox.isChecked() && !mIgnoreOnStop) {
saveIfNeeded();
finish();
}
}
} }
/** /**
@ -821,7 +867,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
@Override @Override
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
saveIfNeeded();
ArrayList<Uri> attachments = new ArrayList<Uri>(); ArrayList<Uri> attachments = new ArrayList<Uri>();
for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) { for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) {
View view = mAttachments.getChildAt(i); View view = mAttachments.getChildAt(i);
@ -842,6 +887,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
outState.putSerializable(STATE_KEY_HTML_QUOTE, mQuotedHtmlContent); outState.putSerializable(STATE_KEY_HTML_QUOTE, mQuotedHtmlContent);
outState.putSerializable(STATE_KEY_MESSAGE_FORMAT, mMessageFormat); outState.putSerializable(STATE_KEY_MESSAGE_FORMAT, mMessageFormat);
outState.putBoolean(STATE_KEY_READ_RECEIPT, mReadReceipt); outState.putBoolean(STATE_KEY_READ_RECEIPT, mReadReceipt);
outState.putBoolean(STATE_KEY_DRAFT_NEEDS_SAVING, mDraftNeedsSaving);
} }
@Override @Override
@ -875,13 +921,13 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mPgpData = (PgpData) savedInstanceState.getSerializable(STATE_PGP_DATA); mPgpData = (PgpData) savedInstanceState.getSerializable(STATE_PGP_DATA);
mInReplyTo = savedInstanceState.getString(STATE_IN_REPLY_TO); mInReplyTo = savedInstanceState.getString(STATE_IN_REPLY_TO);
mReferences = savedInstanceState.getString(STATE_REFERENCES); mReferences = savedInstanceState.getString(STATE_REFERENCES);
mDraftNeedsSaving = savedInstanceState.getBoolean(STATE_KEY_DRAFT_NEEDS_SAVING);
initializeCrypto(); initializeCrypto();
updateFrom(); updateFrom();
updateSignature(); updateSignature();
updateEncryptLayout(); updateEncryptLayout();
mDraftNeedsSaving = false;
} }
private void updateTitle() { private void updateTitle() {
@ -916,6 +962,16 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
return Address.parseUnencoded(view.getText().toString().trim()); return Address.parseUnencoded(view.getText().toString().trim());
} }
/*
* Returns an Address array of recipients this email will be sent to.
* @return Address array of recipients this email will be sent to.
*/
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 * 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 * include it later. Draft messages are treated somewhat differently in that signatures are not
@ -957,7 +1013,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
// Place the signature immediately after the reply. // Place the signature immediately after the reply.
if (!isDraft) { if (!isDraft) {
if (mQuoteStyle == QuoteStyle.HEADER || replyAfterQuote || mAccount.isSignatureBeforeQuotedText()) { if (mQuoteStyle == QuoteStyle.HEADER || replyAfterQuote || mAccount.isSignatureBeforeQuotedText()) {
Log.d("ASH", "appending signature after new content");
text = appendSignature(text); text = appendSignature(text);
} }
} }
@ -1412,7 +1467,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
String signature = ""; String signature = "";
if (mIdentity.getSignatureUse()) { if (mIdentity.getSignatureUse()) {
signature = mSignatureView.getText().toString(); signature = mSignatureView.getText().toString();
if(!StringUtils.isNullOrEmpty(signature)) { if (!StringUtils.isNullOrEmpty(signature)) {
signature = HtmlConverter.textToHtmlFragment("\n" + signature); signature = HtmlConverter.textToHtmlFragment("\n" + signature);
} }
} }
@ -1427,7 +1482,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
} }
private void saveIfNeeded() { private void saveIfNeeded() {
if (!mDraftNeedsSaving || mPreventDraftSaving || mPgpData.hasEncryptionKeys()) { if (!mDraftNeedsSaving || mPreventDraftSaving || mPgpData.hasEncryptionKeys() ||
mEncryptCheckbox.isChecked()) {
return; return;
} }
@ -1457,19 +1513,20 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
Toast.makeText(this, getString(R.string.message_compose_error_no_recipients), Toast.LENGTH_LONG).show(); Toast.makeText(this, getString(R.string.message_compose_error_no_recipients), Toast.LENGTH_LONG).show();
return; return;
} }
final CryptoProvider crypto = mAccount.getCryptoProvider();
if (mEncryptCheckbox.isChecked() && !mPgpData.hasEncryptionKeys()) { if (mEncryptCheckbox.isChecked() && !mPgpData.hasEncryptionKeys()) {
mMessageFormat = MessageFormat.TEXT;
// key selection before encryption // key selection before encryption
StringBuilder emails = new StringBuilder(); StringBuilder emails = new StringBuilder();
Address[][] addresses = new Address[][] { getAddresses(mToView), for (Address address : getRecipientAddresses()) {
getAddresses(mCcView),
getAddresses(mBccView)
};
for (Address[] addressArray : addresses) {
for (Address address : addressArray) {
if (emails.length() != 0) { if (emails.length() != 0) {
emails.append(','); emails.append(',');
} }
emails.append(address.getAddress()); emails.append(address.getAddress());
if (!mContinueWithoutPublicKey &&
!crypto.hasPublicKeyForEmail(this, address.getAddress())) {
showDialog(DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY);
return;
} }
} }
if (emails.length() != 0) { if (emails.length() != 0) {
@ -1478,7 +1535,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
emails.append(mIdentity.getEmail()); emails.append(mIdentity.getEmail());
mPreventDraftSaving = true; mPreventDraftSaving = true;
if (!mAccount.getCryptoProvider().selectEncryptionKeys(MessageCompose.this, emails.toString(), mPgpData)) { if (!crypto.selectEncryptionKeys(MessageCompose.this, emails.toString(), mPgpData)) {
mPreventDraftSaving = false; mPreventDraftSaving = false;
} }
return; return;
@ -1487,7 +1544,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
if (mPgpData.getEncryptedData() == null) { if (mPgpData.getEncryptedData() == null) {
String text = buildText(false).getText(); String text = buildText(false).getText();
mPreventDraftSaving = true; mPreventDraftSaving = true;
if (!mAccount.getCryptoProvider().encrypt(this, text, mPgpData)) { if (!crypto.encrypt(this, text, mPgpData)) {
mPreventDraftSaving = false; mPreventDraftSaving = false;
} }
return; return;
@ -1520,7 +1577,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
} }
private void onSave() { private void onSave() {
mDraftNeedsSaving = true;
saveIfNeeded(); saveIfNeeded();
finish(); finish();
} }
@ -1547,6 +1603,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
* Kick off a picker for whatever kind of MIME types we'll accept and let Android take over. * Kick off a picker for whatever kind of MIME types we'll accept and let Android take over.
*/ */
private void onAddAttachment() { private void onAddAttachment() {
mIgnoreOnStop = true;
if (K9.isGalleryBuggy()) { if (K9.isGalleryBuggy()) {
if (K9.useGalleryBugWorkaround()) { if (K9.useGalleryBugWorkaround()) {
Toast.makeText(MessageCompose.this, Toast.makeText(MessageCompose.this,
@ -1853,7 +1910,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
onSend(); onSend();
break; break;
case R.id.save: case R.id.save:
if (mEncryptCheckbox.isChecked()) {
showDialog(DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED);
} else {
onSave(); onSave();
}
break; break;
case R.id.discard: case R.id.discard:
onDiscard(); onDiscard();
@ -1927,7 +1988,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (mDraftNeedsSaving) { if (mEncryptCheckbox.isChecked()) {
showDialog(DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED);
} else if (mDraftNeedsSaving) {
showDialog(DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE); showDialog(DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE);
} else { } else {
super.onBackPressed(); super.onBackPressed();
@ -1954,6 +2017,34 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
} }
}) })
.create(); .create();
case DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED:
return new AlertDialog.Builder(this)
.setTitle(R.string.refuse_to_save_draft_marked_encrypted_dlg_title)
.setMessage(R.string.refuse_to_save_draft_marked_encrypted_instructions_fmt)
.setNeutralButton(R.string.okay_action, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dismissDialog(DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED);
}
})
.create();
case DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY:
return new AlertDialog.Builder(this)
.setTitle(R.string.continue_without_public_key_dlg_title)
.setMessage(R.string.continue_without_public_key_instructions_fmt)
.setPositiveButton(R.string.continue_action, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dismissDialog(DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY);
mContinueWithoutPublicKey = true;
onSend();
}
})
.setNegativeButton(R.string.back_action, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dismissDialog(DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY);
mContinueWithoutPublicKey = false;
}
})
.create();
} }
return super.onCreateDialog(id); return super.onCreateDialog(id);
} }
@ -2390,10 +2481,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
List<Integer> start = new ArrayList<Integer>(); List<Integer> start = new ArrayList<Integer>();
List<Integer> end = new ArrayList<Integer>(); List<Integer> end = new ArrayList<Integer>();
while(blockquoteStart.find()) { while (blockquoteStart.find()) {
start.add(blockquoteStart.start()); start.add(blockquoteStart.start());
} }
while(blockquoteEnd.find()) { while (blockquoteEnd.find()) {
end.add(blockquoteEnd.start()); end.add(blockquoteEnd.start());
} }
if (start.size() != end.size()) { if (start.size() != end.size()) {
@ -2408,8 +2499,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
} else { } else {
for (int i = 0; i < start.size() - 1; i++) { for (int i = 0; i < start.size() - 1; i++) {
// within blockquotes. // within blockquotes.
if (end.get(i) < start.get(i+1)) { if (end.get(i) < start.get(i + 1)) {
dashSignatureHtml.region(end.get(i), start.get(i+1)); dashSignatureHtml.region(end.get(i), start.get(i + 1));
if (dashSignatureHtml.find()) { if (dashSignatureHtml.find()) {
content = content.substring(0, dashSignatureHtml.start()); content = content.substring(0, dashSignatureHtml.start());
break; break;
@ -2824,7 +2915,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private class SaveMessageTask extends AsyncTask<Void, Void, Void> { private class SaveMessageTask extends AsyncTask<Void, Void, Void> {
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
/* /*
* Create the message from all the data the user has entered. * Create the message from all the data the user has entered.
*/ */
@ -2855,10 +2945,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
Message draftMessage = messagingController.saveDraft(mAccount, message); Message draftMessage = messagingController.saveDraft(mAccount, message);
mDraftUid = draftMessage.getUid(); mDraftUid = draftMessage.getUid();
// Don't display the toast if the user is just changing the orientation
if ((getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
mHandler.sendEmptyMessage(MSG_SAVED_DRAFT); mHandler.sendEmptyMessage(MSG_SAVED_DRAFT);
}
return null; return null;
} }
} }

View File

@ -92,7 +92,9 @@ public class MessageView extends K9Activity implements OnClickListener {
} }
@Override @Override
public void onMount(String providerId) { /* no-op */ } public void onMount(String providerId) {
/* no-op */
}
} }
@ -117,7 +119,7 @@ public class MessageView extends K9Activity implements OnClickListener {
public boolean dispatchKeyEvent(KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) {
boolean ret = false; boolean ret = false;
if (KeyEvent.ACTION_DOWN == event.getAction()) { if (KeyEvent.ACTION_DOWN == event.getAction()) {
ret = onKeyDown(event.getKeyCode(), event); ret = onCustomKeyDown(event.getKeyCode(), event);
} }
if (!ret) { if (!ret) {
ret = super.dispatchKeyEvent(event); ret = super.dispatchKeyEvent(event);
@ -125,29 +127,36 @@ public class MessageView extends K9Activity implements OnClickListener {
return ret; return ret;
} }
@Override /**
public boolean onKeyDown(final int keyCode, final KeyEvent event) { * Handle hotkeys
if ( *
// XXX TODO - when we go to android 2.0, uncomment this * <p>
// android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR && * This method is called by {@link #dispatchKeyEvent(KeyEvent)} before any view had the chance
keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { * to consume this key event.
// Take care of calling this method on earlier versions of * </p>
// the platform where it doesn't exist. *
onBackPressed(); * @param keyCode
return true; * The value in {@code event.getKeyCode()}.
} * @param event
* Description of the key event.
*
* @return {@code true} if this event was consumed.
*/
public boolean onCustomKeyDown(final int keyCode, final KeyEvent event) {
switch (keyCode) { switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP: { case KeyEvent.KEYCODE_VOLUME_UP: {
if (K9.useVolumeKeysForNavigationEnabled()) { if (K9.useVolumeKeysForNavigationEnabled()) {
onNext(); onNext();
return true; return true;
} }
break;
} }
case KeyEvent.KEYCODE_VOLUME_DOWN: { case KeyEvent.KEYCODE_VOLUME_DOWN: {
if (K9.useVolumeKeysForNavigationEnabled()) { if (K9.useVolumeKeysForNavigationEnabled()) {
onPrevious(); onPrevious();
return true; return true;
} }
break;
} }
case KeyEvent.KEYCODE_SHIFT_LEFT: case KeyEvent.KEYCODE_SHIFT_LEFT:
case KeyEvent.KEYCODE_SHIFT_RIGHT: { case KeyEvent.KEYCODE_SHIFT_RIGHT: {
@ -222,7 +231,7 @@ public class MessageView extends K9Activity implements OnClickListener {
return true; return true;
} }
} }
return super.onKeyDown(keyCode, event); return false;
} }
@Override @Override

View File

@ -96,6 +96,7 @@ public class AccountSettings extends K9PreferenceActivity {
private static final String PREFERENCE_SYNC_REMOTE_DELETIONS = "account_sync_remote_deletetions"; 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_APP = "crypto_app";
private static final String PREFERENCE_CRYPTO_AUTO_SIGNATURE = "crypto_auto_signature"; 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_LOCAL_STORAGE_PROVIDER = "local_storage_provider"; private static final String PREFERENCE_LOCAL_STORAGE_PROVIDER = "local_storage_provider";
@ -160,6 +161,7 @@ public class AccountSettings extends K9PreferenceActivity {
private ListPreference mMaxPushFolders; private ListPreference mMaxPushFolders;
private ListPreference mCryptoApp; private ListPreference mCryptoApp;
private CheckBoxPreference mCryptoAutoSignature; private CheckBoxPreference mCryptoAutoSignature;
private CheckBoxPreference mCryptoAutoEncrypt;
private ListPreference mLocalStorageProvider; private ListPreference mLocalStorageProvider;
@ -540,8 +542,8 @@ public class AccountSettings extends K9PreferenceActivity {
}); });
} else { } else {
PreferenceScreen incomingPrefs = (PreferenceScreen) findPreference(PREFERENCE_SCREEN_INCOMING); PreferenceScreen incomingPrefs = (PreferenceScreen) findPreference(PREFERENCE_SCREEN_INCOMING);
incomingPrefs.removePreference( (PreferenceScreen) findPreference(PREFERENCE_SCREEN_PUSH_ADVANCED)); incomingPrefs.removePreference((PreferenceScreen) findPreference(PREFERENCE_SCREEN_PUSH_ADVANCED));
incomingPrefs.removePreference( (ListPreference) findPreference(PREFERENCE_PUSH_MODE)); incomingPrefs.removePreference((ListPreference) findPreference(PREFERENCE_PUSH_MODE));
} }
mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY); mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY);
@ -680,14 +682,19 @@ public class AccountSettings extends K9PreferenceActivity {
mCryptoAutoSignature = (CheckBoxPreference) findPreference(PREFERENCE_CRYPTO_AUTO_SIGNATURE); mCryptoAutoSignature = (CheckBoxPreference) findPreference(PREFERENCE_CRYPTO_AUTO_SIGNATURE);
mCryptoAutoSignature.setChecked(mAccount.getCryptoAutoSignature()); mCryptoAutoSignature.setChecked(mAccount.getCryptoAutoSignature());
mCryptoAutoEncrypt = (CheckBoxPreference) findPreference(PREFERENCE_CRYPTO_AUTO_ENCRYPT);
mCryptoAutoEncrypt.setChecked(mAccount.isCryptoAutoEncrypt());
handleCryptoAppDependencies(); handleCryptoAppDependencies();
} }
private void handleCryptoAppDependencies() { private void handleCryptoAppDependencies() {
if ("".equals(mCryptoApp.getValue())) { if ("".equals(mCryptoApp.getValue())) {
mCryptoAutoSignature.setEnabled(false); mCryptoAutoSignature.setEnabled(false);
mCryptoAutoEncrypt.setEnabled(false);
} else { } else {
mCryptoAutoSignature.setEnabled(true); mCryptoAutoSignature.setEnabled(true);
mCryptoAutoEncrypt.setEnabled(true);
} }
} }
@ -733,6 +740,7 @@ public class AccountSettings extends K9PreferenceActivity {
mAccount.setStripSignature(mStripSignature.isChecked()); mAccount.setStripSignature(mStripSignature.isChecked());
mAccount.setCryptoApp(mCryptoApp.getValue()); mAccount.setCryptoApp(mCryptoApp.getValue());
mAccount.setCryptoAutoSignature(mCryptoAutoSignature.isChecked()); mAccount.setCryptoAutoSignature(mCryptoAutoSignature.isChecked());
mAccount.setCryptoAutoEncrypt(mCryptoAutoEncrypt.isChecked());
mAccount.setLocalStorageProviderId(mLocalStorageProvider.getValue()); mAccount.setLocalStorageProviderId(mLocalStorageProvider.getValue());
// In webdav account we use the exact folder name also for inbox, // In webdav account we use the exact folder name also for inbox,

View File

@ -232,6 +232,95 @@ public class Apg extends CryptoProvider {
return ids; 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;
}
/**
* Find out if a given email has a secret key.
*
* @param context
* @param email The email in question.
* @return true if there is a secret key for this email.
*/
@Override
public boolean hasSecretKeyForEmail(Context context, String email) {
try {
Uri contentUri = Uri.withAppendedPath(Apg.CONTENT_URI_SECRET_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) {
c.close();
return true;
}
if (c != null) {
c.close();
}
} catch (SecurityException e) {
Toast.makeText(context,
context.getResources().getString(R.string.insufficient_apg_permissions),
Toast.LENGTH_LONG).show();
}
return false;
}
/**
* Find out if a given email has a public key.
*
* @param context
* @param email The email in question.
* @return true if there is a public key for this email.
*/
@Override
public boolean hasPublicKeyForEmail(Context context, String email) {
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) {
c.close();
return true;
}
if (c != null) {
c.close();
}
} catch (SecurityException e) {
Toast.makeText(context,
context.getResources().getString(R.string.insufficient_apg_permissions),
Toast.LENGTH_LONG).show();
}
return false;
}
/** /**
* Get the user id based on the key id. * Get the user id based on the key id.
* *

View File

@ -24,6 +24,9 @@ abstract public class CryptoProvider {
abstract public boolean encrypt(Activity activity, String data, PgpData pgpData); abstract public boolean encrypt(Activity activity, String data, PgpData pgpData);
abstract public boolean decrypt(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[] getSecretKeyIdsFromEmail(Context context, String email);
abstract public long[] getPublicKeyIdsFromEmail(Context context, String email);
abstract public boolean hasSecretKeyForEmail(Context context, String email);
abstract public boolean hasPublicKeyForEmail(Context context, String email);
abstract public String getUserId(Context context, long keyId); abstract public String getUserId(Context context, long keyId);
abstract public String getName(); abstract public String getName();
abstract public boolean test(Context context); abstract public boolean test(Context context);

View File

@ -37,6 +37,21 @@ public class None extends CryptoProvider {
return null; return null;
} }
@Override
public long[] getPublicKeyIdsFromEmail(Context context, String email) {
return null;
}
@Override
public boolean hasSecretKeyForEmail(Context context, String email) {
return false;
}
@Override
public boolean hasPublicKeyForEmail(Context context, String email) {
return false;
}
@Override @Override
public String getUserId(Context context, long keyId) { public String getUserId(Context context, long keyId) {
return null; return null;

View File

@ -2,7 +2,7 @@ package com.fsck.k9.helper;
public final class StringUtils { public final class StringUtils {
public static boolean isNullOrEmpty(String string){ public static boolean isNullOrEmpty(String string) {
return string == null || string.length() == 0; return string == null || string.length() == 0;
} }

View File

@ -151,7 +151,7 @@ public class Address {
} catch (MimeException pe) { } catch (MimeException pe) {
Log.e(K9.LOG_TAG, "MimeException in Address.parse()", pe); Log.e(K9.LOG_TAG, "MimeException in Address.parse()", pe);
//but we do an silent failover : we just use the given string as name with empty address //but we do an silent failover : we just use the given string as name with empty address
addresses.add(new Address(null, addressList,false)); addresses.add(new Address(null, addressList, false));
} }
return addresses.toArray(EMPTY_ADDRESS_ARRAY); return addresses.toArray(EMPTY_ADDRESS_ARRAY);
} }

View File

@ -10,9 +10,9 @@ import java.io.InputStream;
* past where the protocol handler intended the client to read. * past where the protocol handler intended the client to read.
*/ */
public class FixedLengthInputStream extends InputStream { public class FixedLengthInputStream extends InputStream {
private InputStream mIn; private final InputStream mIn;
private int mLength; private final int mLength;
private int mCount; private int mCount = 0;
public FixedLengthInputStream(InputStream in, int length) { public FixedLengthInputStream(InputStream in, int length) {
this.mIn = in; this.mIn = in;
@ -26,34 +26,44 @@ public class FixedLengthInputStream extends InputStream {
@Override @Override
public int read() throws IOException { public int read() throws IOException {
if (mCount < mLength) { if (mCount >= mLength) {
mCount++;
return mIn.read();
} else {
return -1; return -1;
} }
int d = mIn.read();
if (d != -1) {
mCount++;
}
return d;
} }
@Override @Override
public int read(byte[] b, int offset, int length) throws IOException { public int read(byte[] b, int offset, int length) throws IOException {
if (mCount < mLength) { if (mCount >= mLength) {
return -1;
}
int d = mIn.read(b, offset, Math.min(mLength - mCount, length)); int d = mIn.read(b, offset, Math.min(mLength - mCount, length));
if (d == -1) { if (d != -1) {
return -1;
} else {
mCount += d; mCount += d;
}
return d; return d;
} }
} else {
return -1;
}
}
@Override @Override
public int read(byte[] b) throws IOException { public int read(byte[] b) throws IOException {
return read(b, 0, b.length); return read(b, 0, b.length);
} }
@Override
public long skip(long n) throws IOException {
long d = mIn.skip(Math.min(n, available()));
if (d > 0) {
mCount += d;
}
return d;
}
@Override @Override
public String toString() { public String toString() {
return String.format("FixedLengthInputStream(in=%s, length=%d)", mIn.toString(), mLength); return String.format("FixedLengthInputStream(in=%s, length=%d)", mIn.toString(), mLength);

View File

@ -109,7 +109,10 @@ public class MimeHeader {
v = EncoderUtil.encodeEncodedWord(field.value, charset); v = EncoderUtil.encodeEncodedWord(field.value, charset);
} }
writer.write(field.name + ": " + v + "\r\n"); writer.write(field.name);
writer.write(": ");
writer.write(v);
writer.write("\r\n");
} }
} }
writer.flush(); writer.flush();

View File

@ -70,22 +70,29 @@ public class MimeMultipart extends Multipart {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
if (mPreamble != null) { if (mPreamble != null) {
writer.write(mPreamble + "\r\n"); writer.write(mPreamble);
writer.write("\r\n");
} }
if (mParts.isEmpty()) { if (mParts.isEmpty()) {
writer.write("--" + mBoundary + "\r\n"); writer.write("--");
writer.write(mBoundary);
writer.write("\r\n");
} }
for (int i = 0, count = mParts.size(); i < count; i++) { for (int i = 0, count = mParts.size(); i < count; i++) {
BodyPart bodyPart = mParts.get(i); BodyPart bodyPart = mParts.get(i);
writer.write("--" + mBoundary + "\r\n"); writer.write("--");
writer.write(mBoundary);
writer.write("\r\n");
writer.flush(); writer.flush();
bodyPart.writeTo(out); bodyPart.writeTo(out);
writer.write("\r\n"); writer.write("\r\n");
} }
writer.write("--" + mBoundary + "--\r\n"); writer.write("--");
writer.write(mBoundary);
writer.write("--\r\n");
writer.flush(); writer.flush();
} }

View File

@ -888,7 +888,8 @@ public class MimeUtility {
*/ */
private static final String[][] MIME_TYPE_REPLACEMENT_MAP = new String[][] { private static final String[][] MIME_TYPE_REPLACEMENT_MAP = new String[][] {
{"image/jpg", "image/jpeg"}, {"image/jpg", "image/jpeg"},
{"image/pjpeg", "image/jpeg"} // see issue 1712 {"image/pjpeg", "image/jpeg"}, // see issue 1712
{"application/x-zip-compressed", "application/zip"} // see issue 3791
}; };
public static String unfold(String s) { public static String unfold(String s) {

View File

@ -89,15 +89,15 @@ public class EasStore extends Store {
// Command timeout is the the time allowed for reading data from an open connection before an // Command timeout is the the time allowed for reading data from an open connection before an
// IOException is thrown. After a small added allowance, our watchdog alarm goes off (allowing // IOException is thrown. After a small added allowance, our watchdog alarm goes off (allowing
// us to detect a silently dropped connection). The allowance is defined below. // us to detect a silently dropped connection). The allowance is defined below.
static private final int COMMAND_TIMEOUT = 30*1000; static private final int COMMAND_TIMEOUT = 30 * 1000;
// Connection timeout is the time given to connect to the server before reporting an IOException // Connection timeout is the time given to connect to the server before reporting an IOException
static private final int CONNECTION_TIMEOUT = 20*1000; static private final int CONNECTION_TIMEOUT = 20 * 1000;
// This needs to be long enough to send the longest reasonable message, without being so long // This needs to be long enough to send the longest reasonable message, without being so long
// as to effectively "hang" sending of mail. The standard 30 second timeout isn't long enough // as to effectively "hang" sending of mail. The standard 30 second timeout isn't long enough
// for pictures and the like. For now, we'll use 15 minutes, in the knowledge that any socket // for pictures and the like. For now, we'll use 15 minutes, in the knowledge that any socket
// failure would probably generate an Exception before timing out anyway // failure would probably generate an Exception before timing out anyway
public static final int SEND_MAIL_TIMEOUT = 15*60*1000; public static final int SEND_MAIL_TIMEOUT = 15 * 60 * 1000;
// MSFT's custom HTTP result code indicating the need to provision // MSFT's custom HTTP result code indicating the need to provision
static private final int HTTP_NEED_PROVISIONING = 449; static private final int HTTP_NEED_PROVISIONING = 449;
@ -592,7 +592,7 @@ public class EasStore extends Store {
} }
@Override @Override
public List <? extends Folder> getPersonalNamespaces(boolean forceListAll) throws MessagingException { public List <? extends Folder > getPersonalNamespaces(boolean forceListAll) throws MessagingException {
if (forceListAll || getStoreSyncKey().equals(INITIAL_SYNC_KEY)) { if (forceListAll || getStoreSyncKey().equals(INITIAL_SYNC_KEY)) {
if (forceListAll) { if (forceListAll) {
// Reset the sync key so the Exchange server will return the entire folder list // Reset the sync key so the Exchange server will return the entire folder list
@ -737,7 +737,7 @@ public class EasStore extends Store {
try { try {
LocalStore localStore = mAccount.getLocalStore(); LocalStore localStore = mAccount.getLocalStore();
if (localStore != null) { if (localStore != null) {
List<? extends Folder> localFolders = localStore.getPersonalNamespaces(false); List <? extends Folder > localFolders = localStore.getPersonalNamespaces(false);
synchronized (mFolderList) { synchronized (mFolderList) {
for (Folder folder : localFolders) { for (Folder folder : localFolders) {
int type = FolderSyncParser.USER_FOLDER_TYPE; int type = FolderSyncParser.USER_FOLDER_TYPE;
@ -767,8 +767,7 @@ public class EasStore extends Store {
if (getStoreSyncKey().equals(INITIAL_SYNC_KEY)) { if (getStoreSyncKey().equals(INITIAL_SYNC_KEY)) {
try { try {
getInitialFolderList(); getInitialFolderList();
} } catch (MessagingException e) {
catch (MessagingException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -1289,7 +1288,7 @@ public class EasStore extends Store {
} }
s.end(); s.end();
} }
}.send(this); } .send(this);
} }
private void deleteServerMessages(final String[] uids) throws MessagingException { private void deleteServerMessages(final String[] uids) throws MessagingException {
@ -1306,7 +1305,7 @@ public class EasStore extends Store {
} }
s.end(); s.end();
} }
}.send(this); } .send(this);
} }
@Override @Override
@ -1586,7 +1585,7 @@ public class EasStore extends Store {
.start(Tags.SYNC_COLLECTION) .start(Tags.SYNC_COLLECTION)
.data(Tags.SYNC_CLASS, className) .data(Tags.SYNC_CLASS, className)
.data(Tags.SYNC_SYNC_KEY, syncKey) .data(Tags.SYNC_SYNC_KEY, syncKey)
.data(Tags.SYNC_COLLECTION_ID, folderServerId ); .data(Tags.SYNC_COLLECTION_ID, folderServerId);
prepareCommand(s); prepareCommand(s);

View File

@ -244,8 +244,7 @@ public class ImapStore extends Store {
userEnc = URLEncoder.encode(server.username, "UTF-8"); userEnc = URLEncoder.encode(server.username, "UTF-8");
passwordEnc = (server.password != null) ? passwordEnc = (server.password != null) ?
URLEncoder.encode(server.password, "UTF-8") : ""; URLEncoder.encode(server.password, "UTF-8") : "";
} } catch (UnsupportedEncodingException e) {
catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Could not encode username or password", e); throw new IllegalArgumentException("Could not encode username or password", e);
} }
@ -280,9 +279,9 @@ public class ImapStore extends Store {
String userInfo = authType.toString() + ":" + userEnc + ":" + passwordEnc; String userInfo = authType.toString() + ":" + userEnc + ":" + passwordEnc;
try { try {
Map<String, String> extra = server.getExtra(); Map<String, String> extra = server.getExtra();
String prefix = (extra != null) ? extra.get(ImapStoreSettings.PATH_PREFIX_KEY) : null; String path = (extra != null) ? "/" + extra.get(ImapStoreSettings.PATH_PREFIX_KEY) : null;
return new URI(scheme, userInfo, server.host, server.port, return new URI(scheme, userInfo, server.host, server.port,
prefix, path,
null, null).toString(); null, null).toString();
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
throw new IllegalArgumentException("Can't create ImapStore URI", e); throw new IllegalArgumentException("Can't create ImapStore URI", e);
@ -613,7 +612,7 @@ public class ImapStore extends Store {
if (connection.capabilities.contains("XLIST")) { if (connection.capabilities.contains("XLIST")) {
if (K9.DEBUG) Log.d(K9.LOG_TAG, "Folder auto-configuration: Using XLIST."); if (K9.DEBUG) Log.d(K9.LOG_TAG, "Folder auto-configuration: Using XLIST.");
commandResponse = "XLIST"; commandResponse = "XLIST";
} else if(connection.capabilities.contains("SPECIAL-USE")) { } else if (connection.capabilities.contains("SPECIAL-USE")) {
if (K9.DEBUG) Log.d(K9.LOG_TAG, "Folder auto-configuration: Using RFC6154/SPECIAL-USE."); if (K9.DEBUG) Log.d(K9.LOG_TAG, "Folder auto-configuration: Using RFC6154/SPECIAL-USE.");
commandResponse = "LIST"; commandResponse = "LIST";
commandOptions = " (SPECIAL-USE)"; commandOptions = " (SPECIAL-USE)";

View File

@ -301,8 +301,7 @@ public class LocalStore extends Store implements Serializable {
Log.e(K9.LOG_TAG, " error trying to ugpgrade a folder class", e); Log.e(K9.LOG_TAG, " error trying to ugpgrade a folder class", e);
} }
} }
} } catch (SQLiteException e) {
catch (SQLiteException e) {
Log.e(K9.LOG_TAG, "Exception while upgrading database to v41. folder classes may have vanished", e); Log.e(K9.LOG_TAG, "Exception while upgrading database to v41. folder classes may have vanished", e);
} finally { } finally {
@ -373,8 +372,7 @@ public class LocalStore extends Store implements Serializable {
} }
} }
} }
} } catch (SQLiteException e) {
catch (SQLiteException e) {
Log.e(K9.LOG_TAG, "Exception while upgrading database. Resetting the DB to v0"); Log.e(K9.LOG_TAG, "Exception while upgrading database. Resetting the DB to v0");
db.setVersion(0); db.setVersion(0);
throw new Error("Database upgrade failed! Resetting your DB version to 0 to force a full schema recreation."); throw new Error("Database upgrade failed! Resetting your DB version to 0 to force a full schema recreation.");
@ -2399,7 +2397,9 @@ public class LocalStore extends Store implements Serializable {
if (s != null) { if (s != null) {
try { try {
size = Integer.parseInt(s); size = Integer.parseInt(s);
} catch (NumberFormatException e) { /* Ignore */ } } catch (NumberFormatException e) {
/* Ignore */
}
} }
} }
} }
@ -2829,7 +2829,7 @@ public class LocalStore extends Store implements Serializable {
mLastUid = lastUid; mLastUid = lastUid;
} }
public long getOldestMessageDate() throws MessagingException { public Long getOldestMessageDate() throws MessagingException {
return database.execute(false, new DbCallback<Long>() { return database.execute(false, new DbCallback<Long>() {
@Override @Override
public Long doDbWork(final SQLiteDatabase db) { public Long doDbWork(final SQLiteDatabase db) {

View File

@ -117,7 +117,7 @@ public class Pop3Store extends Store {
int userIndex = 0, passwordIndex = 1; int userIndex = 0, passwordIndex = 1;
String userinfo = pop3Uri.getUserInfo(); String userinfo = pop3Uri.getUserInfo();
String[] userInfoParts = userinfo.split(":"); String[] userInfoParts = userinfo.split(":");
if (userInfoParts.length > 2 || userinfo.endsWith(":") ) { if (userInfoParts.length > 2 || userinfo.endsWith(":")) {
// If 'userinfo' ends with ":" the password is empty. This can only happen // If 'userinfo' ends with ":" the password is empty. This can only happen
// after an account was imported (so authType and username are present). // after an account was imported (so authType and username are present).
userIndex++; userIndex++;
@ -156,8 +156,7 @@ public class Pop3Store extends Store {
userEnc = URLEncoder.encode(server.username, "UTF-8"); userEnc = URLEncoder.encode(server.username, "UTF-8");
passwordEnc = (server.password != null) ? passwordEnc = (server.password != null) ?
URLEncoder.encode(server.password, "UTF-8") : ""; URLEncoder.encode(server.password, "UTF-8") : "";
} } catch (UnsupportedEncodingException e) {
catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Could not encode username or password", e); throw new IllegalArgumentException("Could not encode username or password", e);
} }

View File

@ -206,8 +206,7 @@ public class WebDavStore extends Store {
userEnc = URLEncoder.encode(server.username, "UTF-8"); userEnc = URLEncoder.encode(server.username, "UTF-8");
passwordEnc = (server.password != null) ? passwordEnc = (server.password != null) ?
URLEncoder.encode(server.password, "UTF-8") : ""; URLEncoder.encode(server.password, "UTF-8") : "";
} } catch (UnsupportedEncodingException e) {
catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Could not encode username or password", e); throw new IllegalArgumentException("Could not encode username or password", e);
} }
@ -242,9 +241,9 @@ public class WebDavStore extends Store {
authPath = (authPath != null) ? authPath : ""; authPath = (authPath != null) ? authPath : "";
String mailboxPath = extra.get(WebDavStoreSettings.MAILBOX_PATH_KEY); String mailboxPath = extra.get(WebDavStoreSettings.MAILBOX_PATH_KEY);
mailboxPath = (mailboxPath != null) ? mailboxPath : ""; mailboxPath = (mailboxPath != null) ? mailboxPath : "";
uriPath = path + "|" + authPath + "|" + mailboxPath; uriPath = "/" + path + "|" + authPath + "|" + mailboxPath;
} else { } else {
uriPath = "||"; uriPath = "/||";
} }
try { try {
@ -1399,7 +1398,7 @@ public class WebDavStore extends Store {
messageCount = dataset.getMessageCount(); messageCount = dataset.getMessageCount();
} }
if (K9.DEBUG && K9.DEBUG_PROTOCOL_WEBDAV) { if (K9.DEBUG && K9.DEBUG_PROTOCOL_WEBDAV) {
Log.v(K9.LOG_TAG, "Counted messages and webdav returned: "+messageCount); Log.v(K9.LOG_TAG, "Counted messages and webdav returned: " + messageCount);
} }
return messageCount; return messageCount;
@ -1772,7 +1771,7 @@ public class WebDavStore extends Store {
try { try {
wdMessage.setFlagInternal(Flag.SEEN, uidToReadStatus.get(wdMessage.getUid())); wdMessage.setFlagInternal(Flag.SEEN, uidToReadStatus.get(wdMessage.getUid()));
} catch (NullPointerException e) { } catch (NullPointerException e) {
Log.v(K9.LOG_TAG,"Under some weird circumstances, setting the read status when syncing from webdav threw an NPE. Skipping."); Log.v(K9.LOG_TAG, "Under some weird circumstances, setting the read status when syncing from webdav threw an NPE. Skipping.");
} }
if (listener != null) { if (listener != null) {
@ -1841,7 +1840,7 @@ public class WebDavStore extends Store {
wdMessage.setNewHeaders(envelope); wdMessage.setNewHeaders(envelope);
wdMessage.setFlagInternal(Flag.SEEN, envelope.getReadStatus()); wdMessage.setFlagInternal(Flag.SEEN, envelope.getReadStatus());
} else { } else {
Log.e(K9.LOG_TAG,"Asked to get metadata for a non-existent message: "+wdMessage.getUid()); Log.e(K9.LOG_TAG, "Asked to get metadata for a non-existent message: " + wdMessage.getUid());
} }
if (listener != null) { if (listener != null) {

View File

@ -45,7 +45,7 @@ public class EasEmailSyncParser extends AbstractSyncParser {
// Message.MAILBOX_KEY + "=" + mMailbox.mId, null); // Message.MAILBOX_KEY + "=" + mMailbox.mId, null);
} }
public void addData (EasMessage msg) throws IOException, MessagingException { public void addData(EasMessage msg) throws IOException, MessagingException {
// ArrayList<Attachment> atts = new ArrayList<Attachment>(); // ArrayList<Attachment> atts = new ArrayList<Attachment>();
while (nextTag(Tags.SYNC_APPLICATION_DATA) != END) { while (nextTag(Tags.SYNC_APPLICATION_DATA) != END) {

View File

@ -368,7 +368,7 @@ public abstract class Parser {
text = null; text = null;
name = null; name = null;
int id = nextId (); int id = nextId();
while (id == Wbxml.SWITCH_PAGE) { while (id == Wbxml.SWITCH_PAGE) {
nextId = NOT_FETCHED; nextId = NOT_FETCHED;
// Get the new page number // Get the new page number

View File

@ -200,7 +200,7 @@ public class ProvisionParser extends Parser {
if (value.equals("0")) { if (value.equals("0")) {
sps.mMaxScreenLockTime = 1; sps.mMaxScreenLockTime = 1;
} else { } else {
sps.mMaxScreenLockTime = 60*Integer.parseInt(value); sps.mMaxScreenLockTime = 60 * Integer.parseInt(value);
} }
} }
} else if (name.equals("AEFrequencyType")) { } else if (name.equals("AEFrequencyType")) {
@ -368,11 +368,16 @@ public class ProvisionParser extends Parser {
// bit 25: remote wipe capability required // bit 25: remote wipe capability required
private static final int REQUIRE_REMOTE_WIPE = 1 << 25; private static final int REQUIRE_REMOTE_WIPE = 1 << 25;
/*package*/ final int mMinPasswordLength; /*package*/
/*package*/ final int mPasswordMode; final int mMinPasswordLength;
/*package*/ final int mMaxPasswordFails; /*package*/
/*package*/ final int mMaxScreenLockTime; final int mPasswordMode;
/*package*/ final boolean mRequireRemoteWipe; /*package*/
final int mMaxPasswordFails;
/*package*/
final int mMaxScreenLockTime;
/*package*/
final boolean mRequireRemoteWipe;
public int getMinPasswordLengthForTest() { public int getMinPasswordLengthForTest() {
return mMinPasswordLength; return mMinPasswordLength;

View File

@ -96,7 +96,7 @@ public class Serializer {
out.flush(); out.flush();
} }
public void startDocument() throws IOException{ public void startDocument() throws IOException {
out.write(0x03); // version 1.3 out.write(0x03); // version 1.3
out.write(0x01); // unknown or missing public identifier out.write(0x01); // unknown or missing public identifier
out.write(106); out.write(106);
@ -186,7 +186,7 @@ public class Serializer {
int idx = 0; int idx = 0;
do { do {
buf[idx++] = (byte) (i & 0x7f); buf[idx++] = (byte)(i & 0x7f);
i = i >> 7; i = i >> 7;
} while (i != 0); } while (i != 0);
@ -205,7 +205,7 @@ public class Serializer {
out.write(0); out.write(0);
} }
void writeStringValue (ContentValues cv, String key, int tag) throws IOException { void writeStringValue(ContentValues cv, String key, int tag) throws IOException {
String value = cv.getAsString(key); String value = cv.getAsString(key);
if (value != null && value.length() > 0) { if (value != null && value.length() > 0) {
data(tag, value); data(tag, value);

View File

@ -214,7 +214,7 @@ public class Tags {
public static final int FOLDER_UPDATE = FOLDER_PAGE + 0x11; public static final int FOLDER_UPDATE = FOLDER_PAGE + 0x11;
public static final int FOLDER_SYNC_KEY = FOLDER_PAGE + 0x12; public static final int FOLDER_SYNC_KEY = FOLDER_PAGE + 0x12;
public static final int FOLDER_FOLDER_CREATE = FOLDER_PAGE + 0x13; public static final int FOLDER_FOLDER_CREATE = FOLDER_PAGE + 0x13;
public static final int FOLDER_FOLDER_DELETE= FOLDER_PAGE + 0x14; public static final int FOLDER_FOLDER_DELETE = FOLDER_PAGE + 0x14;
public static final int FOLDER_FOLDER_UPDATE = FOLDER_PAGE + 0x15; public static final int FOLDER_FOLDER_UPDATE = FOLDER_PAGE + 0x15;
public static final int FOLDER_FOLDER_SYNC = FOLDER_PAGE + 0x16; public static final int FOLDER_FOLDER_SYNC = FOLDER_PAGE + 0x16;
public static final int FOLDER_COUNT = FOLDER_PAGE + 0x17; public static final int FOLDER_COUNT = FOLDER_PAGE + 0x17;
@ -479,7 +479,8 @@ public class Tags {
public static final int BASE_CONTENT_TYPE = BASE_PAGE + 0x17; public static final int BASE_CONTENT_TYPE = BASE_PAGE + 0x17;
static public String[][] pages = { static public String[][] pages = {
{ // 0x00 AirSync {
// 0x00 AirSync
"Sync", "Responses", "Add", "Change", "Delete", "Fetch", "SyncKey", "ClientId", "Sync", "Responses", "Add", "Change", "Delete", "Fetch", "SyncKey", "ClientId",
"ServerId", "Status", "Collection", "Class", "Version", "CollectionId", "GetChanges", "ServerId", "Status", "Collection", "Class", "Version", "CollectionId", "GetChanges",
"MoreAvailable", "WindowSize", "Commands", "Options", "FilterType", "Truncation", "MoreAvailable", "WindowSize", "Commands", "Options", "FilterType", "Truncation",

View File

@ -139,8 +139,7 @@ public class SmtpTransport extends Transport {
URLEncoder.encode(server.username, "UTF-8") : ""; URLEncoder.encode(server.username, "UTF-8") : "";
passwordEnc = (server.password != null) ? passwordEnc = (server.password != null) ?
URLEncoder.encode(server.password, "UTF-8") : ""; URLEncoder.encode(server.password, "UTF-8") : "";
} } catch (UnsupportedEncodingException e) {
catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Could not encode username or password", e); throw new IllegalArgumentException("Could not encode username or password", e);
} }

View File

@ -27,6 +27,7 @@ public class AccountSettings {
s.put("chipColor", new ColorSetting(0xFF0000FF)); s.put("chipColor", new ColorSetting(0xFF0000FF));
s.put("cryptoApp", new StringSetting(Apg.NAME)); s.put("cryptoApp", new StringSetting(Apg.NAME));
s.put("cryptoAutoSignature", new BooleanSetting(false)); s.put("cryptoAutoSignature", new BooleanSetting(false));
s.put("cryptoAutoEncrypt", new BooleanSetting(false)); // added to version 3
s.put("defaultQuotedTextShown", new BooleanSetting(Account.DEFAULT_QUOTED_TEXT_SHOWN)); s.put("defaultQuotedTextShown", new BooleanSetting(Account.DEFAULT_QUOTED_TEXT_SHOWN));
s.put("deletePolicy", new DeletePolicySetting(Account.DELETE_POLICY_NEVER)); s.put("deletePolicy", new DeletePolicySetting(Account.DELETE_POLICY_NEVER));
s.put("displayCount", new IntegerResourceSetting(K9.DEFAULT_VISIBLE_LIMIT, s.put("displayCount", new IntegerResourceSetting(K9.DEFAULT_VISIBLE_LIMIT,
@ -248,7 +249,9 @@ public class AccountSettings {
if (mMapping.containsKey(deletePolicy)) { if (mMapping.containsKey(deletePolicy)) {
return deletePolicy; return deletePolicy;
} }
} catch (NumberFormatException e) { /* do nothing */ } } catch (NumberFormatException e) {
/* do nothing */
}
throw new InvalidSettingValueException(); throw new InvalidSettingValueException();
} }

View File

@ -186,7 +186,9 @@ public class GlobalSettings {
if (mMapping.containsKey(theme)) { if (mMapping.containsKey(theme)) {
return theme; return theme;
} }
} catch (NumberFormatException e) { /* do nothing */ } } catch (NumberFormatException e) {
/* do nothing */
}
throw new InvalidSettingValueException(); throw new InvalidSettingValueException();
} }
@ -249,7 +251,9 @@ public class GlobalSettings {
if (new File(value).isDirectory()) { if (new File(value).isDirectory()) {
return value; return value;
} }
} catch (Exception e) { /* do nothing */ } } catch (Exception e) {
/* do nothing */
}
throw new InvalidSettingValueException(); throw new InvalidSettingValueException();
} }

View File

@ -32,7 +32,7 @@ public class Settings {
* *
* @see SettingsExporter * @see SettingsExporter
*/ */
public static final int VERSION = 2; public static final int VERSION = 3;
public static Map<String, String> validate(Map<String, SettingsDescription> settings, public static Map<String, String> validate(Map<String, SettingsDescription> settings,
Map<String, String> importedSettings, boolean useDefaultValues) { Map<String, String> importedSettings, boolean useDefaultValues) {
@ -245,7 +245,9 @@ public class Settings {
if (value.length() == 7) { if (value.length() == 7) {
return Integer.parseInt(value.substring(1), 16) | 0xFF000000; return Integer.parseInt(value.substring(1), 16) | 0xFF000000;
} }
} catch (NumberFormatException e) { /* do nothing */ } } catch (NumberFormatException e) {
/* do nothing */
}
throw new InvalidSettingValueException(); throw new InvalidSettingValueException();
} }
@ -259,9 +261,9 @@ public class Settings {
* </p> * </p>
*/ */
public static class EnumSetting extends SettingsDescription { public static class EnumSetting extends SettingsDescription {
private Class<? extends Enum<?>> mEnumClass; private Class <? extends Enum<? >> mEnumClass;
public EnumSetting(Class<? extends Enum<?>> enumClass, Object defaultValue) { public EnumSetting(Class <? extends Enum<? >> enumClass, Object defaultValue) {
super(defaultValue); super(defaultValue);
mEnumClass = enumClass; mEnumClass = enumClass;
} }
@ -270,7 +272,7 @@ public class Settings {
@Override @Override
public Object fromString(String value) throws InvalidSettingValueException { public Object fromString(String value) throws InvalidSettingValueException {
try { try {
return Enum.valueOf((Class<? extends Enum>)mEnumClass, value); return Enum.valueOf((Class <? extends Enum >)mEnumClass, value);
} catch (Exception e) { } catch (Exception e) {
throw new InvalidSettingValueException(); throw new InvalidSettingValueException();
} }
@ -339,7 +341,9 @@ public class Settings {
if (mMapping.containsKey(fontSize)) { if (mMapping.containsKey(fontSize)) {
return fontSize; return fontSize;
} }
} catch (NumberFormatException e) { /* do nothing */ } } catch (NumberFormatException e) {
/* do nothing */
}
throw new InvalidSettingValueException(); throw new InvalidSettingValueException();
} }
@ -375,7 +379,9 @@ public class Settings {
if (mMapping.containsKey(fontSize)) { if (mMapping.containsKey(fontSize)) {
return fontSize; return fontSize;
} }
} catch (NumberFormatException e) { /* do nothing */ } } catch (NumberFormatException e) {
/* do nothing */
}
throw new InvalidSettingValueException(); throw new InvalidSettingValueException();
} }
@ -401,7 +407,9 @@ public class Settings {
if (mStart <= intValue && intValue <= mEnd) { if (mStart <= intValue && intValue <= mEnd) {
return intValue; return intValue;
} }
} catch (NumberFormatException e) { /* do nothing */ } } catch (NumberFormatException e) {
/* do nothing */
}
throw new InvalidSettingValueException(); throw new InvalidSettingValueException();
} }

View File

@ -81,8 +81,7 @@ public class SettingsExporter {
OutputStream os = null; OutputStream os = null;
String filename = null; String filename = null;
try try {
{
File dir = new File(Environment.getExternalStorageDirectory() + File.separator File dir = new File(Environment.getExternalStorageDirectory() + File.separator
+ context.getPackageName()); + context.getPackageName());
dir.mkdirs(); dir.mkdirs();
@ -114,7 +113,7 @@ public class SettingsExporter {
XmlSerializer serializer = Xml.newSerializer(); XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(os, "UTF-8"); serializer.setOutput(os, "UTF-8");
serializer.startDocument(null, Boolean.valueOf(true)); serializer.startDocument(null, Boolean.TRUE);
// Output with indentation // Output with indentation
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
@ -293,7 +292,9 @@ public class SettingsExporter {
// This is an identity key. Save identity index for later... // This is an identity key. Save identity index for later...
try { try {
identities.add(Integer.parseInt(thirdPart)); identities.add(Integer.parseInt(thirdPart));
} catch (NumberFormatException e) { /* ignore */ } } catch (NumberFormatException e) {
/* ignore */
}
// ... but don't write it now. // ... but don't write it now.
continue; continue;
} }

View File

@ -176,8 +176,7 @@ public class SettingsImporter {
boolean globalSettings, List<String> accountUuids, boolean overwrite) boolean globalSettings, List<String> accountUuids, boolean overwrite)
throws SettingsImportExportException { throws SettingsImportExportException {
try try {
{
boolean globalSettingsImported = false; boolean globalSettingsImported = false;
List<AccountDescriptionPair> importedAccounts = new ArrayList<AccountDescriptionPair>(); List<AccountDescriptionPair> importedAccounts = new ArrayList<AccountDescriptionPair>();
List<AccountDescription> errorneousAccounts = new ArrayList<AccountDescription>(); List<AccountDescription> errorneousAccounts = new ArrayList<AccountDescription>();
@ -625,7 +624,7 @@ public class SettingsImporter {
Imported imported = null; Imported imported = null;
int eventType = xpp.getEventType(); int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) { while (eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
if (SettingsExporter.ROOT_ELEMENT.equals(xpp.getName())) { if (SettingsExporter.ROOT_ELEMENT.equals(xpp.getName())) {
imported = parseRoot(xpp, globalSettings, accountUuids, overview); imported = parseRoot(xpp, globalSettings, accountUuids, overview);
} else { } else {
@ -683,7 +682,7 @@ public class SettingsImporter {
while (!(eventType == XmlPullParser.END_TAG && while (!(eventType == XmlPullParser.END_TAG &&
SettingsExporter.ROOT_ELEMENT.equals(xpp.getName()))) { SettingsExporter.ROOT_ELEMENT.equals(xpp.getName()))) {
if(eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String element = xpp.getName(); String element = xpp.getName();
if (SettingsExporter.GLOBAL_ELEMENT.equals(element)) { if (SettingsExporter.GLOBAL_ELEMENT.equals(element)) {
if (overview || globalSettings) { if (overview || globalSettings) {
@ -772,7 +771,7 @@ public class SettingsImporter {
int eventType = xpp.next(); int eventType = xpp.next();
while (!(eventType == XmlPullParser.END_TAG && endTag.equals(xpp.getName()))) { while (!(eventType == XmlPullParser.END_TAG && endTag.equals(xpp.getName()))) {
if(eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String element = xpp.getName(); String element = xpp.getName();
if (SettingsExporter.VALUE_ELEMENT.equals(element)) { if (SettingsExporter.VALUE_ELEMENT.equals(element)) {
String key = xpp.getAttributeValue(null, SettingsExporter.KEY_ATTRIBUTE); String key = xpp.getAttributeValue(null, SettingsExporter.KEY_ATTRIBUTE);
@ -807,7 +806,7 @@ public class SettingsImporter {
while (!(eventType == XmlPullParser.END_TAG && while (!(eventType == XmlPullParser.END_TAG &&
SettingsExporter.ACCOUNTS_ELEMENT.equals(xpp.getName()))) { SettingsExporter.ACCOUNTS_ELEMENT.equals(xpp.getName()))) {
if(eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String element = xpp.getName(); String element = xpp.getName();
if (SettingsExporter.ACCOUNT_ELEMENT.equals(element)) { if (SettingsExporter.ACCOUNT_ELEMENT.equals(element)) {
if (accounts == null) { if (accounts == null) {
@ -856,7 +855,7 @@ public class SettingsImporter {
while (!(eventType == XmlPullParser.END_TAG && while (!(eventType == XmlPullParser.END_TAG &&
SettingsExporter.ACCOUNT_ELEMENT.equals(xpp.getName()))) { SettingsExporter.ACCOUNT_ELEMENT.equals(xpp.getName()))) {
if(eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String element = xpp.getName(); String element = xpp.getName();
if (SettingsExporter.NAME_ELEMENT.equals(element)) { if (SettingsExporter.NAME_ELEMENT.equals(element)) {
account.name = getText(xpp); account.name = getText(xpp);
@ -912,7 +911,7 @@ public class SettingsImporter {
int eventType = xpp.next(); int eventType = xpp.next();
while (!(eventType == XmlPullParser.END_TAG && endTag.equals(xpp.getName()))) { while (!(eventType == XmlPullParser.END_TAG && endTag.equals(xpp.getName()))) {
if(eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String element = xpp.getName(); String element = xpp.getName();
if (SettingsExporter.HOST_ELEMENT.equals(element)) { if (SettingsExporter.HOST_ELEMENT.equals(element)) {
server.host = getText(xpp); server.host = getText(xpp);
@ -946,7 +945,7 @@ public class SettingsImporter {
while (!(eventType == XmlPullParser.END_TAG && while (!(eventType == XmlPullParser.END_TAG &&
SettingsExporter.IDENTITIES_ELEMENT.equals(xpp.getName()))) { SettingsExporter.IDENTITIES_ELEMENT.equals(xpp.getName()))) {
if(eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String element = xpp.getName(); String element = xpp.getName();
if (SettingsExporter.IDENTITY_ELEMENT.equals(element)) { if (SettingsExporter.IDENTITY_ELEMENT.equals(element)) {
if (identities == null) { if (identities == null) {
@ -973,7 +972,7 @@ public class SettingsImporter {
while (!(eventType == XmlPullParser.END_TAG && while (!(eventType == XmlPullParser.END_TAG &&
SettingsExporter.IDENTITY_ELEMENT.equals(xpp.getName()))) { SettingsExporter.IDENTITY_ELEMENT.equals(xpp.getName()))) {
if(eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String element = xpp.getName(); String element = xpp.getName();
if (SettingsExporter.NAME_ELEMENT.equals(element)) { if (SettingsExporter.NAME_ELEMENT.equals(element)) {
identity.name = getText(xpp); identity.name = getText(xpp);
@ -1001,7 +1000,7 @@ public class SettingsImporter {
while (!(eventType == XmlPullParser.END_TAG && while (!(eventType == XmlPullParser.END_TAG &&
SettingsExporter.FOLDERS_ELEMENT.equals(xpp.getName()))) { SettingsExporter.FOLDERS_ELEMENT.equals(xpp.getName()))) {
if(eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String element = xpp.getName(); String element = xpp.getName();
if (SettingsExporter.FOLDER_ELEMENT.equals(element)) { if (SettingsExporter.FOLDER_ELEMENT.equals(element)) {
if (folders == null) { if (folders == null) {

View File

@ -126,7 +126,7 @@ public abstract class CoreService extends Service {
} }
if (createIfNotExists) { if (createIfNotExists) {
addWakeLock(context,intent); addWakeLock(context, intent);
} }
} }
@ -258,7 +258,9 @@ public abstract class CoreService extends Service {
try { try {
// Release the wake lock acquired at the start of this method // Release the wake lock acquired at the start of this method
wakeLock.release(); wakeLock.release();
} catch (Exception e) { /* ignore */ } } catch (Exception e) {
/* ignore */
}
try { try {
// If there is no outstanding work to be done in a background thread we can stop // If there is no outstanding work to be done in a background thread we can stop
@ -267,7 +269,9 @@ public abstract class CoreService extends Service {
stopSelf(startId); stopSelf(startId);
startFlag = START_NOT_STICKY; startFlag = START_NOT_STICKY;
} }
} catch (Exception e) { /* ignore */ } } catch (Exception e) {
/* ignore */
}
} }
return startFlag; return startFlag;

View File

@ -120,8 +120,7 @@ public class SleepService extends CoreService {
endSleep(id); endSleep(id);
} }
return START_NOT_STICKY; return START_NOT_STICKY;
} } finally {
finally {
stopSelf(startId); stopSelf(startId);
} }
} }

View File

@ -319,12 +319,12 @@ public class SingleMessageView extends LinearLayout {
* @param listeners Set of listeners. * @param listeners Set of listeners.
*/ */
public void setListeners(final Set<MessagingListener> listeners) { public void setListeners(final Set<MessagingListener> listeners) {
if(!mScreenReaderEnabled) { if (!mScreenReaderEnabled) {
if(mMessageContentView != null) { if (mMessageContentView != null) {
mMessageContentView.setListeners(listeners); mMessageContentView.setListeners(listeners);
} }
} else { } else {
if(mAccessibleMessageContentView != null) { if (mAccessibleMessageContentView != null) {
mAccessibleMessageContentView.setListeners(listeners); mAccessibleMessageContentView.setListeners(listeners);
} }
} }

View File

@ -78,7 +78,7 @@ public class ToggleScrollView extends ScrollView {
// We save only the Y coordinate instead of the percentage because I don't know how expensive the // We save only the Y coordinate instead of the percentage because I don't know how expensive the
// computeVerticalScrollRange() call is. // computeVerticalScrollRange() call is.
final int scrollRange = computeVerticalScrollRange(); final int scrollRange = computeVerticalScrollRange();
if(scrollRange == 0) { if (scrollRange == 0) {
return 0; return 0;
} }
return (double) mCurrentYPosition / scrollRange; return (double) mCurrentYPosition / scrollRange;
@ -119,7 +119,7 @@ public class ToggleScrollView extends ScrollView {
class ScrollToLastLocationListener extends MessagingListener { class ScrollToLastLocationListener extends MessagingListener {
public void messageViewFinished() { public void messageViewFinished() {
// Don't scroll if our last position was at the top. // Don't scroll if our last position was at the top.
if(mScrollPercentage != 0.0) { if (mScrollPercentage != 0.0) {
final int scrollRange = computeVerticalScrollRange(); final int scrollRange = computeVerticalScrollRange();
final int newY = (int)(mScrollPercentage * scrollRange); final int newY = (int)(mScrollPercentage * scrollRange);
Log.d(K9.LOG_TAG, "ToggleScrollView: requested " + (100 * mScrollPercentage) + "%, " + Log.d(K9.LOG_TAG, "ToggleScrollView: requested " + (100 * mScrollPercentage) + "%, " +
@ -134,7 +134,7 @@ public class ToggleScrollView extends ScrollView {
* @return * @return
*/ */
public MessagingListener getListener() { public MessagingListener getListener() {
if(this.mListener != null) { if (this.mListener != null) {
return this.mListener; return this.mListener;
} else { } else {
return this.mListener = new ScrollToLastLocationListener(); return this.mListener = new ScrollToLastLocationListener();