1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-17 06:55:03 -05:00

Merge commit '4.121' into issue-162-new

Conflicts:
	src/com/fsck/k9/mail/store/LocalStore.java
This commit is contained in:
ashley willis 2012-09-11 01:50:46 -05:00
commit f57ee1181f
27 changed files with 458 additions and 404 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="15019" android:versionCode="15020"
android:versionName="4.120" package="com.fsck.k9" android:versionName="4.121" package="com.fsck.k9"
> >
<uses-sdk <uses-sdk
android:minSdkVersion="7" android:minSdkVersion="7"

View File

@ -502,6 +502,7 @@
<item>dark</item> <item>dark</item>
</string-array> </string-array>
<!-- Note: If you change this make sure the code in Prefs.java is still working -->
<string-array name="background_ops_entries"> <string-array name="background_ops_entries">
<item>@string/background_ops_enabled</item> <item>@string/background_ops_enabled</item>
<item>@string/background_ops_auto_sync</item> <item>@string/background_ops_auto_sync</item>

View File

@ -850,6 +850,7 @@ http://k9mail.googlecode.com/
<string name="background_ops_always">Always</string> <string name="background_ops_always">Always</string>
<string name="background_ops_enabled">When \'Background data\' is checked</string> <string name="background_ops_enabled">When \'Background data\' is checked</string>
<string name="background_ops_auto_sync">When \'Background data\' &amp; \'Auto-sync\' are checked</string> <string name="background_ops_auto_sync">When \'Background data\' &amp; \'Auto-sync\' are checked</string>
<string name="background_ops_auto_sync_only">When \'Auto-sync\' is checked</string>
<string name="no_message_seletected_toast">No message selected</string> <string name="no_message_seletected_toast">No message selected</string>

View File

@ -19,7 +19,6 @@ import com.fsck.k9.mail.store.StorageManager;
import com.fsck.k9.mail.store.StorageManager.StorageProvider; import com.fsck.k9.mail.store.StorageManager.StorageProvider;
import com.fsck.k9.view.ColorChip; import com.fsck.k9.view.ColorChip;
import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;

View File

@ -10,7 +10,6 @@ import java.util.Map;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Config;
import android.util.Log; import android.util.Log;
import com.fsck.k9.preferences.Editor; import com.fsck.k9.preferences.Editor;
import com.fsck.k9.preferences.Storage; import com.fsck.k9.preferences.Storage;
@ -155,14 +154,6 @@ public class Preferences {
getPreferences().edit().putString("defaultAccountUuid", account.getUuid()).commit(); getPreferences().edit().putString("defaultAccountUuid", account.getUuid()).commit();
} }
public void dump() {
if (Config.LOGV) {
for (String key : getPreferences().getAll().keySet()) {
Log.v(K9.LOG_TAG, key + " = " + getPreferences().getAll().get(key));
}
}
}
public SharedPreferences getPreferences() { public SharedPreferences getPreferences() {
return mStorage; return mStorage;
} }

View File

