use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.
the class MessagingController method checkMail.
/**
* Checks mail for one or multiple accounts. If account is null all accounts
* are checked.
*/
public void checkMail(final Context context, final Account account, final boolean ignoreLastCheckedTime, final boolean useManualWakeLock, final MessagingListener listener) {
TracingWakeLock twakeLock = null;
if (useManualWakeLock) {
TracingPowerManager pm = TracingPowerManager.getPowerManager(context);
twakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "K9 MessagingController.checkMail");
twakeLock.setReferenceCounted(false);
twakeLock.acquire(K9.MANUAL_WAKE_LOCK_TIMEOUT);
}
final TracingWakeLock wakeLock = twakeLock;
for (MessagingListener l : getListeners()) {
l.checkMailStarted(context, account);
}
putBackground("checkMail", listener, new Runnable() {
@Override
public void run() {
try {
Timber.i("Starting mail check");
Preferences prefs = Preferences.getPreferences(context);
Collection<Account> accounts;
if (account != null) {
accounts = new ArrayList<>(1);
accounts.add(account);
} else {
accounts = prefs.getAvailableAccounts();
}
for (final Account account : accounts) {
checkMailForAccount(context, account, ignoreLastCheckedTime, listener);
}
} catch (Exception e) {
Timber.e(e, "Unable to synchronize mail");
addErrorMessage(account, null, e);
}
putBackground("finalize sync", null, new Runnable() {
@Override
public void run() {
Timber.i("Finished mail sync");
if (wakeLock != null) {
wakeLock.release();
}
for (MessagingListener l : getListeners()) {
l.checkMailFinished(context, account);
}
}
});
}
});
}
use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.
the class MessagingController method processPendingMoveOrCopy.
void processPendingMoveOrCopy(PendingMoveOrCopy command, Account account) throws MessagingException {
Folder remoteSrcFolder = null;
Folder remoteDestFolder = null;
LocalFolder localDestFolder;
try {
String srcFolder = command.srcFolder;
if (account.getErrorFolderName().equals(srcFolder)) {
return;
}
String destFolder = command.destFolder;
boolean isCopy = command.isCopy;
Store remoteStore = account.getRemoteStore();
remoteSrcFolder = remoteStore.getFolder(srcFolder);
Store localStore = account.getLocalStore();
localDestFolder = (LocalFolder) localStore.getFolder(destFolder);
List<Message> messages = new ArrayList<>();
Collection<String> uids = command.newUidMap != null ? command.newUidMap.keySet() : command.uids;
for (String uid : uids) {
if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
messages.add(remoteSrcFolder.getMessage(uid));
}
}
if (!remoteSrcFolder.exists()) {
throw new MessagingException("processingPendingMoveOrCopy: remoteFolder " + srcFolder + " does not exist", true);
}
remoteSrcFolder.open(Folder.OPEN_MODE_RW);
if (remoteSrcFolder.getMode() != Folder.OPEN_MODE_RW) {
throw new MessagingException("processingPendingMoveOrCopy: could not open remoteSrcFolder " + srcFolder + " read/write", true);
}
Timber.d("processingPendingMoveOrCopy: source folder = %s, %d messages, destination folder = %s, " + "isCopy = %s", srcFolder, messages.size(), destFolder, isCopy);
Map<String, String> remoteUidMap = null;
if (!isCopy && destFolder.equals(account.getTrashFolderName())) {
Timber.d("processingPendingMoveOrCopy doing special case for deleting message");
String destFolderName = destFolder;
if (K9.FOLDER_NONE.equals(destFolderName)) {
destFolderName = null;
}
remoteSrcFolder.delete(messages, destFolderName);
} else {
remoteDestFolder = remoteStore.getFolder(destFolder);
if (isCopy) {
remoteUidMap = remoteSrcFolder.copyMessages(messages, remoteDestFolder);
} else {
remoteUidMap = remoteSrcFolder.moveMessages(messages, remoteDestFolder);
}
}
if (!isCopy && Expunge.EXPUNGE_IMMEDIATELY == account.getExpungePolicy()) {
Timber.i("processingPendingMoveOrCopy expunging folder %s:%s", account.getDescription(), srcFolder);
remoteSrcFolder.expunge();
}
/*
* This next part is used to bring the local UIDs of the local destination folder
* upto speed with the remote UIDs of remote destination folder.
*/
if (command.newUidMap != null && remoteUidMap != null && !remoteUidMap.isEmpty()) {
for (Map.Entry<String, String> entry : remoteUidMap.entrySet()) {
String remoteSrcUid = entry.getKey();
String newUid = entry.getValue();
String localDestUid = command.newUidMap.get(remoteSrcUid);
if (localDestUid == null) {
continue;
}
Message localDestMessage = localDestFolder.getMessage(localDestUid);
if (localDestMessage != null) {
localDestMessage.setUid(newUid);
localDestFolder.changeUid((LocalMessage) localDestMessage);
for (MessagingListener l : getListeners()) {
l.messageUidChanged(account, destFolder, localDestUid, newUid);
}
}
}
}
} finally {
closeFolder(remoteSrcFolder);
closeFolder(remoteDestFolder);
}
}
use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.
the class MessagingController method messagesArrived.
public void messagesArrived(final Account account, final Folder remoteFolder, final List<Message> messages, final boolean flagSyncOnly) {
Timber.i("Got new pushed email messages for account %s, folder %s", account.getDescription(), remoteFolder.getName());
final CountDownLatch latch = new CountDownLatch(1);
putBackground("Push messageArrived of account " + account.getDescription() + ", folder " + remoteFolder.getName(), null, new Runnable() {
@Override
public void run() {
LocalFolder localFolder = null;
try {
LocalStore localStore = account.getLocalStore();
localFolder = localStore.getFolder(remoteFolder.getName());
localFolder.open(Folder.OPEN_MODE_RW);
account.setRingNotified(false);
int newCount = downloadMessages(account, remoteFolder, localFolder, messages, flagSyncOnly, true);
int unreadMessageCount = localFolder.getUnreadMessageCount();
localFolder.setLastPush(System.currentTimeMillis());
localFolder.setStatus(null);
Timber.i("messagesArrived newCount = %d, unread count = %d", newCount, unreadMessageCount);
if (unreadMessageCount == 0) {
notificationController.clearNewMailNotifications(account);
}
for (MessagingListener l : getListeners()) {
l.folderStatusChanged(account, remoteFolder.getName(), unreadMessageCount);
}
} catch (Exception e) {
String rootMessage = getRootCauseMessage(e);
String errorMessage = "Push failed: " + rootMessage;
try {
localFolder.setStatus(errorMessage);
} catch (Exception se) {
Timber.e(se, "Unable to set failed status on localFolder");
}
for (MessagingListener l : getListeners()) {
l.synchronizeMailboxFailed(account, remoteFolder.getName(), errorMessage);
}
addErrorMessage(account, null, e);
} finally {
closeFolder(localFolder);
latch.countDown();
}
}
});
try {
latch.await();
} catch (Exception e) {
Timber.e(e, "Interrupted while awaiting latch release");
}
Timber.i("MessagingController.messagesArrivedLatch released");
}
use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.
the class MessagingController method processPendingAppend.
/**
* Process a pending append message command. This command uploads a local message to the
* server, first checking to be sure that the server message is not newer than
* the local message. Once the local message is successfully processed it is deleted so
* that the server message will be synchronized down without an additional copy being
* created.
* TODO update the local message UID instead of deleting it
*/
void processPendingAppend(PendingAppend command, Account account) throws MessagingException {
Folder remoteFolder = null;
LocalFolder localFolder = null;
try {
String folder = command.folder;
String uid = command.uid;
if (account.getErrorFolderName().equals(folder)) {
return;
}
LocalStore localStore = account.getLocalStore();
localFolder = localStore.getFolder(folder);
LocalMessage localMessage = localFolder.getMessage(uid);
if (localMessage == null) {
return;
}
Store remoteStore = account.getRemoteStore();
remoteFolder = remoteStore.getFolder(folder);
if (!remoteFolder.exists()) {
if (!remoteFolder.create(FolderType.HOLDS_MESSAGES)) {
return;
}
}
remoteFolder.open(Folder.OPEN_MODE_RW);
if (remoteFolder.getMode() != Folder.OPEN_MODE_RW) {
return;
}
Message remoteMessage = null;
if (!localMessage.getUid().startsWith(K9.LOCAL_UID_PREFIX)) {
remoteMessage = remoteFolder.getMessage(localMessage.getUid());
}
if (remoteMessage == null) {
if (localMessage.isSet(Flag.X_REMOTE_COPY_STARTED)) {
Timber.w("Local message with uid %s has flag %s already set, checking for remote message with " + "same message id", localMessage.getUid(), X_REMOTE_COPY_STARTED);
String rUid = remoteFolder.getUidFromMessageId(localMessage);
if (rUid != null) {
Timber.w("Local message has flag %s already set, and there is a remote message with uid %s, " + "assuming message was already copied and aborting this copy", X_REMOTE_COPY_STARTED, rUid);
String oldUid = localMessage.getUid();
localMessage.setUid(rUid);
localFolder.changeUid(localMessage);
for (MessagingListener l : getListeners()) {
l.messageUidChanged(account, folder, oldUid, localMessage.getUid());
}
return;
} else {
Timber.w("No remote message with message-id found, proceeding with append");
}
}
/*
* If the message does not exist remotely we just upload it and then
* update our local copy with the new uid.
*/
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.BODY);
localFolder.fetch(Collections.singletonList(localMessage), fp, null);
String oldUid = localMessage.getUid();
localMessage.setFlag(Flag.X_REMOTE_COPY_STARTED, true);
remoteFolder.appendMessages(Collections.singletonList(localMessage));
localFolder.changeUid(localMessage);
for (MessagingListener l : getListeners()) {
l.messageUidChanged(account, folder, oldUid, localMessage.getUid());
}
} else {
/*
* If the remote message exists we need to determine which copy to keep.
*/
/*
* See if the remote message is newer than ours.
*/
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
remoteFolder.fetch(Collections.singletonList(remoteMessage), fp, null);
Date localDate = localMessage.getInternalDate();
Date remoteDate = remoteMessage.getInternalDate();
if (remoteDate != null && remoteDate.compareTo(localDate) > 0) {
/*
* If the remote message is newer than ours we'll just
* delete ours and move on. A sync will get the server message
* if we need to be able to see it.
*/
localMessage.destroy();
} else {
/*
* Otherwise we'll upload our message and then delete the remote message.
*/
fp = new FetchProfile();
fp.add(FetchProfile.Item.BODY);
localFolder.fetch(Collections.singletonList(localMessage), fp, null);
String oldUid = localMessage.getUid();
localMessage.setFlag(Flag.X_REMOTE_COPY_STARTED, true);
remoteFolder.appendMessages(Collections.singletonList(localMessage));
localFolder.changeUid(localMessage);
for (MessagingListener l : getListeners()) {
l.messageUidChanged(account, folder, oldUid, localMessage.getUid());
}
if (remoteDate != null) {
remoteMessage.setFlag(Flag.DELETED, true);
if (Expunge.EXPUNGE_IMMEDIATELY == account.getExpungePolicy()) {
remoteFolder.expunge();
}
}
}
}
} finally {
closeFolder(remoteFolder);
closeFolder(localFolder);
}
}
use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.
the class MessagingController method deleteMessagesSynchronous.
private void deleteMessagesSynchronous(final Account account, final String folder, final List<? extends Message> messages, MessagingListener listener) {
Folder localFolder = null;
Folder localTrashFolder = null;
List<String> uids = getUidsFromMessages(messages);
try {
//as messages get a new UID after being moved
for (Message message : messages) {
for (MessagingListener l : getListeners(listener)) {
l.messageDeleted(account, folder, message);
}
}
Store localStore = account.getLocalStore();
localFolder = localStore.getFolder(folder);
Map<String, String> uidMap = null;
if (folder.equals(account.getTrashFolderName()) || !account.hasTrashFolder()) {
Timber.d("Deleting messages in trash folder or trash set to -None-, not copying");
localFolder.setFlags(messages, Collections.singleton(Flag.DELETED), true);
} else {
localTrashFolder = localStore.getFolder(account.getTrashFolderName());
if (!localTrashFolder.exists()) {
localTrashFolder.create(Folder.FolderType.HOLDS_MESSAGES);
}
if (localTrashFolder.exists()) {
Timber.d("Deleting messages in normal folder, moving");
uidMap = localFolder.moveMessages(messages, localTrashFolder);
}
}
for (MessagingListener l : getListeners()) {
l.folderStatusChanged(account, folder, localFolder.getUnreadMessageCount());
if (localTrashFolder != null) {
l.folderStatusChanged(account, account.getTrashFolderName(), localTrashFolder.getUnreadMessageCount());
}
}
Timber.d("Delete policy for account %s is %s", account.getDescription(), account.getDeletePolicy());
if (folder.equals(account.getOutboxFolderName())) {
for (Message message : messages) {
// If the message was in the Outbox, then it has been copied to local Trash, and has
// to be copied to remote trash
PendingCommand command = PendingAppend.create(account.getTrashFolderName(), message.getUid());
queuePendingCommand(account, command);
}
processPendingCommands(account);
} else if (account.getDeletePolicy() == DeletePolicy.ON_DELETE) {
if (folder.equals(account.getTrashFolderName())) {
queueSetFlag(account, folder, true, Flag.DELETED, uids);
} else {
queueMoveOrCopy(account, folder, account.getTrashFolderName(), false, uids, uidMap);
}
processPendingCommands(account);
} else if (account.getDeletePolicy() == DeletePolicy.MARK_AS_READ) {
queueSetFlag(account, folder, true, Flag.SEEN, uids);
processPendingCommands(account);
} else {
Timber.d("Delete policy %s prevents delete from server", account.getDeletePolicy());
}
unsuppressMessages(account, messages);
} catch (UnavailableStorageException e) {
Timber.i("Failed to delete message because storage is not available - trying again later.");
throw new UnavailableAccountException(e);
} catch (MessagingException me) {
addErrorMessage(account, null, me);
throw new RuntimeException("Error deleting message from local store.", me);
} finally {
closeFolder(localFolder);
closeFolder(localTrashFolder);
}
}
Aggregations