mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-24 02:12:15 -05:00
Major IMAP IDLE rework:
1) Actual message sync on MessagingController uses same connection as IDLE for faster and more efficient push operation. Uses fewer connections to the server. 2) More aggressive handling of untagged responses should more reliably get flag changes and new messages when many events happen at once. 3) Simplification of new mail notification 4) Push mail now respects the folder visible limit 5) When multiple untagged FETCH responses arrive en bloc, the actual message flags and UIDs are fetched with a single request
This commit is contained in:
parent
e4427f4f17
commit
fc91603429
@ -52,6 +52,7 @@ import com.android.email.mail.FetchProfile;
|
|||||||
import com.android.email.mail.Flag;
|
import com.android.email.mail.Flag;
|
||||||
import com.android.email.mail.Folder;
|
import com.android.email.mail.Folder;
|
||||||
import com.android.email.mail.Message;
|
import com.android.email.mail.Message;
|
||||||
|
import com.android.email.mail.MessageRemovalListener;
|
||||||
import com.android.email.mail.MessageRetrievalListener;
|
import com.android.email.mail.MessageRetrievalListener;
|
||||||
import com.android.email.mail.MessagingException;
|
import com.android.email.mail.MessagingException;
|
||||||
import com.android.email.mail.Part;
|
import com.android.email.mail.Part;
|
||||||
@ -1061,7 +1062,7 @@ public class MessagingController implements Runnable
|
|||||||
/*
|
/*
|
||||||
* Now we download the actual content of messages.
|
* Now we download the actual content of messages.
|
||||||
*/
|
*/
|
||||||
int newMessages = downloadMessages(account, remoteFolder, localFolder, remoteMessages);
|
int newMessages = downloadMessages(account, remoteFolder, localFolder, remoteMessages, false);
|
||||||
|
|
||||||
setLocalUnreadCountToRemote(localFolder, remoteFolder, newMessages);
|
setLocalUnreadCountToRemote(localFolder, remoteFolder, newMessages);
|
||||||
|
|
||||||
@ -1163,22 +1164,14 @@ public class MessagingController implements Runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int downloadMessages(final Account account, final Folder remoteFolder,
|
private int downloadMessages(final Account account, final Folder remoteFolder,
|
||||||
final LocalFolder localFolder, List<Message> inputMessages) throws MessagingException
|
final LocalFolder localFolder, List<Message> inputMessages, boolean flagSyncOnly) throws MessagingException
|
||||||
{
|
{
|
||||||
final String folder = remoteFolder.getName();
|
final String folder = remoteFolder.getName();
|
||||||
|
|
||||||
ArrayList<Message> syncFlagMessages = new ArrayList<Message>();
|
ArrayList<Message> syncFlagMessages = new ArrayList<Message>();
|
||||||
ArrayList<Message> unsyncedMessages = new ArrayList<Message>();
|
List<Message> unsyncedMessages = new ArrayList<Message>();
|
||||||
final AtomicInteger newMessages = new AtomicInteger(0);
|
final AtomicInteger newMessages = new AtomicInteger(0);
|
||||||
|
|
||||||
int visibleLimit = localFolder.getVisibleLimit();
|
|
||||||
int listSize = inputMessages.size();
|
|
||||||
|
|
||||||
if (listSize > visibleLimit)
|
|
||||||
{
|
|
||||||
inputMessages = inputMessages.subList(listSize - visibleLimit, listSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Message> messages = new ArrayList<Message>(inputMessages);
|
List<Message> messages = new ArrayList<Message>(inputMessages);
|
||||||
|
|
||||||
for (Message message : messages)
|
for (Message message : messages)
|
||||||
@ -1189,35 +1182,38 @@ public class MessagingController implements Runnable
|
|||||||
|
|
||||||
if (localMessage == null)
|
if (localMessage == null)
|
||||||
{
|
{
|
||||||
if (!message.isSet(Flag.X_DOWNLOADED_FULL) && !message.isSet(Flag.X_DOWNLOADED_PARTIAL))
|
if (!flagSyncOnly)
|
||||||
{
|
{
|
||||||
if (Email.DEBUG)
|
if (!message.isSet(Flag.X_DOWNLOADED_FULL) && !message.isSet(Flag.X_DOWNLOADED_PARTIAL))
|
||||||
{
|
{
|
||||||
Log.v(Email.LOG_TAG, "Message with uid " + message.getUid() + " is not downloaded at all");
|
if (Email.DEBUG)
|
||||||
}
|
|
||||||
|
|
||||||
unsyncedMessages.add(message);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Email.DEBUG)
|
|
||||||
{
|
|
||||||
Log.v(Email.LOG_TAG, "Message with uid " + message.getUid() + " is partially or fully downloaded");
|
|
||||||
}
|
|
||||||
// Store the updated message locally
|
|
||||||
localFolder.appendMessages(new Message[] { message });
|
|
||||||
|
|
||||||
localMessage = localFolder.getMessage(message.getUid());
|
|
||||||
|
|
||||||
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, message.isSet(Flag.X_DOWNLOADED_FULL));
|
|
||||||
localMessage.setFlag(Flag.X_DOWNLOADED_PARTIAL, message.isSet(Flag.X_DOWNLOADED_PARTIAL));
|
|
||||||
|
|
||||||
for (MessagingListener l : getListeners())
|
|
||||||
{
|
|
||||||
l.synchronizeMailboxAddOrUpdateMessage(account, folder, localMessage);
|
|
||||||
if (!localMessage.isSet(Flag.SEEN))
|
|
||||||
{
|
{
|
||||||
l.synchronizeMailboxNewMessage(account, folder, localMessage);
|
Log.v(Email.LOG_TAG, "Message with uid " + message.getUid() + " is not downloaded at all");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsyncedMessages.add(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Email.DEBUG)
|
||||||
|
{
|
||||||
|
Log.v(Email.LOG_TAG, "Message with uid " + message.getUid() + " is partially or fully downloaded");
|
||||||
|
}
|
||||||
|
// Store the updated message locally
|
||||||
|
localFolder.appendMessages(new Message[] { message });
|
||||||
|
|
||||||
|
localMessage = localFolder.getMessage(message.getUid());
|
||||||
|
|
||||||
|
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, message.isSet(Flag.X_DOWNLOADED_FULL));
|
||||||
|
localMessage.setFlag(Flag.X_DOWNLOADED_PARTIAL, message.isSet(Flag.X_DOWNLOADED_PARTIAL));
|
||||||
|
|
||||||
|
for (MessagingListener l : getListeners())
|
||||||
|
{
|
||||||
|
l.synchronizeMailboxAddOrUpdateMessage(account, folder, localMessage);
|
||||||
|
if (!localMessage.isSet(Flag.SEEN))
|
||||||
|
{
|
||||||
|
l.synchronizeMailboxNewMessage(account, folder, localMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1251,6 +1247,13 @@ public class MessagingController implements Runnable
|
|||||||
* fetch results for newest to oldest. If not, no harm done.
|
* fetch results for newest to oldest. If not, no harm done.
|
||||||
*/
|
*/
|
||||||
Collections.reverse(unsyncedMessages);
|
Collections.reverse(unsyncedMessages);
|
||||||
|
int visibleLimit = localFolder.getVisibleLimit();
|
||||||
|
int listSize = unsyncedMessages.size();
|
||||||
|
|
||||||
|
if (listSize > visibleLimit)
|
||||||
|
{
|
||||||
|
unsyncedMessages = unsyncedMessages.subList(listSize - visibleLimit, listSize);
|
||||||
|
}
|
||||||
|
|
||||||
FetchProfile fp = new FetchProfile();
|
FetchProfile fp = new FetchProfile();
|
||||||
if (remoteFolder.supportsFetchingFlags())
|
if (remoteFolder.supportsFetchingFlags())
|
||||||
@ -1281,9 +1284,9 @@ public class MessagingController implements Runnable
|
|||||||
|
|
||||||
// Store the new message locally
|
// Store the new message locally
|
||||||
localFolder.appendMessages(new Message[]
|
localFolder.appendMessages(new Message[]
|
||||||
{
|
{
|
||||||
message
|
message
|
||||||
});
|
});
|
||||||
|
|
||||||
if (message.getSize() > (MAX_SMALL_MESSAGE_SIZE))
|
if (message.getSize() > (MAX_SMALL_MESSAGE_SIZE))
|
||||||
{
|
{
|
||||||
@ -1556,6 +1559,19 @@ public class MessagingController implements Runnable
|
|||||||
}
|
}
|
||||||
Log.i(Email.LOG_TAG, "SYNC: Synced remote messages for folder " + folder + ", " + newMessages.get() + " new messages");
|
Log.i(Email.LOG_TAG, "SYNC: Synced remote messages for folder " + folder + ", " + newMessages.get() + " new messages");
|
||||||
|
|
||||||
|
localFolder.purgeToVisibleLimit(new MessageRemovalListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void messageRemoved(Message message)
|
||||||
|
{
|
||||||
|
for (MessagingListener l : getListeners())
|
||||||
|
{
|
||||||
|
l.synchronizeMailboxRemovedMessage(account, folder, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
return newMessages.get();
|
return newMessages.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2072,7 +2088,7 @@ public class MessagingController implements Runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
String rootCauseMessage = getRootCauseMessage(t);
|
String rootCauseMessage = getRootCauseMessage(t);
|
||||||
log("Error" + "'" + rootCauseMessage + "'");
|
Log.e(Email.LOG_TAG, "Error " + "'" + rootCauseMessage + "'", t);
|
||||||
|
|
||||||
Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication);
|
Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication);
|
||||||
LocalFolder localFolder = (LocalFolder)localStore.getFolder(account.getErrorFolderName());
|
LocalFolder localFolder = (LocalFolder)localStore.getFolder(account.getErrorFolderName());
|
||||||
@ -2474,9 +2490,9 @@ public class MessagingController implements Runnable
|
|||||||
fp.add(FetchProfile.Item.ENVELOPE);
|
fp.add(FetchProfile.Item.ENVELOPE);
|
||||||
fp.add(FetchProfile.Item.BODY);
|
fp.add(FetchProfile.Item.BODY);
|
||||||
localFolder.fetch(new Message[]
|
localFolder.fetch(new Message[]
|
||||||
{
|
{
|
||||||
message
|
message
|
||||||
}, fp, null);
|
}, fp, null);
|
||||||
localFolder.close(false);
|
localFolder.close(false);
|
||||||
if (!message.isSet(Flag.SEEN))
|
if (!message.isSet(Flag.SEEN))
|
||||||
{
|
{
|
||||||
@ -2753,9 +2769,9 @@ public class MessagingController implements Runnable
|
|||||||
(LocalFolder) localStore.getFolder(account.getOutboxFolderName());
|
(LocalFolder) localStore.getFolder(account.getOutboxFolderName());
|
||||||
localFolder.open(OpenMode.READ_WRITE);
|
localFolder.open(OpenMode.READ_WRITE);
|
||||||
localFolder.appendMessages(new Message[]
|
localFolder.appendMessages(new Message[]
|
||||||
{
|
{
|
||||||
message
|
message
|
||||||
});
|
});
|
||||||
Message localMessage = localFolder.getMessage(message.getUid());
|
Message localMessage = localFolder.getMessage(message.getUid());
|
||||||
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true);
|
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true);
|
||||||
localFolder.close(false);
|
localFolder.close(false);
|
||||||
@ -3799,9 +3815,9 @@ public class MessagingController implements Runnable
|
|||||||
(LocalFolder) localStore.getFolder(account.getDraftsFolderName());
|
(LocalFolder) localStore.getFolder(account.getDraftsFolderName());
|
||||||
localFolder.open(OpenMode.READ_WRITE);
|
localFolder.open(OpenMode.READ_WRITE);
|
||||||
localFolder.appendMessages(new Message[]
|
localFolder.appendMessages(new Message[]
|
||||||
{
|
{
|
||||||
message
|
message
|
||||||
});
|
});
|
||||||
Message localMessage = localFolder.getMessage(message.getUid());
|
Message localMessage = localFolder.getMessage(message.getUid());
|
||||||
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true);
|
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true);
|
||||||
|
|
||||||
@ -3989,15 +4005,15 @@ public class MessagingController implements Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void messagesFlagsChanged(String folderName,
|
public void messagesFlagsChanged(Folder folder,
|
||||||
List<Message> messages)
|
List<Message> messages)
|
||||||
{
|
{
|
||||||
controller.messagesArrived(account, folderName, messages, false);
|
controller.messagesArrived(account, folder, messages, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
public void messagesArrived(String folderName, List<Message> messages)
|
public void messagesArrived(Folder folder, List<Message> messages)
|
||||||
{
|
{
|
||||||
controller.messagesArrived(account, folderName, messages, true);
|
controller.messagesArrived(account, folder, messages, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sleep(long millis)
|
public void sleep(long millis)
|
||||||
@ -4152,44 +4168,37 @@ public class MessagingController implements Runnable
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void messagesArrived(final Account account, final String folderName, final List<Message> messages, final boolean doNotify)
|
public void messagesArrived(final Account account, final Folder remoteFolder, final List<Message> messages, final boolean flagSyncOnly)
|
||||||
{
|
{
|
||||||
Log.i(Email.LOG_TAG, "Got new pushed email messages for account " + account.getDescription()
|
Log.i(Email.LOG_TAG, "Got new pushed email messages for account " + account.getDescription()
|
||||||
+ ", folder " + folderName);
|
+ ", folder " + remoteFolder.getName());
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
putBackground("Push messageArrived of account " + account.getDescription()
|
putBackground("Push messageArrived of account " + account.getDescription()
|
||||||
+ ", folder " + folderName, null, new Runnable()
|
+ ", folder " + remoteFolder.getName(), null, new Runnable()
|
||||||
{
|
{
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
LocalFolder localFolder = null;
|
LocalFolder localFolder = null;
|
||||||
Folder remoteFolder = null;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LocalStore localStore = (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication);
|
LocalStore localStore = (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication);
|
||||||
Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication);
|
localFolder= (LocalFolder) localStore.getFolder(remoteFolder.getName());
|
||||||
remoteFolder = remoteStore.getFolder(folderName);
|
|
||||||
localFolder= (LocalFolder) localStore.getFolder(folderName);
|
|
||||||
localFolder.open(OpenMode.READ_WRITE);
|
localFolder.open(OpenMode.READ_WRITE);
|
||||||
remoteFolder.open(OpenMode.READ_WRITE);
|
remoteFolder.open(OpenMode.READ_WRITE);
|
||||||
|
|
||||||
int newCount = downloadMessages(account, remoteFolder, localFolder, messages);
|
int newCount = downloadMessages(account, remoteFolder, localFolder, messages, flagSyncOnly);
|
||||||
|
setLocalUnreadCountToRemote(localFolder, remoteFolder, messages.size());
|
||||||
|
|
||||||
localFolder.setLastPush(System.currentTimeMillis());
|
localFolder.setLastPush(System.currentTimeMillis());
|
||||||
localFolder.setStatus(null);
|
localFolder.setStatus(null);
|
||||||
|
|
||||||
int unreadMessageCount = account.getUnreadMessageCount(mApplication, mApplication);
|
int unreadMessageCount = account.getUnreadMessageCount(mApplication, mApplication);
|
||||||
if (doNotify && newCount > 0 && unreadMessageCount > 0)
|
Log.i(Email.LOG_TAG, "messagesArrived newCount = " + newCount + ", unreadMessageCount = " + unreadMessageCount);
|
||||||
{
|
notifyAccount(mApplication, account, newCount, unreadMessageCount);
|
||||||
notifyAccount(mApplication, account, newCount, unreadMessageCount);
|
|
||||||
}
|
|
||||||
if (unreadMessageCount == 0)
|
|
||||||
{
|
|
||||||
notifyAccount(mApplication, account, newCount, unreadMessageCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (MessagingListener l : getListeners())
|
for (MessagingListener l : getListeners())
|
||||||
{
|
{
|
||||||
l.folderStatusChanged(account, folderName);
|
l.folderStatusChanged(account, remoteFolder.getName());
|
||||||
l.accountStatusChanged(account, unreadMessageCount);
|
l.accountStatusChanged(account, unreadMessageCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4208,7 +4217,7 @@ public class MessagingController implements Runnable
|
|||||||
}
|
}
|
||||||
for (MessagingListener l : getListeners())
|
for (MessagingListener l : getListeners())
|
||||||
{
|
{
|
||||||
l.synchronizeMailboxFailed(account, folderName, errorMessage);
|
l.synchronizeMailboxFailed(account, remoteFolder.getName(), errorMessage);
|
||||||
}
|
}
|
||||||
addErrorMessage(account, e);
|
addErrorMessage(account, e);
|
||||||
}
|
}
|
||||||
@ -4225,17 +4234,6 @@ public class MessagingController implements Runnable
|
|||||||
Log.e(Email.LOG_TAG, "Unable to close localFolder", e);
|
Log.e(Email.LOG_TAG, "Unable to close localFolder", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (remoteFolder != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
remoteFolder.close(false);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.e(Email.LOG_TAG, "Unable to close remoteFolder", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4249,7 +4247,7 @@ public class MessagingController implements Runnable
|
|||||||
{
|
{
|
||||||
Log.e(Email.LOG_TAG, "Interrupted while awaiting latch release", e);
|
Log.e(Email.LOG_TAG, "Interrupted while awaiting latch release", e);
|
||||||
}
|
}
|
||||||
Log.i(Email.LOG_TAG, "Latch released");
|
Log.i(Email.LOG_TAG, "MessagingController.messagesArrivedLatch released");
|
||||||
}
|
}
|
||||||
enum MemorizingState { STARTED, FINISHED, FAILED };
|
enum MemorizingState { STARTED, FINISHED, FAILED };
|
||||||
|
|
||||||
|
6
src/com/android/email/mail/MessageRemovalListener.java
Normal file
6
src/com/android/email/mail/MessageRemovalListener.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.android.email.mail;
|
||||||
|
|
||||||
|
public interface MessageRemovalListener
|
||||||
|
{
|
||||||
|
public void messageRemoved(Message message);
|
||||||
|
}
|
@ -6,8 +6,8 @@ public interface PushReceiver
|
|||||||
{
|
{
|
||||||
public void acquireWakeLock();
|
public void acquireWakeLock();
|
||||||
public void releaseWakeLock();
|
public void releaseWakeLock();
|
||||||
public void messagesArrived(String folderName, List<Message> mess);
|
public void messagesArrived(Folder folder, List<Message> mess);
|
||||||
public void messagesFlagsChanged(String folderName, List<Message> mess);
|
public void messagesFlagsChanged(Folder folder, List<Message> mess);
|
||||||
public String getPushState(String folderName);
|
public String getPushState(String folderName);
|
||||||
public void pushError(String errorMessage, Exception e);
|
public void pushError(String errorMessage, Exception e);
|
||||||
public void setPushActive(String folderName, boolean enabled);
|
public void setPushActive(String folderName, boolean enabled);
|
||||||
|
@ -464,6 +464,12 @@ public class ImapStore extends Store
|
|||||||
public void open(OpenMode mode) throws MessagingException
|
public void open(OpenMode mode) throws MessagingException
|
||||||
{
|
{
|
||||||
internalOpen(mode);
|
internalOpen(mode);
|
||||||
|
|
||||||
|
if (mMessageCount == -1)
|
||||||
|
{
|
||||||
|
throw new MessagingException(
|
||||||
|
"Did not find message count during open");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ImapResponse> internalOpen(OpenMode mode) throws MessagingException
|
public List<ImapResponse> internalOpen(OpenMode mode) throws MessagingException
|
||||||
@ -559,13 +565,8 @@ public class ImapStore extends Store
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mMessageCount == -1)
|
|
||||||
{
|
|
||||||
throw new MessagingException(
|
|
||||||
"Did not find message count with command '" + command + "'");
|
|
||||||
}
|
|
||||||
mExists = true;
|
mExists = true;
|
||||||
return null;
|
return responses;
|
||||||
}
|
}
|
||||||
catch (IOException ioe)
|
catch (IOException ioe)
|
||||||
{
|
{
|
||||||
@ -594,7 +595,7 @@ public class ImapStore extends Store
|
|||||||
{
|
{
|
||||||
if (mMessageCount != -1)
|
if (mMessageCount != -1)
|
||||||
{
|
{
|
||||||
// close();
|
// close();
|
||||||
mMessageCount = -1;
|
mMessageCount = -1;
|
||||||
}
|
}
|
||||||
if (!isOpen())
|
if (!isOpen())
|
||||||
@ -788,12 +789,12 @@ public class ImapStore extends Store
|
|||||||
public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
|
public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
|
||||||
throws MessagingException
|
throws MessagingException
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
return getMessages(start, end, false, listener);
|
return getMessages(start, end, false, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Message[] getMessages(int start, int end, boolean includeDeleted, MessageRetrievalListener listener)
|
|
||||||
|
|
||||||
|
protected Message[] getMessages(final int start, final int end, final boolean includeDeleted, final MessageRetrievalListener listener)
|
||||||
throws MessagingException
|
throws MessagingException
|
||||||
{
|
{
|
||||||
if (start < 1 || end < 1 || end < start)
|
if (start < 1 || end < 1 || end < start)
|
||||||
@ -802,22 +803,48 @@ public class ImapStore extends Store
|
|||||||
String.format("Invalid message set %d %d",
|
String.format("Invalid message set %d %d",
|
||||||
start, end));
|
start, end));
|
||||||
}
|
}
|
||||||
|
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 search(searcher, listener);
|
||||||
|
|
||||||
|
}
|
||||||
|
protected Message[] getMessages(final List<Integer> mesgSeqs, final boolean includeDeleted, final MessageRetrievalListener listener)
|
||||||
|
throws MessagingException
|
||||||
|
{
|
||||||
|
ImapSearcher searcher = new ImapSearcher()
|
||||||
|
{
|
||||||
|
public List<ImapResponse> search() throws IOException, MessagingException
|
||||||
|
{
|
||||||
|
return executeSimpleCommand(String.format("UID SEARCH %s" + (includeDeleted ? "" : " NOT DELETED"), Utility.combine(mesgSeqs.toArray(), ',')));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return search(searcher, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener) throws MessagingException
|
||||||
|
{
|
||||||
|
|
||||||
checkOpen();
|
checkOpen();
|
||||||
ArrayList<Message> messages = new ArrayList<Message>();
|
ArrayList<Message> messages = new ArrayList<Message>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
boolean gotSearchValues = false;
|
boolean gotSearchValues = false;
|
||||||
ArrayList<Integer> uids = new ArrayList<Integer>();
|
ArrayList<Integer> uids = new ArrayList<Integer>();
|
||||||
List<ImapResponse> responses = executeSimpleCommand(String.format("UID SEARCH %d:%d" + (includeDeleted ? "" : " NOT DELETED"), start, end));
|
List<ImapResponse> responses = searcher.search(); //
|
||||||
for (ImapResponse response : responses)
|
for (ImapResponse response : responses)
|
||||||
{
|
{
|
||||||
// Log.d(Email.LOG_TAG, "Got search response: " + response.get(0) + ", size " + response.size());
|
// Log.d(Email.LOG_TAG, "Got search response: " + response.get(0) + ", size " + response.size());
|
||||||
if (response.get(0).equals("SEARCH"))
|
if (response.get(0).equals("SEARCH"))
|
||||||
{
|
{
|
||||||
gotSearchValues = true;
|
gotSearchValues = true;
|
||||||
for (int i = 1, count = response.size(); i < count; i++)
|
for (int i = 1, count = response.size(); i < count; i++)
|
||||||
{
|
{
|
||||||
// Log.d(Email.LOG_TAG, "Got search response UID: " + response.getString(i));
|
// Log.d(Email.LOG_TAG, "Got search response UID: " + response.getString(i));
|
||||||
|
|
||||||
uids.add(Integer.parseInt(response.getString(i)));
|
uids.add(Integer.parseInt(response.getString(i)));
|
||||||
}
|
}
|
||||||
@ -975,7 +1002,6 @@ public class ImapStore extends Store
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
response = mConnection.readResponse();
|
response = mConnection.readResponse();
|
||||||
handleUntaggedResponse(response);
|
|
||||||
if (Email.DEBUG)
|
if (Email.DEBUG)
|
||||||
{
|
{
|
||||||
Log.v(Email.LOG_TAG, "response for fetch: " + response + " for " + getLogId());
|
Log.v(Email.LOG_TAG, "response for fetch: " + response + " for " + getLogId());
|
||||||
@ -988,7 +1014,8 @@ public class ImapStore extends Store
|
|||||||
Message message = messageMap.get(uid);
|
Message message = messageMap.get(uid);
|
||||||
if (message == null)
|
if (message == null)
|
||||||
{
|
{
|
||||||
Log.w(Email.LOG_TAG, "Do not have message in messageMap for UID " + uid + " for " + getLogId());
|
Log.d(Email.LOG_TAG, "Do not have message in messageMap for UID " + uid + " for " + getLogId());
|
||||||
|
handleUntaggedResponse(response);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (listener != null)
|
if (listener != null)
|
||||||
@ -1107,6 +1134,10 @@ public class ImapStore extends Store
|
|||||||
listener.messageFinished(message, messageNumber, messageMap.size());
|
listener.messageFinished(message, messageNumber, messageMap.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handleUntaggedResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
while (response.more());
|
while (response.more());
|
||||||
|
|
||||||
@ -1467,9 +1498,9 @@ public class ImapStore extends Store
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Try to find the UID of the message we just appended using the
|
* Try to find the UID of the message we just appended using the
|
||||||
* Message-ID header.
|
* Message-ID header.
|
||||||
*/
|
*/
|
||||||
String[] messageIdHeader = message.getHeader("Message-ID");
|
String[] messageIdHeader = message.getHeader("Message-ID");
|
||||||
|
|
||||||
if (messageIdHeader == null || messageIdHeader.length == 0)
|
if (messageIdHeader == null || messageIdHeader.length == 0)
|
||||||
@ -1743,9 +1774,9 @@ public class ImapStore extends Store
|
|||||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||||
final boolean secure = mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED;
|
final boolean secure = mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED;
|
||||||
sslContext.init(null, new TrustManager[]
|
sslContext.init(null, new TrustManager[]
|
||||||
{
|
{
|
||||||
TrustManagerFactory.get(mHost, secure)
|
TrustManagerFactory.get(mHost, secure)
|
||||||
}, new SecureRandom());
|
}, new SecureRandom());
|
||||||
mSocket = sslContext.getSocketFactory().createSocket();
|
mSocket = sslContext.getSocketFactory().createSocket();
|
||||||
mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT);
|
mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT);
|
||||||
}
|
}
|
||||||
@ -1783,10 +1814,10 @@ public class ImapStore extends Store
|
|||||||
{
|
{
|
||||||
if (capability instanceof String)
|
if (capability instanceof String)
|
||||||
{
|
{
|
||||||
if (Email.DEBUG)
|
// if (Email.DEBUG)
|
||||||
{
|
// {
|
||||||
Log.v(Email.LOG_TAG, "Saving capability '" + capability + "' for " + getLogId());
|
// Log.v(Email.LOG_TAG, "Saving capability '" + capability + "' for " + getLogId());
|
||||||
}
|
// }
|
||||||
capabilities.add((String)capability);
|
capabilities.add((String)capability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1807,9 +1838,9 @@ public class ImapStore extends Store
|
|||||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||||
boolean secure = mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED;
|
boolean secure = mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED;
|
||||||
sslContext.init(null, new TrustManager[]
|
sslContext.init(null, new TrustManager[]
|
||||||
{
|
{
|
||||||
TrustManagerFactory.get(mHost, secure)
|
TrustManagerFactory.get(mHost, secure)
|
||||||
}, new SecureRandom());
|
}, new SecureRandom());
|
||||||
mSocket = sslContext.getSocketFactory().createSocket(mSocket, mHost, mPort,
|
mSocket = sslContext.getSocketFactory().createSocket(mSocket, mHost, mPort,
|
||||||
true);
|
true);
|
||||||
mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT);
|
mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT);
|
||||||
@ -1886,10 +1917,10 @@ public class ImapStore extends Store
|
|||||||
if (Email.DEBUG)
|
if (Email.DEBUG)
|
||||||
{
|
{
|
||||||
Log.v(Email.LOG_TAG, "Connection " + getLogId() + " has " + capabilities.size() + " capabilities");
|
Log.v(Email.LOG_TAG, "Connection " + getLogId() + " has " + capabilities.size() + " capabilities");
|
||||||
for (String capability : capabilities)
|
// for (String capability : capabilities)
|
||||||
{
|
// {
|
||||||
Log.v(Email.LOG_TAG, "Have capability '" + capability + "' for " + getLogId());
|
// Log.v(Email.LOG_TAG, "Have capability '" + capability + "' for " + getLogId());
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
return capabilities.contains("IDLE");
|
return capabilities.contains("IDLE");
|
||||||
}
|
}
|
||||||
@ -2223,6 +2254,7 @@ public class ImapStore extends Store
|
|||||||
final AtomicBoolean idling = new AtomicBoolean(false);
|
final AtomicBoolean idling = new AtomicBoolean(false);
|
||||||
final AtomicBoolean doneSent = new AtomicBoolean(false);
|
final AtomicBoolean doneSent = new AtomicBoolean(false);
|
||||||
final AtomicInteger delayTime = new AtomicInteger(NORMAL_DELAY_TIME);
|
final AtomicInteger delayTime = new AtomicInteger(NORMAL_DELAY_TIME);
|
||||||
|
List<ImapResponse> storedUntaggedResponses = new ArrayList<ImapResponse>();
|
||||||
|
|
||||||
public ImapFolderPusher(ImapStore store, String name, PushReceiver nReceiver)
|
public ImapFolderPusher(ImapStore store, String name, PushReceiver nReceiver)
|
||||||
{
|
{
|
||||||
@ -2265,6 +2297,7 @@ public class ImapStore extends Store
|
|||||||
Log.i(Email.LOG_TAG, "Pusher starting for " + getLogId());
|
Log.i(Email.LOG_TAG, "Pusher starting for " + getLogId());
|
||||||
while (stop.get() != true)
|
while (stop.get() != true)
|
||||||
{
|
{
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int oldUidNext = -1;
|
int oldUidNext = -1;
|
||||||
@ -2328,14 +2361,25 @@ public class ImapStore extends Store
|
|||||||
{
|
{
|
||||||
if (stop.get() != true)
|
if (stop.get() != true)
|
||||||
{
|
{
|
||||||
Log.i(Email.LOG_TAG, "About to IDLE for " + getLogId());
|
List<ImapResponse> untaggedResponses = null;
|
||||||
|
if (storedUntaggedResponses.size() > 0)
|
||||||
|
{
|
||||||
|
Log.i(Email.LOG_TAG, "Processing " + storedUntaggedResponses.size() + " from previous commands for " + getLogId());
|
||||||
|
untaggedResponses = new ArrayList<ImapResponse>(storedUntaggedResponses);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.i(Email.LOG_TAG, "About to IDLE for " + getLogId());
|
||||||
|
|
||||||
receiver.setPushActive(getName(), true);
|
receiver.setPushActive(getName(), true);
|
||||||
idling.set(true);
|
idling.set(true);
|
||||||
doneSent.set(false);
|
doneSent.set(false);
|
||||||
executeSimpleCommand("IDLE", false, ImapFolderPusher.this);
|
untaggedResponses = executeSimpleCommand("IDLE", false, ImapFolderPusher.this);
|
||||||
idling.set(false);
|
idling.set(false);
|
||||||
receiver.setPushActive(getName(), false);
|
|
||||||
|
}
|
||||||
|
storedUntaggedResponses.clear();
|
||||||
|
processUntaggedResponses(untaggedResponses);
|
||||||
delayTime.set(NORMAL_DELAY_TIME);
|
delayTime.set(NORMAL_DELAY_TIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2343,6 +2387,7 @@ public class ImapStore extends Store
|
|||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
receiver.acquireWakeLock();
|
receiver.acquireWakeLock();
|
||||||
|
storedUntaggedResponses.clear();
|
||||||
idling.set(false);
|
idling.set(false);
|
||||||
receiver.setPushActive(getName(), false);
|
receiver.setPushActive(getName(), false);
|
||||||
try
|
try
|
||||||
@ -2372,6 +2417,7 @@ public class ImapStore extends Store
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
receiver.setPushActive(getName(), false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Log.i(Email.LOG_TAG, "Pusher for " + getLogId() + " is exiting");
|
Log.i(Email.LOG_TAG, "Pusher for " + getLogId() + " is exiting");
|
||||||
@ -2391,39 +2437,50 @@ public class ImapStore extends Store
|
|||||||
listeningThread.start();
|
listeningThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Integer> flagSyncMsgSeqs = new ArrayList<Integer>();
|
@Override
|
||||||
|
protected void handleUntaggedResponse(ImapResponse response)
|
||||||
protected List<ImapResponse> handleUntaggedResponses(List<ImapResponse> responses)
|
|
||||||
{
|
{
|
||||||
flagSyncMsgSeqs.clear();
|
if (response.mTag == null && response.size() > 1)
|
||||||
int oldMessageCount = mMessageCount;
|
|
||||||
|
|
||||||
super.handleUntaggedResponses(responses);
|
|
||||||
|
|
||||||
List<Integer> flagSyncMsgSeqsCopy = new ArrayList<Integer>();
|
|
||||||
flagSyncMsgSeqsCopy.addAll(flagSyncMsgSeqs);
|
|
||||||
|
|
||||||
|
|
||||||
if (Email.DEBUG)
|
|
||||||
{
|
{
|
||||||
Log.d(Email.LOG_TAG, "oldMessageCount = " + oldMessageCount + ", new mMessageCount = " + mMessageCount
|
Object responseType = response.get(1);
|
||||||
+ " for " + getLogId());
|
if ("FETCH".equals(responseType)
|
||||||
|
|| "EXPUNGE".equals(responseType)
|
||||||
|
|| "EXISTS".equals(responseType))
|
||||||
|
{
|
||||||
|
if (Email.DEBUG)
|
||||||
|
{
|
||||||
|
Log.d(Email.LOG_TAG, "Storing response " + response + " for later processing");
|
||||||
|
}
|
||||||
|
storedUntaggedResponses.add(response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (oldMessageCount > 0 && mMessageCount > oldMessageCount)
|
}
|
||||||
|
|
||||||
|
protected void processUntaggedResponses(List<ImapResponse> responses)
|
||||||
|
{
|
||||||
|
int oldMessageCount = mMessageCount;
|
||||||
|
List<Integer> flagSyncMsgSeqs = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
for (ImapResponse response : responses)
|
||||||
|
{
|
||||||
|
oldMessageCount += processUntaggedResponse(oldMessageCount, response, flagSyncMsgSeqs);
|
||||||
|
}
|
||||||
|
if (oldMessageCount < 0)
|
||||||
|
{
|
||||||
|
oldMessageCount = 0;
|
||||||
|
}
|
||||||
|
if (mMessageCount > oldMessageCount)
|
||||||
{
|
{
|
||||||
syncMessages(oldMessageCount + 1, mMessageCount, true);
|
syncMessages(oldMessageCount + 1, mMessageCount, true);
|
||||||
}
|
}
|
||||||
if (Email.DEBUG)
|
if (Email.DEBUG)
|
||||||
{
|
{
|
||||||
Log.d(Email.LOG_TAG, "There are " + flagSyncMsgSeqsCopy + " messages needing flag sync for " + getLogId());
|
Log.d(Email.LOG_TAG, "There are " + flagSyncMsgSeqs + " messages needing flag sync for " + getLogId());
|
||||||
}
|
}
|
||||||
// TODO: Identify ranges and call syncMessages on said identified ranges
|
if (flagSyncMsgSeqs.size() > 0)
|
||||||
for (Integer msgSeq : flagSyncMsgSeqsCopy)
|
|
||||||
{
|
{
|
||||||
syncMessages(msgSeq, msgSeq, false);
|
syncMessages(flagSyncMsgSeqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return responses;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncMessages(int start, int end, boolean newArrivals)
|
private void syncMessages(int start, int end, boolean newArrivals)
|
||||||
@ -2448,9 +2505,32 @@ public class ImapStore extends Store
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleUntaggedResponse(ImapResponse response)
|
private void syncMessages(List<Integer> flagSyncMsgSeqs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Message[] messageArray = null;
|
||||||
|
|
||||||
|
messageArray = getMessages(flagSyncMsgSeqs, true, null);
|
||||||
|
|
||||||
|
List<Message> messages = new ArrayList<Message>();
|
||||||
|
for (Message message : messageArray)
|
||||||
|
{
|
||||||
|
messages.add(message);
|
||||||
|
}
|
||||||
|
pushMessages(messages, false);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
receiver.pushError("Exception while processing Push untagged responses", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int processUntaggedResponse(int oldMessageCount, ImapResponse response, List<Integer> flagSyncMsgSeqs)
|
||||||
{
|
{
|
||||||
super.handleUntaggedResponse(response);
|
super.handleUntaggedResponse(response);
|
||||||
|
int messageCountDelta = 0;
|
||||||
if (response.mTag == null && response.size() > 1)
|
if (response.mTag == null && response.size() > 1)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -2463,7 +2543,37 @@ public class ImapStore extends Store
|
|||||||
{
|
{
|
||||||
Log.d(Email.LOG_TAG, "Got untagged FETCH for msgseq " + msgSeq + " for " + getLogId());
|
Log.d(Email.LOG_TAG, "Got untagged FETCH for msgseq " + msgSeq + " for " + getLogId());
|
||||||
}
|
}
|
||||||
flagSyncMsgSeqs.add(msgSeq);
|
if (flagSyncMsgSeqs.contains(msgSeq) == false)
|
||||||
|
{
|
||||||
|
flagSyncMsgSeqs.add(msgSeq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("EXPUNGE".equals(responseType))
|
||||||
|
{
|
||||||
|
int msgSeq = response.getNumber(0);
|
||||||
|
if (msgSeq <= oldMessageCount)
|
||||||
|
{
|
||||||
|
messageCountDelta = -1;
|
||||||
|
}
|
||||||
|
if (Email.DEBUG)
|
||||||
|
{
|
||||||
|
Log.d(Email.LOG_TAG, "Got untagged EXPUNGE for msgseq " + msgSeq + " for " + getLogId());
|
||||||
|
}
|
||||||
|
List<Integer> newSeqs = new ArrayList<Integer>();
|
||||||
|
Iterator<Integer> flagIter = flagSyncMsgSeqs.iterator();
|
||||||
|
while (flagIter.hasNext())
|
||||||
|
{
|
||||||
|
Integer flagMsg = flagIter.next();
|
||||||
|
if (flagMsg >= msgSeq)
|
||||||
|
{
|
||||||
|
flagIter.remove();
|
||||||
|
if (flagMsg > msgSeq)
|
||||||
|
{
|
||||||
|
newSeqs.add(flagMsg--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flagSyncMsgSeqs.addAll(newSeqs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -2471,6 +2581,7 @@ public class ImapStore extends Store
|
|||||||
Log.e(Email.LOG_TAG, "Could not handle untagged FETCH for " + getLogId(), e);
|
Log.e(Email.LOG_TAG, "Could not handle untagged FETCH for " + getLogId(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return messageCountDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2481,11 +2592,11 @@ public class ImapStore extends Store
|
|||||||
{
|
{
|
||||||
if (newArrivals)
|
if (newArrivals)
|
||||||
{
|
{
|
||||||
receiver.messagesArrived(getName(), messages);
|
receiver.messagesArrived(this, messages);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
receiver.messagesFlagsChanged(getName(), messages);
|
receiver.messagesFlagsChanged(this, messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (RuntimeException e)
|
catch (RuntimeException e)
|
||||||
@ -2684,4 +2795,8 @@ public class ImapStore extends Store
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
private interface ImapSearcher
|
||||||
|
{
|
||||||
|
List<ImapResponse> search() throws IOException, MessagingException;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ import com.android.email.mail.FetchProfile;
|
|||||||
import com.android.email.mail.Flag;
|
import com.android.email.mail.Flag;
|
||||||
import com.android.email.mail.Folder;
|
import com.android.email.mail.Folder;
|
||||||
import com.android.email.mail.Message;
|
import com.android.email.mail.Message;
|
||||||
|
import com.android.email.mail.MessageRemovalListener;
|
||||||
import com.android.email.mail.MessageRetrievalListener;
|
import com.android.email.mail.MessageRetrievalListener;
|
||||||
import com.android.email.mail.MessagingException;
|
import com.android.email.mail.MessagingException;
|
||||||
import com.android.email.mail.Part;
|
import com.android.email.mail.Part;
|
||||||
@ -610,9 +611,9 @@ public class LocalStore extends Store implements Serializable
|
|||||||
cursor = mDb.rawQuery("SELECT id, unread_count, visible_limit, last_updated, status, push_state, last_pushed FROM folders "
|
cursor = mDb.rawQuery("SELECT id, unread_count, visible_limit, last_updated, status, push_state, last_pushed FROM folders "
|
||||||
+ "where folders.name = ?",
|
+ "where folders.name = ?",
|
||||||
new String[]
|
new String[]
|
||||||
{
|
{
|
||||||
mName
|
mName
|
||||||
});
|
});
|
||||||
|
|
||||||
if (cursor.moveToFirst())
|
if (cursor.moveToFirst())
|
||||||
{
|
{
|
||||||
@ -705,10 +706,10 @@ public class LocalStore extends Store implements Serializable
|
|||||||
throw new MessagingException("Folder " + mName + " already exists.");
|
throw new MessagingException("Folder " + mName + " already exists.");
|
||||||
}
|
}
|
||||||
mDb.execSQL("INSERT INTO folders (name, visible_limit) VALUES (?, ?)", new Object[]
|
mDb.execSQL("INSERT INTO folders (name, visible_limit) VALUES (?, ?)", new Object[]
|
||||||
{
|
{
|
||||||
mName,
|
mName,
|
||||||
Email.DEFAULT_VISIBLE_LIMIT
|
Email.DEFAULT_VISIBLE_LIMIT
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,10 +720,10 @@ public class LocalStore extends Store implements Serializable
|
|||||||
throw new MessagingException("Folder " + mName + " already exists.");
|
throw new MessagingException("Folder " + mName + " already exists.");
|
||||||
}
|
}
|
||||||
mDb.execSQL("INSERT INTO folders (name, visible_limit) VALUES (?, ?)", new Object[]
|
mDb.execSQL("INSERT INTO folders (name, visible_limit) VALUES (?, ?)", new Object[]
|
||||||
{
|
{
|
||||||
mName,
|
mName,
|
||||||
visibleLimit
|
visibleLimit
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,9 +746,9 @@ public class LocalStore extends Store implements Serializable
|
|||||||
{
|
{
|
||||||
cursor = mDb.rawQuery("SELECT COUNT(*) FROM messages WHERE messages.folder_id = ?",
|
cursor = mDb.rawQuery("SELECT COUNT(*) FROM messages WHERE messages.folder_id = ?",
|
||||||
new String[]
|
new String[]
|
||||||
{
|
{
|
||||||
Long.toString(mFolderId)
|
Long.toString(mFolderId)
|
||||||
});
|
});
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
int messageCount = cursor.getInt(0);
|
int messageCount = cursor.getInt(0);
|
||||||
return messageCount;
|
return messageCount;
|
||||||
@ -799,6 +800,23 @@ public class LocalStore extends Store implements Serializable
|
|||||||
return mVisibleLimit;
|
return mVisibleLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void purgeToVisibleLimit(MessageRemovalListener listener) throws MessagingException
|
||||||
|
{
|
||||||
|
open(OpenMode.READ_WRITE);
|
||||||
|
Message[] messages = getMessages(null);
|
||||||
|
for (int i = 0; i < messages.length; i++)
|
||||||
|
{
|
||||||
|
if (i >= mVisibleLimit)
|
||||||
|
{
|
||||||
|
if (listener != null)
|
||||||
|
{
|
||||||
|
listener.messageRemoved(messages[i]);
|
||||||
|
}
|
||||||
|
messages[i].setFlag(Flag.X_DESTROYED, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setVisibleLimit(int visibleLimit) throws MessagingException
|
public void setVisibleLimit(int visibleLimit) throws MessagingException
|
||||||
{
|
{
|
||||||
@ -1060,19 +1078,19 @@ public class LocalStore extends Store implements Serializable
|
|||||||
cursor = mDb.query(
|
cursor = mDb.query(
|
||||||
"attachments",
|
"attachments",
|
||||||
new String[]
|
new String[]
|
||||||
{
|
{
|
||||||
"id",
|
"id",
|
||||||
"size",
|
"size",
|
||||||
"name",
|
"name",
|
||||||
"mime_type",
|
"mime_type",
|
||||||
"store_data",
|
"store_data",
|
||||||
"content_uri"
|
"content_uri"
|
||||||
},
|
},
|
||||||
"message_id = ?",
|
"message_id = ?",
|
||||||
new String[] { Long.toString(localMessage.mId) },
|
new String[] { Long.toString(localMessage.mId) },
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
while (cursor.moveToNext())
|
while (cursor.moveToNext())
|
||||||
{
|
{
|
||||||
@ -1227,9 +1245,9 @@ public class LocalStore extends Store implements Serializable
|
|||||||
+ "bcc_list, reply_to_list, attachment_count, internal_date, message_id "
|
+ "bcc_list, reply_to_list, attachment_count, internal_date, message_id "
|
||||||
+ "FROM messages " + "WHERE uid = ? " + "AND folder_id = ?",
|
+ "FROM messages " + "WHERE uid = ? " + "AND folder_id = ?",
|
||||||
new String[]
|
new String[]
|
||||||
{
|
{
|
||||||
message.getUid(), Long.toString(mFolderId)
|
message.getUid(), Long.toString(mFolderId)
|
||||||
});
|
});
|
||||||
if (!cursor.moveToNext())
|
if (!cursor.moveToNext())
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@ -1272,9 +1290,9 @@ public class LocalStore extends Store implements Serializable
|
|||||||
+ (includeDeleted ? "" : "deleted = 0")
|
+ (includeDeleted ? "" : "deleted = 0")
|
||||||
+ " folder_id = ? ORDER BY date DESC"
|
+ " folder_id = ? ORDER BY date DESC"
|
||||||
, new String[]
|
, new String[]
|
||||||
{
|
{
|
||||||
Long.toString(mFolderId)
|
Long.toString(mFolderId)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -1369,11 +1387,11 @@ public class LocalStore extends Store implements Serializable
|
|||||||
message.setUid(Email.LOCAL_UID_PREFIX + UUID.randomUUID().toString());
|
message.setUid(Email.LOCAL_UID_PREFIX + UUID.randomUUID().toString());
|
||||||
|
|
||||||
mDb.execSQL("UPDATE messages " + "SET folder_id = ?, uid = ? " + "WHERE id = ?", new Object[]
|
mDb.execSQL("UPDATE messages " + "SET folder_id = ?, uid = ? " + "WHERE id = ?", new Object[]
|
||||||
{
|
{
|
||||||
lDestFolder.getId(),
|
lDestFolder.getId(),
|
||||||
message.getUid(),
|
message.getUid(),
|
||||||
lMessage.getId()
|
lMessage.getId()
|
||||||
});
|
});
|
||||||
|
|
||||||
LocalMessage placeHolder = new LocalMessage(oldUID, this);
|
LocalMessage placeHolder = new LocalMessage(oldUID, this);
|
||||||
placeHolder.setFlagInternal(Flag.DELETED, true);
|
placeHolder.setFlagInternal(Flag.DELETED, true);
|
||||||
@ -1561,27 +1579,27 @@ public class LocalStore extends Store implements Serializable
|
|||||||
+ "html_content = ?, text_content = ?, reply_to_list = ?, "
|
+ "html_content = ?, text_content = ?, reply_to_list = ?, "
|
||||||
+ "attachment_count = ? WHERE id = ?",
|
+ "attachment_count = ? WHERE id = ?",
|
||||||
new Object[]
|
new Object[]
|
||||||
{
|
{
|
||||||
message.getUid(),
|
message.getUid(),
|
||||||
message.getSubject(),
|
message.getSubject(),
|
||||||
Address.pack(message.getFrom()),
|
Address.pack(message.getFrom()),
|
||||||
message.getSentDate() == null ? System
|
message.getSentDate() == null ? System
|
||||||
.currentTimeMillis() : message.getSentDate()
|
.currentTimeMillis() : message.getSentDate()
|
||||||
.getTime(),
|
.getTime(),
|
||||||
Utility.combine(message.getFlags(), ',').toUpperCase(),
|
Utility.combine(message.getFlags(), ',').toUpperCase(),
|
||||||
mFolderId,
|
mFolderId,
|
||||||
Address.pack(message
|
Address.pack(message
|
||||||
.getRecipients(RecipientType.TO)),
|
.getRecipients(RecipientType.TO)),
|
||||||
Address.pack(message
|
Address.pack(message
|
||||||
.getRecipients(RecipientType.CC)),
|
.getRecipients(RecipientType.CC)),
|
||||||
Address.pack(message
|
Address.pack(message
|
||||||
.getRecipients(RecipientType.BCC)),
|
.getRecipients(RecipientType.BCC)),
|
||||||
html.length() > 0 ? html : null,
|
html.length() > 0 ? html : null,
|
||||||
text.length() > 0 ? text : null,
|
text.length() > 0 ? text : null,
|
||||||
Address.pack(message.getReplyTo()),
|
Address.pack(message.getReplyTo()),
|
||||||
attachments.size(),
|
attachments.size(),
|
||||||
message.mId
|
message.mId
|
||||||
});
|
});
|
||||||
|
|
||||||
for (int i = 0, count = attachments.size(); i < count; i++)
|
for (int i = 0, count = attachments.size(); i < count; i++)
|
||||||
{
|
{
|
||||||
@ -1621,9 +1639,9 @@ public class LocalStore extends Store implements Serializable
|
|||||||
{
|
{
|
||||||
mDb.execSQL("DELETE FROM headers WHERE id = ?",
|
mDb.execSQL("DELETE FROM headers WHERE id = ?",
|
||||||
new Object[]
|
new Object[]
|
||||||
{
|
{
|
||||||
id
|
id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1802,9 +1820,9 @@ public class LocalStore extends Store implements Serializable
|
|||||||
{
|
{
|
||||||
open(OpenMode.READ_ONLY);
|
open(OpenMode.READ_ONLY);
|
||||||
mDb.execSQL("DELETE FROM messages WHERE folder_id = ? and date < ?", new Object[]
|
mDb.execSQL("DELETE FROM messages WHERE folder_id = ? and date < ?", new Object[]
|
||||||
{
|
{
|
||||||
Long.toString(mFolderId), new Long(cutoff)
|
Long.toString(mFolderId), new Long(cutoff)
|
||||||
});
|
});
|
||||||
resetUnreadCount();
|
resetUnreadCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1840,9 +1858,9 @@ public class LocalStore extends Store implements Serializable
|
|||||||
deleteAttachments(message.getUid());
|
deleteAttachments(message.getUid());
|
||||||
}
|
}
|
||||||
mDb.execSQL("DELETE FROM folders WHERE id = ?", new Object[]
|
mDb.execSQL("DELETE FROM folders WHERE id = ?", new Object[]
|
||||||
{
|
{
|
||||||
Long.toString(mFolderId),
|
Long.toString(mFolderId),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2158,18 +2176,18 @@ public class LocalStore extends Store implements Serializable
|
|||||||
"reply_to_list = NULL " +
|
"reply_to_list = NULL " +
|
||||||
"WHERE id = ?",
|
"WHERE id = ?",
|
||||||
new Object[]
|
new Object[]
|
||||||
{
|
{
|
||||||
mId
|
mId
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete all of the messages' attachments to save space.
|
* Delete all of the messages' attachments to save space.
|
||||||
*/
|
*/
|
||||||
mDb.execSQL("DELETE FROM attachments WHERE id = ?",
|
mDb.execSQL("DELETE FROM attachments WHERE id = ?",
|
||||||
new Object[]
|
new Object[]
|
||||||
{
|
{
|
||||||
mId
|
mId
|
||||||
});
|
});
|
||||||
|
|
||||||
((LocalFolder)mFolder).deleteHeaders(mId);
|
((LocalFolder)mFolder).deleteHeaders(mId);
|
||||||
|
|
||||||
@ -2213,9 +2231,9 @@ public class LocalStore extends Store implements Serializable
|
|||||||
* Set the flags on the message.
|
* Set the flags on the message.
|
||||||
*/
|
*/
|
||||||
mDb.execSQL("UPDATE messages " + "SET flags = ? " + " WHERE id = ?", new Object[]
|
mDb.execSQL("UPDATE messages " + "SET flags = ? " + " WHERE id = ?", new Object[]
|
||||||
{
|
{
|
||||||
Utility.combine(getFlags(), ',').toUpperCase(), mId
|
Utility.combine(getFlags(), ',').toUpperCase(), mId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user