@ -17,7 +17,6 @@ import java.util.List;
public class ChooseIdentity extends K9ListActivity { public class ChooseIdentity extends K9ListActivity {
Account mAccount; Account mAccount;
String mUID;
ArrayAdapter<String> adapter; ArrayAdapter<String> adapter;
public static final String EXTRA_ACCOUNT = "com.fsck.k9.ChooseIdentity_account"; public static final String EXTRA_ACCOUNT = "com.fsck.k9.ChooseIdentity_account";

View File

@ -11,7 +11,6 @@ import android.os.Handler;
import android.os.PowerManager; import android.os.PowerManager;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Config;
import android.util.Log; import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.*; import android.view.*;
@ -1099,10 +1098,6 @@ public class FolderList extends K9ListActivity {
if (account.equals(mAccount)) { if (account.equals(mAccount)) {
mHandler.progress(false); mHandler.progress(false);
if (Config.LOGV) {
Log.v(K9.LOG_TAG, "listFoldersFailed " + message);
}
} }
super.listFoldersFailed(account, message); super.listFoldersFailed(account, message);
} }

View File

@ -3432,11 +3432,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
static class IdentityAdapter extends BaseAdapter { static class IdentityAdapter extends BaseAdapter {
private LayoutInflater mLayoutInflater; private LayoutInflater mLayoutInflater;
private List<Object> mItems; private List<Object> mItems;
private FontSizes mFontSizes;
public IdentityAdapter(Context context, LayoutInflater layoutInflater) { public IdentityAdapter(Context context, LayoutInflater layoutInflater) {
mLayoutInflater = layoutInflater; mLayoutInflater = layoutInflater;
mFontSizes = K9.getFontSizes();
List<Object> items = new ArrayList<Object>(); List<Object> items = new ArrayList<Object>();
Preferences prefs = Preferences.getPreferences(context.getApplicationContext()); Preferences prefs = Preferences.getPreferences(context.getApplicationContext());

View File

@ -54,12 +54,10 @@ import android.widget.Toast;
import com.fsck.k9.Account; import com.fsck.k9.Account;
import com.fsck.k9.Account.SortType; import com.fsck.k9.Account.SortType;
import com.fsck.k9.AccountStats; import com.fsck.k9.AccountStats;
import com.fsck.k9.BaseAccount;
import com.fsck.k9.FontSizes; import com.fsck.k9.FontSizes;
import com.fsck.k9.K9; import com.fsck.k9.K9;
import com.fsck.k9.Preferences; import com.fsck.k9.Preferences;
import com.fsck.k9.R; import com.fsck.k9.R;
import com.fsck.k9.SearchAccount;
import com.fsck.k9.SearchSpecification; import com.fsck.k9.SearchSpecification;
import com.fsck.k9.activity.setup.AccountSettings; import com.fsck.k9.activity.setup.AccountSettings;
import com.fsck.k9.activity.setup.FolderSettings; import com.fsck.k9.activity.setup.FolderSettings;
@ -272,8 +270,6 @@ public class MessageList
private Account mAccount; private Account mAccount;
private int mUnreadMessageCount = 0; private int mUnreadMessageCount = 0;
private GestureDetector gestureDetector;
private View.OnTouchListener gestureListener;
/** /**
* Stores the name of the folder that we want to open as soon as possible * Stores the name of the folder that we want to open as soon as possible
* after load. * after load.
@ -364,15 +360,15 @@ public class MessageList
@Override @Override
public void run() { public void run() {
for (MessageInfoHolder message : messages) { for (MessageInfoHolder message : messages) {
if (message != null) { if (message != null && (mFolderName == null || (
if (mFolderName == null || (message.folder != null && message.folder.name.equals(mFolderName))) { message.folder != null &&
message.folder.name.equals(mFolderName)))) {
if (message.selected && mSelectedCount > 0) { if (message.selected && mSelectedCount > 0) {
mSelectedCount--; mSelectedCount--;
} }
mAdapter.messages.remove(message); mAdapter.messages.remove(message);
} }
} }
}
resetUnreadCountOnThread(); resetUnreadCountOnThread();
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();

View File

@ -6,6 +6,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Vibrator; import android.os.Vibrator;
import android.preference.*; import android.preference.*;
@ -50,6 +51,7 @@ public class AccountSettings extends K9PreferenceActivity {
private static final String PREFERENCE_SCREEN_COMPOSING = "composing"; private static final String PREFERENCE_SCREEN_COMPOSING = "composing";
private static final String PREFERENCE_SCREEN_INCOMING = "incoming_prefs"; private static final String PREFERENCE_SCREEN_INCOMING = "incoming_prefs";
private static final String PREFERENCE_SCREEN_PUSH_ADVANCED = "push_advanced"; private static final String PREFERENCE_SCREEN_PUSH_ADVANCED = "push_advanced";
private static final String PREFERENCE_SCREEN_NOTIFICATIONS = "notifications";
private static final String PREFERENCE_DESCRIPTION = "account_description"; private static final String PREFERENCE_DESCRIPTION = "account_description";
private static final String PREFERENCE_MARK_MESSAGE_AS_READ_ON_VIEW = "mark_message_as_read_on_view"; private static final String PREFERENCE_MARK_MESSAGE_AS_READ_ON_VIEW = "mark_message_as_read_on_view";
@ -581,8 +583,23 @@ public class AccountSettings extends K9PreferenceActivity {
mNotificationOpensUnread = (CheckBoxPreference)findPreference(PREFERENCE_NOTIFICATION_OPENS_UNREAD); mNotificationOpensUnread = (CheckBoxPreference)findPreference(PREFERENCE_NOTIFICATION_OPENS_UNREAD);
mNotificationOpensUnread.setChecked(mAccount.goToUnreadMessageSearch()); mNotificationOpensUnread.setChecked(mAccount.goToUnreadMessageSearch());
mNotificationUnreadCount = (CheckBoxPreference)findPreference(PREFERENCE_NOTIFICATION_UNREAD_COUNT); CheckBoxPreference notificationUnreadCount =
mNotificationUnreadCount.setChecked(mAccount.isNotificationShowsUnreadCount()); (CheckBoxPreference) findPreference(PREFERENCE_NOTIFICATION_UNREAD_COUNT);
/*
* Honeycomb and newer don't show the notification number as overlay on the notification
* icon in the status bar, so we hide the setting.
*
* See http://code.google.com/p/android/issues/detail?id=21477
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
PreferenceScreen notificationsPrefs =
(PreferenceScreen) findPreference(PREFERENCE_SCREEN_NOTIFICATIONS);
notificationsPrefs.removePreference(notificationUnreadCount);
} else {
notificationUnreadCount.setChecked(mAccount.isNotificationShowsUnreadCount());
mNotificationUnreadCount = notificationUnreadCount;
}
new PopulateFolderPrefsTask().execute(); new PopulateFolderPrefsTask().execute();
@ -699,7 +716,9 @@ public class AccountSettings extends K9PreferenceActivity {
mAccount.getNotificationSetting().setVibrateTimes(Integer.parseInt(mAccountVibrateTimes.getValue())); mAccount.getNotificationSetting().setVibrateTimes(Integer.parseInt(mAccountVibrateTimes.getValue()));
mAccount.getNotificationSetting().setLed(mAccountLed.isChecked()); mAccount.getNotificationSetting().setLed(mAccountLed.isChecked());
mAccount.setGoToUnreadMessageSearch(mNotificationOpensUnread.isChecked()); mAccount.setGoToUnreadMessageSearch(mNotificationOpensUnread.isChecked());
if (mNotificationUnreadCount != null) {
mAccount.setNotificationShowsUnreadCount(mNotificationUnreadCount.isChecked()); mAccount.setNotificationShowsUnreadCount(mNotificationUnreadCount.isChecked());
}
mAccount.setFolderTargetMode(Account.FolderMode.valueOf(mTargetMode.getValue())); mAccount.setFolderTargetMode(Account.FolderMode.valueOf(mTargetMode.getValue()));
Log.d("ASH", "Setting delete policy to " + mDeletePolicy.getValue()); Log.d("ASH", "Setting delete policy to " + mDeletePolicy.getValue());
mAccount.setDeletePolicy(Integer.parseInt(mDeletePolicy.getValue())); mAccount.setDeletePolicy(Integer.parseInt(mDeletePolicy.getValue()));

View File

@ -319,13 +319,13 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
if (name.equalsIgnoreCase(storeURIHost) || name.equalsIgnoreCase(transportURIHost)) { if (name.equalsIgnoreCase(storeURIHost) || name.equalsIgnoreCase(transportURIHost)) {
//TODO: localize this string //TODO: localize this string
altNamesText.append("Subject(alt): ").append(name).append(",...\n"); altNamesText.append("Subject(alt): ").append(name).append(",...\n");
} else if (name.startsWith("*.")) { } else if (name.startsWith("*.") && (
if (storeURIHost.endsWith(name.substring(2)) || transportURIHost.endsWith(name.substring(2))) { storeURIHost.endsWith(name.substring(2)) ||
transportURIHost.endsWith(name.substring(2)))) {
//TODO: localize this string //TODO: localize this string
altNamesText.append("Subject(alt): ").append(name).append(",...\n"); altNamesText.append("Subject(alt): ").append(name).append(",...\n");
} }
} }
}
chainInfo.append(altNamesText); chainInfo.append(altNamesText);
} }
} catch (Exception e1) { } catch (Exception e1) {

View File

@ -33,6 +33,7 @@ import com.fsck.k9.preferences.CheckBoxListPreference;
import com.fsck.k9.preferences.TimePickerPreference; import com.fsck.k9.preferences.TimePickerPreference;
import com.fsck.k9.service.MailService; import com.fsck.k9.service.MailService;
import com.fsck.k9.view.MessageWebView;
public class Prefs extends K9PreferenceActivity { public class Prefs extends K9PreferenceActivity {
@ -284,12 +285,12 @@ public class Prefs extends K9PreferenceActivity {
mZoomControlsEnabled.setChecked(K9.zoomControlsEnabled()); mZoomControlsEnabled.setChecked(K9.zoomControlsEnabled());
mMobileOptimizedLayout = (CheckBoxPreference) findPreference(PREFERENCE_MESSAGEVIEW_MOBILE_LAYOUT); mMobileOptimizedLayout = (CheckBoxPreference) findPreference(PREFERENCE_MESSAGEVIEW_MOBILE_LAYOUT);
if (Build.VERSION.SDK_INT <= 7) { if (!MessageWebView.isSingleColumnLayoutSupported()) {
mMobileOptimizedLayout.setEnabled(false); mMobileOptimizedLayout.setEnabled(false);
} mMobileOptimizedLayout.setChecked(false);
} else {
mMobileOptimizedLayout.setChecked(K9.mobileOptimizedLayout()); mMobileOptimizedLayout.setChecked(K9.mobileOptimizedLayout());
}
mQuietTimeEnabled = (CheckBoxPreference) findPreference(PREFERENCE_QUIET_TIME_ENABLED); mQuietTimeEnabled = (CheckBoxPreference) findPreference(PREFERENCE_QUIET_TIME_ENABLED);
mQuietTimeEnabled.setChecked(K9.getQuietTimeEnabled()); mQuietTimeEnabled.setChecked(K9.getQuietTimeEnabled());
@ -320,6 +321,33 @@ public class Prefs extends K9PreferenceActivity {
mBackgroundOps = setupListPreference(PREFERENCE_BACKGROUND_OPS, K9.getBackgroundOps().toString()); mBackgroundOps = setupListPreference(PREFERENCE_BACKGROUND_OPS, K9.getBackgroundOps().toString());
// In ICS+ there is no 'background data' setting that apps can chose to ignore anymore. So
// we hide that option for "Background Sync".
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
CharSequence[] oldEntries = mBackgroundOps.getEntries();
CharSequence[] newEntries = new CharSequence[3];
// Use "When 'Auto-sync' is checked" instead of "When 'Background data' & 'Auto-sync'
// are checked" as description.
newEntries[0] = getString(R.string.background_ops_auto_sync_only);
newEntries[1] = oldEntries[2];
newEntries[2] = oldEntries[3];
CharSequence[] oldValues = mBackgroundOps.getEntryValues();
CharSequence[] newValues = new CharSequence[3];
newValues[0] = oldValues[1];
newValues[1] = oldValues[2];
newValues[2] = oldValues[3];
mBackgroundOps.setEntries(newEntries);
mBackgroundOps.setEntryValues(newValues);
// Since ConnectivityManager.getBackgroundDataSetting() always returns 'true' on ICS+
// we map WHEN_CHECKED to ALWAYS.
if (K9.getBackgroundOps() == K9.BACKGROUND_OPS.WHEN_CHECKED) {
mBackgroundOps.setValue(K9.BACKGROUND_OPS.ALWAYS.toString());
mBackgroundOps.setSummary(mBackgroundOps.getEntry());
}
}
mUseGalleryBugWorkaround = (CheckBoxPreference)findPreference(PREFERENCE_GALLERY_BUG_WORKAROUND); mUseGalleryBugWorkaround = (CheckBoxPreference)findPreference(PREFERENCE_GALLERY_BUG_WORKAROUND);
mUseGalleryBugWorkaround.setChecked(K9.useGalleryBugWorkaround()); mUseGalleryBugWorkaround.setChecked(K9.useGalleryBugWorkaround());

View File

@ -21,6 +21,7 @@ import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.Process; import android.os.Process;
import android.text.TextUtils; import android.text.TextUtils;
@ -534,9 +535,6 @@ public class MessagingController implements Runnable {
List<Message> pendingMessages = new ArrayList<Message>(); List<Message> pendingMessages = new ArrayList<Message>();
int totalDone = 0;
@Override @Override
public void messageStarted(String message, int number, int ofTotal) {} public void messageStarted(String message, int number, int ofTotal) {}
@Override @Override
@ -544,7 +542,6 @@ public class MessagingController implements Runnable {
if (!isMessageSuppressed(account, folder, message)) { if (!isMessageSuppressed(account, folder, message)) {
pendingMessages.add(message); pendingMessages.add(message);
totalDone++;
if (pendingMessages.size() > 10) { if (pendingMessages.size() > 10) {
addPendingMessages(); addPendingMessages();
} }
@ -2317,13 +2314,14 @@ public class MessagingController implements Runnable {
* upto speed with the remote UIDs of remote destionation folder. * upto speed with the remote UIDs of remote destionation folder.
*/ */
if (!localUidMap.isEmpty() && remoteUidMap != null && !remoteUidMap.isEmpty()) { if (!localUidMap.isEmpty() && remoteUidMap != null && !remoteUidMap.isEmpty()) {
Set<String> remoteSrcUids = remoteUidMap.keySet(); Set<Map.Entry<String, String>> remoteSrcEntries = remoteUidMap.entrySet();
Iterator<String> remoteSrcUidsIterator = remoteSrcUids.iterator(); Iterator<Map.Entry<String, String>> remoteSrcEntriesIterator = remoteSrcEntries.iterator();
while (remoteSrcUidsIterator.hasNext()) { while (remoteSrcEntriesIterator.hasNext()) {
String remoteSrcUid = remoteSrcUidsIterator.next(); Map.Entry<String, String> entry = remoteSrcEntriesIterator.next();
String remoteSrcUid = entry.getKey();
String localDestUid = localUidMap.get(remoteSrcUid); String localDestUid = localUidMap.get(remoteSrcUid);
String newUid = remoteUidMap.get(remoteSrcUid); String newUid = entry.getValue();
Message localDestMessage = localDestFolder.getMessage(localDestUid); Message localDestMessage = localDestFolder.getMessage(localDestUid);
if (localDestMessage != null) { if (localDestMessage != null) {
@ -3433,7 +3431,6 @@ public class MessagingController implements Runnable {
// "don't even bother" functionality // "don't even bother" functionality
if (getRootCauseMessage(e).startsWith("5")) { if (getRootCauseMessage(e).startsWith("5")) {
localFolder.moveMessages(new Message[] { message }, (LocalFolder) localStore.getFolder(account.getDraftsFolderName())); localFolder.moveMessages(new Message[] { message }, (LocalFolder) localStore.getFolder(account.getDraftsFolderName()));
} else {
} }
message.setFlag(Flag.X_SEND_FAILED, true); message.setFlag(Flag.X_SEND_FAILED, true);
@ -4562,7 +4559,10 @@ public class MessagingController implements Runnable {
builder.setTicker(messageNotice); builder.setTicker(messageNotice);
final int unreadCount = previousUnreadMessageCount + newMessageCount.get(); final int unreadCount = previousUnreadMessageCount + newMessageCount.get();
if (account.isNotificationShowsUnreadCount()) { if (account.isNotificationShowsUnreadCount() ||
// Honeycomb and newer don't show the number as overlay on the notification icon.
// However, the number will appear in the detailed notification view.
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
builder.setNumber(unreadCount); builder.setNumber(unreadCount);
} }

View File

@ -1,5 +1,6 @@
package com.fsck.k9.helper; package com.fsck.k9.helper;
import android.annotation.TargetApi;
import android.content.ClipData; import android.content.ClipData;
import android.content.Context; import android.content.Context;
import android.content.ClipboardManager; import android.content.ClipboardManager;
@ -7,6 +8,7 @@ import android.content.ClipboardManager;
/** /**
* Access the system clipboard using the new {@link ClipboardManager} introduced with API 11 * Access the system clipboard using the new {@link ClipboardManager} introduced with API 11
*/ */
@TargetApi(11)
public class ClipboardManagerApi11 extends com.fsck.k9.helper.ClipboardManager { public class ClipboardManagerApi11 extends com.fsck.k9.helper.ClipboardManager {
public ClipboardManagerApi11(Context context) { public ClipboardManagerApi11(Context context) {

View File

@ -124,8 +124,7 @@ public class DomainNameChecker {
List<?> altNameEntry = (List<?>)(subjectAltName); List<?> altNameEntry = (List<?>)(subjectAltName);
if ((altNameEntry != null) && (2 <= altNameEntry.size())) { if ((altNameEntry != null) && (2 <= altNameEntry.size())) {
Integer altNameType = (Integer)(altNameEntry.get(0)); Integer altNameType = (Integer)(altNameEntry.get(0));
if (altNameType != null) { if (altNameType != null && altNameType.intValue() == ALT_IPA_NAME) {
if (altNameType == ALT_IPA_NAME) {
String altName = (String)(altNameEntry.get(1)); String altName = (String)(altNameEntry.get(1));
if (altName != null) { if (altName != null) {
if (K9.DEBUG) { if (K9.DEBUG) {
@ -139,7 +138,6 @@ public class DomainNameChecker {
} }
} }
} }
}
} catch (CertificateParsingException e) { } catch (CertificateParsingException e) {
} }
@ -166,20 +164,16 @@ public class DomainNameChecker {
List<?> altNameEntry = (List<?>)(i.next()); List<?> altNameEntry = (List<?>)(i.next());
if ((altNameEntry != null) && (2 <= altNameEntry.size())) { if ((altNameEntry != null) && (2 <= altNameEntry.size())) {
Integer altNameType = (Integer)(altNameEntry.get(0)); Integer altNameType = (Integer)(altNameEntry.get(0));
if (altNameType != null) { if (altNameType != null && altNameType.intValue() == ALT_DNS_NAME) {
if (altNameType.intValue() == ALT_DNS_NAME) {
hasDns = true; hasDns = true;
String altName = (String)(altNameEntry.get(1)); String altName = (String)(altNameEntry.get(1));
if (altName != null) { if (altName != null && matchDns(thisDomain, altName)) {
if (matchDns(thisDomain, altName)) {
return true; return true;
} }
} }
} }
} }
} }
}
}
} catch (CertificateParsingException e) { } catch (CertificateParsingException e) {
// one way we can get here is if an alternative name starts with // one way we can get here is if an alternative name starts with
// '*' character, which is contrary to one interpretation of the // '*' character, which is contrary to one interpretation of the

View File

@ -1,5 +1,6 @@
package com.fsck.k9.helper; package com.fsck.k9.helper;
import android.annotation.TargetApi;
import android.app.Notification; import android.app.Notification;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
@ -9,6 +10,7 @@ import android.net.Uri;
/** /**
* Create notifications using the new {@link android.app.Notification.Builder} class. * Create notifications using the new {@link android.app.Notification.Builder} class.
*/ */
@TargetApi(11)
public class NotificationBuilderApi11 extends NotificationBuilder { public class NotificationBuilderApi11 extends NotificationBuilder {
private Notification.Builder mBuilder; private Notification.Builder mBuilder;

View File

@ -1,28 +0,0 @@
package com.fsck.k9.mail.filter;
import android.util.Config;
import android.util.Log;
import com.fsck.k9.K9;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class StatusOutputStream extends FilterOutputStream {
private long mCount = 0;
public StatusOutputStream(OutputStream out) {
super(out);
}
@Override
public void write(int oneByte) throws IOException {
super.write(oneByte);
mCount++;
if (Config.LOGV) {
if (mCount % 1024 == 0) {
Log.v(K9.LOG_TAG, "# " + mCount);
}
}
}
}

View File

@ -122,12 +122,11 @@ public class MimeHeader {
public boolean hasToBeEncoded(String text) { public boolean hasToBeEncoded(String text) {
for (int i = 0; i < text.length(); i++) { for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i); char c = text.charAt(i);
if (c < 0x20 || 0x7e < c) { // non printable if ((c < 0x20 || 0x7e < c) && // non printable
if (c != 0x0a && c != 0x0d && c != 0x09) { // non LF/CR/TAB (c != 0x0a && c != 0x0d && c != 0x09)) { // non LF/CR/TAB
return true; return true;
} }
} }
}
return false; return false;
} }

View File

@ -384,6 +384,10 @@ public class ImapResponseParser {
return (String)get(index); return (String)get(index);
} }
public long getLong(int index) {
return Long.parseLong(getString(index));
}
public int getNumber(int index) { public int getNumber(int index) {
return Integer.parseInt(getString(index)); return Integer.parseInt(getString(index));
} }

View File

@ -843,12 +843,12 @@ public class ImapStore extends Store {
class ImapFolder extends Folder { class ImapFolder extends Folder {
private String mName; private String mName;
protected volatile int mMessageCount = -1; protected volatile int mMessageCount = -1;
protected volatile int uidNext = -1; protected volatile long uidNext = -1L;
protected volatile ImapConnection mConnection; protected volatile ImapConnection mConnection;
private OpenMode mMode; private OpenMode mMode;
private volatile boolean mExists; private volatile boolean mExists;
private ImapStore store = null; private ImapStore store = null;
Map<Integer, String> msgSeqUidMap = new ConcurrentHashMap<Integer, String>(); Map<Long, String> msgSeqUidMap = new ConcurrentHashMap<Long, String>();
public ImapFolder(ImapStore nStore, String name) { public ImapFolder(ImapStore nStore, String name) {
@ -1350,7 +1350,7 @@ public class ImapStore extends Store {
return getRemoteMessageCount("FLAGGED NOT DELETED"); return getRemoteMessageCount("FLAGGED NOT DELETED");
} }
protected int getHighestUid() { protected long getHighestUid() {
try { try {
ImapSearcher searcher = new ImapSearcher() { ImapSearcher searcher = new ImapSearcher() {
public List<ImapResponse> search() throws IOException, MessagingException { public List<ImapResponse> search() throws IOException, MessagingException {
@ -1359,12 +1359,12 @@ public class ImapStore extends Store {
}; };
Message[] messages = search(searcher, null); Message[] messages = search(searcher, null);
if (messages.length > 0) { if (messages.length > 0) {
return Integer.parseInt(messages[0].getUid()); return Long.parseLong(messages[0].getUid());
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(K9.LOG_TAG, "Unable to find highest UID in folder " + getName(), e); Log.e(K9.LOG_TAG, "Unable to find highest UID in folder " + getName(), e);
} }
return -1; return -1L;
} }
@ -1404,7 +1404,7 @@ public class ImapStore extends Store {
return search(searcher, listener); return search(searcher, listener);
} }
protected Message[] getMessages(final List<Integer> mesgSeqs, final boolean includeDeleted, final MessageRetrievalListener listener) protected Message[] getMessages(final List<Long> mesgSeqs, final boolean includeDeleted, final MessageRetrievalListener listener)
throws MessagingException { throws MessagingException {
ImapSearcher searcher = new ImapSearcher() { ImapSearcher searcher = new ImapSearcher() {
public List<ImapResponse> search() throws IOException, MessagingException { public List<ImapResponse> search() throws IOException, MessagingException {
@ -1429,13 +1429,13 @@ public class ImapStore extends Store {
checkOpen(); checkOpen();
ArrayList<Message> messages = new ArrayList<Message>(); ArrayList<Message> messages = new ArrayList<Message>();
try { try {
ArrayList<Integer> uids = new ArrayList<Integer>(); ArrayList<Long> uids = new ArrayList<Long>();
List<ImapResponse> responses = searcher.search(); // List<ImapResponse> responses = searcher.search(); //
for (ImapResponse response : responses) { for (ImapResponse response : responses) {
if (response.mTag == null) { if (response.mTag == null) {
if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) { if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) {
for (int i = 1, count = response.size(); i < count; i++) { for (int i = 1, count = response.size(); i < count; i++) {
uids.add(Integer.parseInt(response.getString(i))); uids.add(response.getLong(i));
} }
} }
} }
@ -1444,10 +1444,11 @@ public class ImapStore extends Store {
// Sort the uids in numerically ascending order // Sort the uids in numerically ascending order
Collections.sort(uids); Collections.sort(uids);
for (int i = 0, count = uids.size(); i < count; i++) { for (int i = 0, count = uids.size(); i < count; i++) {
String uid = uids.get(i).toString();
if (listener != null) { if (listener != null) {
listener.messageStarted("" + uids.get(i), i, count); listener.messageStarted(uid, i, count);
} }
ImapMessage message = new ImapMessage("" + uids.get(i), this); ImapMessage message = new ImapMessage(uid, this);
messages.add(message); messages.add(message);
if (listener != null) { if (listener != null) {
listener.messageFinished(message, i, count); listener.messageFinished(message, i, count);
@ -1571,7 +1572,7 @@ public class ImapStore extends Store {
if (response.mTag == null && ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) { if (response.mTag == null && ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
ImapList fetchList = (ImapList)response.getKeyedValue("FETCH"); ImapList fetchList = (ImapList)response.getKeyedValue("FETCH");
String uid = fetchList.getKeyedString("UID"); String uid = fetchList.getKeyedString("UID");
int msgSeq = response.getNumber(0); long msgSeq = response.getLong(0);
if (uid != null) { if (uid != null) {
try { try {
msgSeqUidMap.put(msgSeq, uid); msgSeqUidMap.put(msgSeq, uid);
@ -1798,7 +1799,7 @@ public class ImapStore extends Store {
if (keyObj instanceof String) { if (keyObj instanceof String) {
String key = (String)keyObj; String key = (String)keyObj;
if ("UIDNEXT".equalsIgnoreCase(key)) { if ("UIDNEXT".equalsIgnoreCase(key)) {
uidNext = bracketed.getNumber(1); uidNext = bracketed.getLong(1);
if (K9.DEBUG) if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Got UidNext = " + uidNext + " for " + getLogId()); Log.d(K9.LOG_TAG, "Got UidNext = " + uidNext + " for " + getLogId());
} }
@ -2190,10 +2191,10 @@ public class ImapStore extends Store {
public String getNewPushState(String oldPushStateS, Message message) { public String getNewPushState(String oldPushStateS, Message message) {
try { try {
String messageUidS = message.getUid(); String messageUidS = message.getUid();
int messageUid = Integer.parseInt(messageUidS); long messageUid = Long.parseLong(messageUidS);
ImapPushState oldPushState = ImapPushState.parse(oldPushStateS); ImapPushState oldPushState = ImapPushState.parse(oldPushStateS);
if (messageUid >= oldPushState.uidNext) { if (messageUid >= oldPushState.uidNext) {
int uidNext = messageUid + 1; long uidNext = messageUid + 1;
ImapPushState newPushState = new ImapPushState(uidNext); ImapPushState newPushState = new ImapPushState(uidNext);
return newPushState.toString(); return newPushState.toString();
} else { } else {
@ -2303,8 +2304,8 @@ public class ImapStore extends Store {
capabilityList = response; capabilityList = response;
} }
if (capabilityList != null) { if (capabilityList != null && !capabilityList.isEmpty() &&
if (!capabilityList.isEmpty() && ImapResponseParser.equalsIgnoreCase(capabilityList.get(0), CAPABILITY_CAPABILITY)) { ImapResponseParser.equalsIgnoreCase(capabilityList.get(0), CAPABILITY_CAPABILITY)) {
if (K9.DEBUG) { if (K9.DEBUG) {
Log.d(K9.LOG_TAG, "Saving " + capabilityList.size() + " capabilities for " + getLogId()); Log.d(K9.LOG_TAG, "Saving " + capabilityList.size() + " capabilities for " + getLogId());
} }
@ -2317,8 +2318,6 @@ public class ImapStore extends Store {
capabilities.add(((String)capability).toUpperCase(Locale.US)); capabilities.add(((String)capability).toUpperCase(Locale.US));
} }
} }
}
} }
} }
return responses; return responses;
@ -2886,7 +2885,7 @@ public class ImapStore extends Store {
while (!stop.get()) { while (!stop.get()) {
try { try {
int oldUidNext = -1; long oldUidNext = -1L;
try { try {
String pushStateS = receiver.getPushState(getName()); String pushStateS = receiver.getPushState(getName());
ImapPushState pushState = ImapPushState.parse(pushStateS); ImapPushState pushState = ImapPushState.parse(pushStateS);
@ -2922,16 +2921,16 @@ public class ImapStore extends Store {
if (stop.get()) { if (stop.get()) {
continue; continue;
} }
int startUid = oldUidNext; long startUid = oldUidNext;
int newUidNext = uidNext; long newUidNext = uidNext;
if (newUidNext == -1) { if (newUidNext == -1) {
if (K9.DEBUG) { if (K9.DEBUG) {
Log.d(K9.LOG_TAG, "uidNext is -1, using search to find highest UID"); Log.d(K9.LOG_TAG, "uidNext is -1, using search to find highest UID");
} }
int highestUid = getHighestUid(); long highestUid = getHighestUid();
if (highestUid != -1) { if (highestUid != -1L) {
if (K9.DEBUG) if (K9.DEBUG)
Log.d(K9.LOG_TAG, "highest UID = " + highestUid); Log.d(K9.LOG_TAG, "highest UID = " + highestUid);
newUidNext = highestUid + 1; newUidNext = highestUid + 1;
@ -2952,7 +2951,7 @@ public class ImapStore extends Store {
if (K9.DEBUG) if (K9.DEBUG)
Log.i(K9.LOG_TAG, "Needs sync from uid " + startUid + " to " + newUidNext + " for " + getLogId()); Log.i(K9.LOG_TAG, "Needs sync from uid " + startUid + " to " + newUidNext + " for " + getLogId());
List<Message> messages = new ArrayList<Message>(); List<Message> messages = new ArrayList<Message>();
for (int uid = startUid; uid < newUidNext; uid++) { for (long uid = startUid; uid < newUidNext; uid++) {
ImapMessage message = new ImapMessage("" + uid, ImapFolderPusher.this); ImapMessage message = new ImapMessage("" + uid, ImapFolderPusher.this);
messages.add(message); messages.add(message);
} }
@ -3052,7 +3051,7 @@ public class ImapStore extends Store {
if (oldMessageCount == -1) { if (oldMessageCount == -1) {
skipSync = true; skipSync = true;
} }
List<Integer> flagSyncMsgSeqs = new ArrayList<Integer>(); List<Long> flagSyncMsgSeqs = new ArrayList<Long>();
List<String> removeMsgUids = new LinkedList<String>(); List<String> removeMsgUids = new LinkedList<String>();
for (ImapResponse response : responses) { for (ImapResponse response : responses) {
@ -3078,7 +3077,7 @@ public class ImapStore extends Store {
} }
private void syncMessages(int end, boolean newArrivals) throws MessagingException { private void syncMessages(int end, boolean newArrivals) throws MessagingException {
int oldUidNext = -1; long oldUidNext = -1L;
try { try {
String pushStateS = receiver.getPushState(getName()); String pushStateS = receiver.getPushState(getName());
ImapPushState pushState = ImapPushState.parse(pushStateS); ImapPushState pushState = ImapPushState.parse(pushStateS);
@ -3091,10 +3090,10 @@ public class ImapStore extends Store {
Message[] messageArray = getMessages(end, end, null, true, null); Message[] messageArray = getMessages(end, end, null, true, null);
if (messageArray != null && messageArray.length > 0) { if (messageArray != null && messageArray.length > 0) {
int newUid = Integer.parseInt(messageArray[0].getUid()); long newUid = Long.parseLong(messageArray[0].getUid());
if (K9.DEBUG) if (K9.DEBUG)
Log.i(K9.LOG_TAG, "Got newUid " + newUid + " for message " + end + " on " + getLogId()); Log.i(K9.LOG_TAG, "Got newUid " + newUid + " for message " + end + " on " + getLogId());
int startUid = oldUidNext; long startUid = oldUidNext;
if (startUid < newUid - 10) { if (startUid < newUid - 10) {
startUid = newUid - 10; startUid = newUid - 10;
} }
@ -3106,8 +3105,8 @@ public class ImapStore extends Store {
if (K9.DEBUG) if (K9.DEBUG)
Log.i(K9.LOG_TAG, "Needs sync from uid " + startUid + " to " + newUid + " for " + getLogId()); Log.i(K9.LOG_TAG, "Needs sync from uid " + startUid + " to " + newUid + " for " + getLogId());
List<Message> messages = new ArrayList<Message>(); List<Message> messages = new ArrayList<Message>();
for (int uid = startUid; uid <= newUid; uid++) { for (long uid = startUid; uid <= newUid; uid++) {
ImapMessage message = new ImapMessage("" + uid, ImapFolderPusher.this); ImapMessage message = new ImapMessage(Long.toString(uid), ImapFolderPusher.this);
messages.add(message); messages.add(message);
} }
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
@ -3117,7 +3116,7 @@ public class ImapStore extends Store {
} }
} }
private void syncMessages(List<Integer> flagSyncMsgSeqs) { private void syncMessages(List<Long> flagSyncMsgSeqs) {
try { try {
Message[] messageArray = null; Message[] messageArray = null;
@ -3160,7 +3159,7 @@ public class ImapStore extends Store {
} }
protected int processUntaggedResponse(int oldMessageCount, ImapResponse response, List<Integer> flagSyncMsgSeqs, List<String> removeMsgUids) { protected int processUntaggedResponse(long oldMessageCount, ImapResponse response, List<Long> flagSyncMsgSeqs, List<String> removeMsgUids) {
super.handleUntaggedResponse(response); super.handleUntaggedResponse(response);
int messageCountDelta = 0; int messageCountDelta = 0;
if (response.mTag == null && response.size() > 1) { if (response.mTag == null && response.size() > 1) {
@ -3168,7 +3167,7 @@ public class ImapStore extends Store {
Object responseType = response.get(1); Object responseType = response.get(1);
if (ImapResponseParser.equalsIgnoreCase(responseType, "FETCH")) { if (ImapResponseParser.equalsIgnoreCase(responseType, "FETCH")) {
Log.i(K9.LOG_TAG, "Got FETCH " + response); Log.i(K9.LOG_TAG, "Got FETCH " + response);
int msgSeq = response.getNumber(0); long msgSeq = response.getLong(0);
if (K9.DEBUG) if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Got untagged FETCH for msgseq " + msgSeq + " for " + getLogId()); Log.d(K9.LOG_TAG, "Got untagged FETCH for msgseq " + msgSeq + " for " + getLogId());
@ -3178,17 +3177,17 @@ public class ImapStore extends Store {
} }
} }
if (ImapResponseParser.equalsIgnoreCase(responseType, "EXPUNGE")) { if (ImapResponseParser.equalsIgnoreCase(responseType, "EXPUNGE")) {
int msgSeq = response.getNumber(0); long msgSeq = response.getLong(0);
if (msgSeq <= oldMessageCount) { if (msgSeq <= oldMessageCount) {
messageCountDelta = -1; messageCountDelta = -1;
} }
if (K9.DEBUG) if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Got untagged EXPUNGE for msgseq " + msgSeq + " for " + getLogId()); Log.d(K9.LOG_TAG, "Got untagged EXPUNGE for msgseq " + msgSeq + " for " + getLogId());
List<Integer> newSeqs = new ArrayList<Integer>(); List<Long> newSeqs = new ArrayList<Long>();
Iterator<Integer> flagIter = flagSyncMsgSeqs.iterator(); Iterator<Long> flagIter = flagSyncMsgSeqs.iterator();
while (flagIter.hasNext()) { while (flagIter.hasNext()) {
Integer flagMsg = flagIter.next(); long flagMsg = flagIter.next();
if (flagMsg >= msgSeq) { if (flagMsg >= msgSeq) {
flagIter.remove(); flagIter.remove();
if (flagMsg > msgSeq) { if (flagMsg > msgSeq) {
@ -3199,14 +3198,13 @@ public class ImapStore extends Store {
flagSyncMsgSeqs.addAll(newSeqs); flagSyncMsgSeqs.addAll(newSeqs);
List<Integer> msgSeqs = new ArrayList<Integer>(msgSeqUidMap.keySet()); List<Long> msgSeqs = new ArrayList<Long>(msgSeqUidMap.keySet());
Collections.sort(msgSeqs); // Have to do comparisons in order because of msgSeq reductions Collections.sort(msgSeqs); // Have to do comparisons in order because of msgSeq reductions
for (Integer msgSeqNumI : msgSeqs) { for (long msgSeqNum : msgSeqs) {
if (K9.DEBUG) { if (K9.DEBUG) {
Log.v(K9.LOG_TAG, "Comparing EXPUNGEd msgSeq " + msgSeq + " to " + msgSeqNumI); Log.v(K9.LOG_TAG, "Comparing EXPUNGEd msgSeq " + msgSeq + " to " + msgSeqNum);
} }
int msgSeqNum = msgSeqNumI;
if (msgSeqNum == msgSeq) { if (msgSeqNum == msgSeq) {
String uid = msgSeqUidMap.get(msgSeqNum); String uid = msgSeqUidMap.get(msgSeqNum);
if (K9.DEBUG) { if (K9.DEBUG) {
@ -3388,12 +3386,12 @@ public class ImapStore extends Store {
} }
protected static class ImapPushState { protected static class ImapPushState {
protected int uidNext; protected long uidNext;
protected ImapPushState(int nUidNext) { protected ImapPushState(long nUidNext) {
uidNext = nUidNext; uidNext = nUidNext;
} }
protected static ImapPushState parse(String pushState) { protected static ImapPushState parse(String pushState) {
int newUidNext = -1; long newUidNext = -1L;
if (pushState != null) { if (pushState != null) {
StringTokenizer tokenizer = new StringTokenizer(pushState, ";"); StringTokenizer tokenizer = new StringTokenizer(pushState, ";");
while (tokenizer.hasMoreTokens()) { while (tokenizer.hasMoreTokens()) {
@ -3404,8 +3402,8 @@ public class ImapStore extends Store {
if ("uidNext".equalsIgnoreCase(key) && thisState.hasMoreTokens()) { if ("uidNext".equalsIgnoreCase(key) && thisState.hasMoreTokens()) {
String value = thisState.nextToken(); String value = thisState.nextToken();
try { try {
newUidNext = Integer.parseInt(value); newUidNext = Long.parseLong(value);
} catch (Exception e) { } catch (NumberFormatException e) {
Log.e(K9.LOG_TAG, "Unable to part uidNext value " + value, e); Log.e(K9.LOG_TAG, "Unable to part uidNext value " + value, e);
} }

View File

@ -157,6 +157,8 @@ public class LocalStore extends Store implements Serializable {
AttachmentProvider.clear(mApplication); AttachmentProvider.clear(mApplication);
db.beginTransaction();
try {
try { try {
// schema version 29 was when we moved to incremental updates // schema version 29 was when we moved to incremental updates
// in the case of a new db or a < v29 db, we blow away and start from scratch // in the case of a new db or a < v29 db, we blow away and start from scratch
@ -369,6 +371,7 @@ public class LocalStore extends Store implements Serializable {
Log.e(K9.LOG_TAG, "Error trying to fix the outbox folders", e); Log.e(K9.LOG_TAG, "Error trying to fix the outbox folders", e);
} }
} }
}
if (db.getVersion() < 44) { if (db.getVersion() < 44) {
Log.d("ASH", "updatedb " + mAccount.getDescription()); Log.d("ASH", "updatedb " + mAccount.getDescription());
try { try {
@ -410,19 +413,19 @@ Log.d("ASH", "updatedb " + mAccount.getDescription());
+ e); + e);
} }
} }
} } 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.");
} }
db.setVersion(DB_VERSION); db.setVersion(DB_VERSION);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
if (db.getVersion() != DB_VERSION) { if (db.getVersion() != DB_VERSION) {
throw new Error("Database upgrade failed!"); throw new Error("Database upgrade failed!");
} }
@ -3496,11 +3499,9 @@ Log.v("ASH", mAccount.getDescription() + ":" + name + " is " + (localOnly == 1 ?
if (!isSet(Flag.DELETED)) { if (!isSet(Flag.DELETED)) {
if (flag == Flag.SEEN) { if (flag == Flag.SEEN && set != isSet(Flag.SEEN)) {
if (set != isSet(Flag.SEEN)) {
folder.setUnreadMessageCount(folder.getUnreadMessageCount() + (set ? -1 : 1)); folder.setUnreadMessageCount(folder.getUnreadMessageCount() + (set ? -1 : 1));
} }
}
if (flag == Flag.FLAGGED) { if (flag == Flag.FLAGGED) {
folder.setFlaggedMessageCount(folder.getFlaggedMessageCount() + (set ? 1 : -1)); folder.setFlaggedMessageCount(folder.getFlaggedMessageCount() + (set ? 1 : -1));

View File

@ -1996,11 +1996,6 @@ public class WebDavStore extends Store {
return false; return false;
} }
@Override
public int hashCode() {
return super.hashCode();
}
@Override @Override
public String getUidFromMessageId(Message message) throws MessagingException { public String getUidFromMessageId(Message message) throws MessagingException {
Log.e(K9.LOG_TAG, Log.e(K9.LOG_TAG,

View File

@ -54,11 +54,8 @@ public class ImapUtility {
for (String item : setItems) { for (String item : setItems) {
if (item.indexOf(':') == -1) { if (item.indexOf(':') == -1) {
// simple item // simple item
try { if (isNumberValid(item)) {
Integer.parseInt(item); // Don't need the value; just ensure it's valid
list.add(item); list.add(item);
} catch (NumberFormatException e) {
Log.d(K9.LOG_TAG, "Invalid UID value", e);
} }
} else { } else {
// range // range
@ -91,23 +88,46 @@ public class ImapUtility {
if (range != null) { if (range != null) {
int colonPos = range.indexOf(':'); int colonPos = range.indexOf(':');
if (colonPos > 0) { if (colonPos > 0) {
int first = Integer.parseInt(range.substring(0, colonPos)); long first = Long.parseLong(range.substring(0, colonPos));
int second = Integer.parseInt(range.substring(colonPos + 1)); long second = Long.parseLong(range.substring(colonPos + 1));
if (is32bitValue(first) && is32bitValue(second)) {
if (first < second) { if (first < second) {
for (int i = first; i <= second; i++) { for (long i = first; i <= second; i++) {
list.add(Integer.toString(i)); list.add(Long.toString(i));
} }
} else { } else {
for (int i = first; i >= second; i--) { for (long i = first; i >= second; i--) {
list.add(Integer.toString(i)); list.add(Long.toString(i));
} }
} }
} else {
Log.d(K9.LOG_TAG, "Invalid range: " + range);
}
} }
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Log.d(K9.LOG_TAG, "Invalid range value", e); Log.d(K9.LOG_TAG, "Invalid range value: " + range, e);
} }
return list; return list;
} }
private static boolean isNumberValid(String number) {
try {
long value = Long.parseLong(number);
if (is32bitValue(value)) {
return true;
}
} catch (NumberFormatException e) {
// do nothing
}
Log.d(K9.LOG_TAG, "Invalid UID value: " + number);
return false;
}
private static boolean is32bitValue(long value) {
return ((value & ~0xFFFFFFFFL) == 0L);
}
} }

View File

@ -188,7 +188,6 @@ public class SmtpTransport extends Transport {
String mPassword; String mPassword;
String mAuthType; String mAuthType;
int mConnectionSecurity; int mConnectionSecurity;
boolean mSecure;
Socket mSocket; Socket mSocket;
PeekableInputStream mIn; PeekableInputStream mIn;
OutputStream mOut; OutputStream mOut;
@ -245,7 +244,6 @@ public class SmtpTransport extends Transport {
}, new SecureRandom()); }, new SecureRandom());
mSocket = sslContext.getSocketFactory().createSocket(); mSocket = sslContext.getSocketFactory().createSocket();
mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT);
mSecure = true;
} else { } else {
mSocket = new Socket(); mSocket = new Socket();
mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT);
@ -308,7 +306,6 @@ public class SmtpTransport extends Transport {
mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(), mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(),
1024)); 1024));
mOut = mSocket.getOutputStream(); mOut = mSocket.getOutputStream();
mSecure = true;
/* /*
* Now resend the EHLO. Required by RFC2487 Sec. 5.2, and more specifically, * Now resend the EHLO. Required by RFC2487 Sec. 5.2, and more specifically,
* Exim. * Exim.

View File

@ -1,5 +1,6 @@
package com.fsck.k9.view; package com.fsck.k9.view;
import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.util.AttributeSet; import android.util.AttributeSet;
@ -24,6 +25,27 @@ public class MessageWebView extends WebView {
*/ */
public static final Method mGetBlockNetworkLoads = K9.getMethod(WebSettings.class, "setBlockNetworkLoads"); public static final Method mGetBlockNetworkLoads = K9.getMethod(WebSettings.class, "setBlockNetworkLoads");
/**
* Check whether the single column layout algorithm can be used on this version of Android.
*
* <p>
* Single column layout was broken on Android < 2.2 (see
* <a href="http://code.google.com/p/android/issues/detail?id=5024">issue 5024</a>).
* </p>
*
* <p>
* Android versions >= 3.0 have problems with unclickable links when single column layout is
* enabled (see
* <a href="http://code.google.com/p/android/issues/detail?id=34886">issue 34886</a>
* in Android's bug tracker, and
* <a href="http://code.google.com/p/k9mail/issues/detail?id=3820">issue 3820</a>
* in K-9 Mail's bug tracker).
*/
public static boolean isSingleColumnLayoutSupported() {
return (Build.VERSION.SDK_INT > 7 && Build.VERSION.SDK_INT < 11);
}
public MessageWebView(Context context) { public MessageWebView(Context context) {
super(context); super(context);
} }
@ -90,24 +112,13 @@ public class MessageWebView extends WebView {
webSettings.setBuiltInZoomControls(true); webSettings.setBuiltInZoomControls(true);
} }
// SINGLE_COLUMN layout was broken on Android < 2.2, so we if (isSingleColumnLayoutSupported() && K9.mobileOptimizedLayout()) {
// administratively disable it
if (Build.VERSION.SDK_INT > 7 && K9.mobileOptimizedLayout()) {
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
} else { } else {
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS); webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
} }
/* disableOverscrolling();
* Build.VERSION.SDK is deprecated cause it just returns the
* "its raw String representation"
* http://developer.android.com/reference/android/os/Build.VERSION_CODES.html#GINGERBREAD
* http://developer.android.com/reference/android/os/Build.VERSION.html#SDK
*/
if (Build.VERSION.SDK_INT >= 9) {
setOverScrollMode(OVER_SCROLL_NEVER);
}
webSettings.setTextSize(K9.getFontSizes().getMessageViewContent()); webSettings.setTextSize(K9.getFontSizes().getMessageViewContent());
@ -116,6 +127,13 @@ public class MessageWebView extends WebView {
} }
@TargetApi(9)
private void disableOverscrolling() {
if (Build.VERSION.SDK_INT >= 9) {
setOverScrollMode(OVER_SCROLL_NEVER);
}
}
public void setText(String text, String contentType) { public void setText(String text, String contentType) {
String content = text; String content = text;
if (K9.getK9Theme() == K9.THEME_DARK) { if (K9.getK9Theme() == K9.THEME_DARK) {

View File

@ -104,6 +104,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
private LinearLayout mInsideAttachmentsContainer; private LinearLayout mInsideAttachmentsContainer;
private SavedState mSavedState; private SavedState mSavedState;
private ClipboardManager mClipboardManager; private ClipboardManager mClipboardManager;
private String mText;
public void initialize(Activity activity) { public void initialize(Activity activity) {
@ -400,7 +401,10 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
break; break;
} }
case R.id.show_pictures: { case R.id.show_pictures: {
// Allow network access first...
setLoadPictures(true); setLoadPictures(true);
// ...then re-populate the WebView with the message text
loadBodyFromText(mText, "text/html");
break; break;
} }
} }
@ -538,28 +542,20 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
MessagingController controller, MessagingListener listener) throws MessagingException { MessagingController controller, MessagingListener listener) throws MessagingException {
resetView(); resetView();
String type;
String text = null; String text = null;
if (pgpData != null) { if (pgpData != null) {
text = pgpData.getDecryptedData(); text = pgpData.getDecryptedData();
} }
if (text != null) { if (text != null) {
type = "text/html";
text = "<html><body><pre>" + text + "</pre></body></html>"; text = "<html><body><pre>" + text + "</pre></body></html>";
} else { } else {
// getTextForDisplay() always returns HTML-ified content. // getTextForDisplay() always returns HTML-ified content.
text = message.getTextForDisplay(); text = message.getTextForDisplay();
type = "text/html";
}
if (text != null) {
final String emailText = text;
final String contentType = type;
loadBodyFromText(emailText, contentType);
updateCryptoLayout(account.getCryptoProvider(), pgpData, message);
} else {
showStatusMessage(getContext().getString(R.string.webview_empty_message));
} }
// Save the text so we can reset the WebView when the user clicks the "Show pictures" button
mText = text;
mHasAttachments = message.hasAttachments(); mHasAttachments = message.hasAttachments();
if (mHasAttachments) { if (mHasAttachments) {
@ -607,6 +603,13 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
} }
} }
} }
if (text != null) {
loadBodyFromText(text, "text/html");
updateCryptoLayout(account.getCryptoProvider(), pgpData, message);
} else {
showStatusMessage(getContext().getString(R.string.webview_empty_message));
}
} }
public void showStatusMessage(String status) { public void showStatusMessage(String status) {

View File

@ -34,6 +34,14 @@ public class ImapUtilityTest extends TestCase {
actual = ImapUtility.getImapSequenceValues("1"); actual = ImapUtility.getImapSequenceValues("1");
MoreAsserts.assertEquals(expected, actual.toArray()); MoreAsserts.assertEquals(expected, actual.toArray());
expected = new String[] {"2147483648"}; // Integer.MAX_VALUE + 1
actual = ImapUtility.getImapSequenceValues("2147483648");
MoreAsserts.assertEquals(expected, actual.toArray());
expected = new String[] {"4294967295"}; // 2^32 - 1
actual = ImapUtility.getImapSequenceValues("4294967295");
MoreAsserts.assertEquals(expected, actual.toArray());
expected = new String[] {"1", "3", "2"}; expected = new String[] {"1", "3", "2"};
actual = ImapUtility.getImapSequenceValues("1,3,2"); actual = ImapUtility.getImapSequenceValues("1,3,2");
MoreAsserts.assertEquals(expected, actual.toArray()); MoreAsserts.assertEquals(expected, actual.toArray());
@ -50,6 +58,11 @@ public class ImapUtilityTest extends TestCase {
actual = ImapUtility.getImapSequenceValues("1,2:4,9:7"); actual = ImapUtility.getImapSequenceValues("1,2:4,9:7");
MoreAsserts.assertEquals(expected, actual.toArray()); MoreAsserts.assertEquals(expected, actual.toArray());
// Test numbers larger than Integer.MAX_VALUE (2147483647)
expected = new String[] {"2147483646", "2147483647", "2147483648"};
actual = ImapUtility.getImapSequenceValues("2147483646:2147483648");
MoreAsserts.assertEquals(expected, actual.toArray());
// Test partially invalid sets // Test partially invalid sets
expected = new String[] { "1", "5" }; expected = new String[] { "1", "5" };
actual = ImapUtility.getImapSequenceValues("1,x,5"); actual = ImapUtility.getImapSequenceValues("1,x,5");
@ -75,6 +88,15 @@ public class ImapUtilityTest extends TestCase {
expected = new String[0]; expected = new String[0];
actual = ImapUtility.getImapSequenceValues("1:x"); actual = ImapUtility.getImapSequenceValues("1:x");
MoreAsserts.assertEquals(expected, actual.toArray()); MoreAsserts.assertEquals(expected, actual.toArray());
// Test values larger than 2^32 - 1
expected = new String[0];
actual = ImapUtility.getImapSequenceValues("4294967296:4294967297");
MoreAsserts.assertEquals(expected, actual.toArray());
expected = new String[0];
actual = ImapUtility.getImapSequenceValues("4294967296"); // 2^32
MoreAsserts.assertEquals(expected, actual.toArray());
} }
/** /**