1
0
mirror of https://github.com/moparisthebest/k-9 synced 2025-01-30 14:50:14 -05:00

Fixes Issue 227

Provide for controlling the maximum age of syncrhonized messages.
Efficient with IMAP, much less efficient with other Stores.
This commit is contained in:
Daniel Applebaum 2010-05-30 21:20:47 +00:00
parent dedfd026be
commit b35f807820
13 changed files with 269 additions and 44 deletions

View File

@ -66,6 +66,36 @@
<item>1000</item>
</string-array>
<string-array name="account_settings_message_age_entries">
<item>@string/account_settings_message_age_any</item>
<item>@string/account_settings_message_age_0</item>
<item>@string/account_settings_message_age_1</item>
<item>@string/account_settings_message_age_2</item>
<item>@string/account_settings_message_age_7</item>
<item>@string/account_settings_message_age_14</item>
<item>@string/account_settings_message_age_21</item>
<item>@string/account_settings_message_age_1_month</item>
<item>@string/account_settings_message_age_2_months</item>
<item>@string/account_settings_message_age_3_months</item>
<item>@string/account_settings_message_age_6_months</item>
<item>@string/account_settings_message_age_1_year</item>
</string-array>
<string-array name="account_settings_message_age_values">
<item>-1</item>
<item>0</item>
<item>1</item>
<item>2</item>
<item>7</item>
<item>14</item>
<item>21</item>
<item>28</item>
<item>56</item>
<item>84</item>
<item>168</item>
<item>365</item>
</string-array>
<string-array name="account_settings_folder_display_mode_entries">
<item>@string/account_settings_folder_display_mode_all</item>
<item>@string/account_settings_folder_display_mode_first_class</item>

View File

@ -446,6 +446,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
<string name="account_setup_options_mail_display_count_500">500 messages</string>
<string name="account_setup_options_mail_display_count_1000">1000 messages</string>
<string name="move_copy_cannot_copy_unsynced_message">Cannot copy or move a message that is not synchronized with the server</string>
<string name="account_setup_failed_dlg_title">Setup could not finish</string>
@ -492,6 +493,21 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
<string name="account_settings_led_color_summary">Choose the color your your phone LED should blink for this account</string>
<string name="account_settings_mail_display_count_label">Number of messages to display</string>
<string name="account_settings_message_age_label">Synchronize messages sent</string>
<string name="account_settings_message_age_any">At any time</string>
<string name="account_settings_message_age_0">Today</string>
<string name="account_settings_message_age_1">since yesterday</string>
<string name="account_settings_message_age_2">in the last 2 days</string>
<string name="account_settings_message_age_7">in the last week</string>
<string name="account_settings_message_age_14">in the last 2 weeks</string>
<string name="account_settings_message_age_21">in the last 3 weeks</string>
<string name="account_settings_message_age_1_month">in the last month</string>
<string name="account_settings_message_age_2_months">in the last 2 months</string>
<string name="account_settings_message_age_3_months">in the last 3 months</string>
<string name="account_settings_message_age_6_months">in the last 6 months</string>
<string name="account_settings_message_age_1_year">in the last year</string>
<string name="account_settings_folder_display_mode_label">Folders to display</string>
<string name="account_settings_folder_display_mode_all">All</string>

View File

@ -39,7 +39,8 @@
android:title="@string/account_settings_mail_display_count_label"
android:entries="@array/account_settings_display_count_entries"
android:entryValues="@array/account_settings_display_count_values"
android:dialogTitle="@string/account_settings_mail_display_count_label" />
android:dialogTitle="@string/account_settings_mail_display_count_label" />
<Preference
android:key="chip_color"
android:singleLine="true"
@ -72,6 +73,13 @@
android:entries="@array/account_settings_check_frequency_entries"
android:entryValues="@array/account_settings_check_frequency_values"
android:dialogTitle="@string/account_settings_mail_check_frequency_label" />
<ListPreference
android:key="account_message_age"
android:title="@string/account_settings_message_age_label"
android:entries="@array/account_settings_message_age_entries"
android:entryValues="@array/account_settings_message_age_values"
android:dialogTitle="@string/account_settings_message_age_label" />
<ListPreference
android:key="folder_sync_mode"

View File

@ -16,6 +16,8 @@ import com.fsck.k9.mail.store.LocalStore;
import com.fsck.k9.mail.store.LocalStore.LocalFolder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
@ -91,6 +93,7 @@ public class Account implements BaseAccount
private Map<String, Boolean> compressionMap = new ConcurrentHashMap<String, Boolean>();
private Searchable searchableFolders;
private boolean subscribedFoldersOnly;
private int maximumPolledMessageAge;
// Tracks if we have sent a notification for this account for
// current set of fetched messages
private boolean mRingNotified;
@ -142,6 +145,7 @@ public class Account implements BaseAccount
mLedColor = mChipColor;
goToUnreadMessageSearch = false;
subscribedFoldersOnly = false;
maximumPolledMessageAge = 10;
searchableFolders = Searchable.ALL;
@ -180,7 +184,7 @@ public class Account implements BaseAccount
+ ".saveAllHeaders", false);
mPushPollOnConnect = preferences.getPreferences().getBoolean(mUuid
+ ".pushPollOnConnect", true);
mDisplayCount = preferences.getPreferences().getInt(mUuid + ".displayCount", -1);
mDisplayCount = preferences.getPreferences().getInt(mUuid + ".displayCount", K9.DEFAULT_VISIBLE_LIMIT);
mLastAutomaticCheckTime = preferences.getPreferences().getLong(mUuid
+ ".lastAutomaticCheckTime", 0);
mNotifyNewMail = preferences.getPreferences().getBoolean(mUuid + ".notifyNewMail",
@ -205,6 +209,8 @@ public class Account implements BaseAccount
false);
subscribedFoldersOnly = preferences.getPreferences().getBoolean(mUuid + ".subscribedFoldersOnly",
false);
maximumPolledMessageAge = preferences.getPreferences().getInt(mUuid
+ ".maximumPolledMessageAge", -1);
for (String type : networkTypes)
{
Boolean useCompression = preferences.getPreferences().getBoolean(mUuid + ".useCompression." + type,
@ -375,6 +381,7 @@ public class Account implements BaseAccount
editor.remove(mUuid + ".ledColor");
editor.remove(mUuid + ".goToUnreadMessageSearch");
editor.remove(mUuid + ".subscribedFoldersOnly");
editor.remove(mUuid + ".maximumPolledMessageAge");
for (String type : networkTypes)
{
editor.remove(mUuid + ".useCompression." + type);
@ -459,7 +466,8 @@ public class Account implements BaseAccount
editor.putInt(mUuid + ".ledColor", mLedColor);
editor.putBoolean(mUuid + ".goToUnreadMessageSearch", goToUnreadMessageSearch);
editor.putBoolean(mUuid + ".subscribedFoldersOnly", subscribedFoldersOnly);
editor.putInt(mUuid + ".maximumPolledMessageAge", maximumPolledMessageAge);
for (String type : networkTypes)
{
Boolean useCompression = compressionMap.get(type);
@ -718,10 +726,6 @@ public class Account implements BaseAccount
public synchronized int getDisplayCount()
{
if (mDisplayCount == -1)
{
this.mDisplayCount = K9.DEFAULT_VISIBLE_LIMIT;
}
return mDisplayCount;
}
@ -1218,4 +1222,54 @@ public class Account implements BaseAccount
{
this.subscribedFoldersOnly = subscribedFoldersOnly;
}
public int getMaximumPolledMessageAge()
{
return maximumPolledMessageAge;
}
public void setMaximumPolledMessageAge(int maximumPolledMessageAge)
{
this.maximumPolledMessageAge = maximumPolledMessageAge;
}
public Date getEarliestPollDate()
{
int age = getMaximumPolledMessageAge();
if (age < 0 == false)
{
Calendar now = Calendar.getInstance();
now.set(Calendar.HOUR_OF_DAY, 0);
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
if (age < 28)
{
now.add(Calendar.DATE, age * -1);
}
else switch (age)
{
case 28:
now.add(Calendar.MONTH, -1);
break;
case 56:
now.add(Calendar.MONTH, -2);
break;
case 84:
now.add(Calendar.MONTH, -3);
break;
case 168:
now.add(Calendar.MONTH, -6);
break;
case 365:
now.add(Calendar.YEAR, -1);
break;
}
return now.getTime();
}
else
{
return null;
}
}
}

View File

@ -52,6 +52,7 @@ public class AccountSettings extends K9PreferenceActivity
private static final String PREFERENCE_CHIP_COLOR = "chip_color";
private static final String PREFERENCE_LED_COLOR = "led_color";
private static final String PREFERENCE_NOTIFICATION_OPENS_UNREAD = "notification_opens_unread";
private static final String PREFERENCE_MESSAGE_AGE = "account_message_age";
@ -60,6 +61,7 @@ public class AccountSettings extends K9PreferenceActivity
private EditTextPreference mAccountDescription;
private ListPreference mCheckFrequency;
private ListPreference mDisplayCount;
private ListPreference mMessageAge;
private CheckBoxPreference mAccountDefault;
private CheckBoxPreference mAccountNotify;
private CheckBoxPreference mAccountNotifySelf;
@ -267,6 +269,21 @@ public class AccountSettings extends K9PreferenceActivity
return false;
}
});
mMessageAge = (ListPreference) findPreference(PREFERENCE_MESSAGE_AGE);
mMessageAge.setValue(String.valueOf(mAccount.getMaximumPolledMessageAge()));
mMessageAge.setSummary(mMessageAge.getEntry());
mMessageAge.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mMessageAge.findIndexOfValue(summary);
mMessageAge.setSummary(mMessageAge.getEntries()[index]);
mMessageAge.setValue(summary);
return false;
}
});
mAccountDefault = (CheckBoxPreference) findPreference(PREFERENCE_DEFAULT);
mAccountDefault.setChecked(
@ -417,6 +434,7 @@ public class AccountSettings extends K9PreferenceActivity
mAccount.setNotifySelfNewMail(mAccountNotifySelf.isChecked());
mAccount.setShowOngoing(mAccountNotifySync.isChecked());
mAccount.setDisplayCount(Integer.parseInt(mDisplayCount.getValue()));
mAccount.setMaximumPolledMessageAge(Integer.parseInt(mMessageAge.getValue()));
mAccount.setVibrate(mAccountVibrate.isChecked());
mAccount.setGoToUnreadMessageSearch(mNotificationOpensUnread.isChecked());
mAccount.setFolderTargetMode(Account.FolderMode.valueOf(mTargetMode.getValue()));

View File

@ -4,6 +4,7 @@ package com.fsck.k9.controller;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@ -1139,16 +1140,17 @@ public class MessagingController implements Runnable
Log.v(K9.LOG_TAG, "SYNC: About to open remote folder " + folder);
remoteFolder.open(OpenMode.READ_WRITE);
if (Account.EXPUNGE_ON_POLL.equals(account.getExpungePolicy()))
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "SYNC: Expunging folder " + account.getDescription() + ":" + folder);
remoteFolder.expunge();
}
}
if (Account.EXPUNGE_ON_POLL.equals(account.getExpungePolicy()))
{
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "SYNC: Expunging folder " + account.getDescription() + ":" + folder);
remoteFolder.expunge();
}
/*
* Get the remote message count.
*/
@ -1163,7 +1165,7 @@ public class MessagingController implements Runnable
if (K9.DEBUG)
Log.v(K9.LOG_TAG, "SYNC: Remote message count for folder " + folder + " is " + remoteMessageCount);
final Date earliestDate = account.getEarliestPollDate();
if (remoteMessageCount > 0)
{
/*
@ -1175,11 +1177,15 @@ public class MessagingController implements Runnable
if (K9.DEBUG)
Log.v(K9.LOG_TAG, "SYNC: About to get messages " + remoteStart + " through " + remoteEnd + " for folder " + folder);
remoteMessageArray = remoteFolder.getMessages(remoteStart, remoteEnd, null);
remoteMessageArray = remoteFolder.getMessages(remoteStart, remoteEnd, earliestDate, null);
for (Message thisMess : remoteMessageArray)
{
remoteMessages.add(thisMess);
remoteUidMap.put(thisMess.getUid(), thisMess);
Message localMessage = localUidMap.get(thisMess.getUid());
if (localMessage == null || localMessage.olderThan(earliestDate) == false)
{
remoteMessages.add(thisMess);
remoteUidMap.put(thisMess.getUid(), thisMess);
}
}
if (K9.DEBUG)
Log.v(K9.LOG_TAG, "SYNC: Got " + remoteUidMap.size() + " messages for folder " + folder);
@ -1193,8 +1199,9 @@ public class MessagingController implements Runnable
}
/*
* Remove any messages that are in the local store but no longer on the remote store.
* Remove any messages that are in the local store but no longer on the remote store or are too old
*/
for (Message localMessage : localMessages)
{
if (remoteUidMap.get(localMessage.getUid()) == null && !localMessage.isSet(Flag.DELETED))
@ -1370,6 +1377,14 @@ public class MessagingController implements Runnable
private int downloadMessages(final Account account, final Folder remoteFolder,
final LocalFolder localFolder, List<Message> inputMessages, boolean flagSyncOnly) throws MessagingException
{
final Date earliestDate = account.getEarliestPollDate();
if (earliestDate != null)
{
if (K9.DEBUG)
{
Log.d(K9.LOG_TAG, "Only syncing messages after " + earliestDate);
}
}
final String folder = remoteFolder.getName();
ArrayList<Message> syncFlagMessages = new ArrayList<Message>();
@ -1500,14 +1515,31 @@ public class MessagingController implements Runnable
{
localFolder.setPushState(newPushState);
}
if (message.isSet(Flag.DELETED))
if (message.isSet(Flag.DELETED) || message.olderThan(earliestDate))
{
if (K9.DEBUG)
Log.v(K9.LOG_TAG, "Newly downloaded message " + account + ":" + folder + ":" + message.getUid()
+ " was already deleted on server, skipping");
{
if (message.isSet(Flag.DELETED))
{
Log.v(K9.LOG_TAG, "Newly downloaded message " + account + ":" + folder + ":" + message.getUid()
+ " was already deleted on server, skipping");
}
else
{
Log.d(K9.LOG_TAG, "Newly downloaded message " + message.getUid() + " is older than "
+ earliestDate + ", skipping");
}
}
progress.incrementAndGet();
for (MessagingListener l : getListeners())
{
l.synchronizeMailboxProgress(account, folder, progress.get(), todo);
}
return;
}
// Store the new message locally
localFolder.appendMessages(new Message[]
{
@ -1611,10 +1643,23 @@ public class MessagingController implements Runnable
{
try
{
if (message.olderThan(earliestDate))
{
if (K9.DEBUG)
{
Log.d(K9.LOG_TAG, "Message " + message.getUid() + " is older than "
+ earliestDate + ", hence not saving");
}
progress.incrementAndGet();
return;
}
// Store the updated message locally
localFolder.appendMessages(new Message[] { message });
Message localMessage = localFolder.getMessage(message.getUid());
progress.incrementAndGet();
// Set a flag indicating this message has now be fully downloaded
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true);
@ -1622,8 +1667,6 @@ public class MessagingController implements Runnable
Log.v(K9.LOG_TAG, "About to notify listeners that we got a new small message "
+ account + ":" + folder + ":" + message.getUid());
progress.incrementAndGet();
// Update the listener with what we've found
for (MessagingListener l : getListeners())
{
@ -1677,6 +1720,17 @@ public class MessagingController implements Runnable
remoteFolder.fetch(largeMessages.toArray(new Message[largeMessages.size()]), fp, null);
for (Message message : largeMessages)
{
if (message.olderThan(earliestDate))
{
if (K9.DEBUG)
{
Log.d(K9.LOG_TAG, "Message " + message.getUid() + " is older than "
+ earliestDate + ", hence not saving");
}
progress.incrementAndGet();
continue;
}
if (message.getBody() == null)
{
/*
@ -1694,6 +1748,7 @@ public class MessagingController implements Runnable
*/
remoteFolder.fetch(new Message[] { message }, fp, null);
// Store the updated message locally
localFolder.appendMessages(new Message[] { message });

View File

@ -1,5 +1,7 @@
package com.fsck.k9.mail;
import java.util.Date;
import com.fsck.k9.Account;
import com.fsck.k9.Preferences;
import com.fsck.k9.controller.MessageRetrievalListener;
@ -82,7 +84,7 @@ public abstract class Folder
public abstract Message getMessage(String uid) throws MessagingException;
public abstract Message[] getMessages(int start, int end, MessageRetrievalListener listener)
public abstract Message[] getMessages(int start, int end, Date earliestDate, MessageRetrievalListener listener)
throws MessagingException;
/**

View File

@ -5,6 +5,9 @@ import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.activity.MessageReference;
public abstract class Message implements Part, Body
@ -23,7 +26,28 @@ public abstract class Message implements Part, Body
protected Date mInternalDate;
protected Folder mFolder;
public boolean olderThan(Date earliestDate)
{
if (earliestDate == null)
{
return false;
}
Date myDate = getSentDate();
if (myDate == null)
{
myDate = getInternalDate();
}
if (myDate == null)
{
myDate = getReceivedDate();
}
if (myDate != null)
{
return myDate.before(earliestDate);
}
return false;
}
@Override
public boolean equals(Object o)
{
@ -79,9 +103,9 @@ public abstract class Message implements Part, Body
this.mInternalDate = internalDate;
}
public abstract Date getReceivedDate() throws MessagingException;
public abstract Date getReceivedDate();
public abstract Date getSentDate() throws MessagingException;
public abstract Date getSentDate();
public abstract void setSentDate(Date sentDate) throws MessagingException;

View File

@ -76,13 +76,13 @@ public class MimeMessage extends Message
}
@Override
public Date getReceivedDate() throws MessagingException
public Date getReceivedDate()
{
return null;
}
@Override
public Date getSentDate() throws MessagingException
public Date getSentDate()
{
if (mSentDate == null)
{

View File

@ -43,6 +43,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
@ -91,6 +92,8 @@ public class ImapStore extends Store
private volatile String mPathPrefix;
private volatile String mCombinedPrefix = null;
private volatile String mPathDelimeter = null;
private static final SimpleDateFormat RFC3501_DATE = new SimpleDateFormat("dd-MMM-yyyy");
private LinkedList<ImapConnection> mConnections =
new LinkedList<ImapConnection>();
@ -1000,13 +1003,13 @@ public class ImapStore extends Store
@Override
public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
public Message[] getMessages(int start, int end, Date earliestDate, MessageRetrievalListener listener)
throws MessagingException
{
return getMessages(start, end, false, listener);
return getMessages(start, end, earliestDate, false, listener);
}
protected Message[] getMessages(final int start, final int end, final boolean includeDeleted, final MessageRetrievalListener listener)
protected Message[] getMessages(final int start, final int end, Date earliestDate, final boolean includeDeleted, final MessageRetrievalListener listener)
throws MessagingException
{
if (start < 1 || end < 1 || end < start)
@ -1015,11 +1018,22 @@ public class ImapStore extends Store
String.format("Invalid message set %d %d",
start, end));
}
final StringBuilder dateSearchString = new StringBuilder();
if (earliestDate != null)
{
dateSearchString.append("SINCE ");
synchronized(RFC3501_DATE)
{
dateSearchString.append(RFC3501_DATE.format(earliestDate));
}
}
ImapSearcher searcher = new ImapSearcher()
{
public List<ImapResponse> search() throws IOException, MessagingException
{
return executeSimpleCommand(String.format("UID SEARCH %d:%d" + (includeDeleted ? "" : " NOT DELETED"), start, end));
return executeSimpleCommand(String.format("UID SEARCH %d:%d %s " + (includeDeleted ? "" : " NOT DELETED"), start, end, dateSearchString));
}
};
return search(searcher, listener);
@ -2008,7 +2022,10 @@ public class ImapStore extends Store
throws MessagingException
{
Log.e(K9.LOG_TAG, "IOException for " + getLogId(), ioe);
connection.close();
if (connection != null)
{
connection.close();
}
close();
return new MessagingException("IO Error", ioe);
}
@ -3099,7 +3116,7 @@ public class ImapStore extends Store
Log.e(K9.LOG_TAG, "Unable to get oldUidNext for " + getLogId(), e);
}
Message[] messageArray = getMessages(end, end, true, null);
Message[] messageArray = getMessages(end, end, null, true, null);
if (messageArray != null && messageArray.length > 0)
{
int newUid = Integer.parseInt(messageArray[0].getUid());

View File

@ -534,7 +534,7 @@ public class LocalStore extends Store implements Serializable
public void resetVisibleLimits()
{
resetVisibleLimits(K9.DEFAULT_VISIBLE_LIMIT);
resetVisibleLimits(mAccount.getDisplayCount());
}
public void resetVisibleLimits(int visibleLimit)
@ -962,7 +962,7 @@ public class LocalStore extends Store implements Serializable
mDb.execSQL("INSERT INTO folders (name, visible_limit) VALUES (?, ?)", new Object[]
{
mName,
K9.DEFAULT_VISIBLE_LIMIT
mAccount.getDisplayCount()
});
return true;
}
@ -1445,7 +1445,7 @@ public class LocalStore extends Store implements Serializable
}
@Override
public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
public Message[] getMessages(int start, int end, Date earliestDate, MessageRetrievalListener listener)
throws MessagingException
{
open(OpenMode.READ_WRITE);

View File

@ -20,6 +20,7 @@ import java.net.*;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.HashSet;
@ -435,7 +436,7 @@ public class Pop3Store extends Store
}
@Override
public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
public Message[] getMessages(int start, int end, Date earliestDate, MessageRetrievalListener listener)
throws MessagingException
{
if (start < 1 || end < 1 || end < start)

View File

@ -1393,7 +1393,7 @@ public class WebDavStore extends Store
}
@Override
public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
public Message[] getMessages(int start, int end, Date earliestDate, MessageRetrievalListener listener)
throws MessagingException
{
ArrayList<Message> messages = new ArrayList<Message>();