Search in sources :

Example 1 with MessagingListener

use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.

the class MessagingController method sendPendingMessagesSynchronous.

/**
     * Attempt to send any messages that are sitting in the Outbox.
     */
@VisibleForTesting
protected void sendPendingMessagesSynchronous(final Account account) {
    LocalFolder localFolder = null;
    Exception lastFailure = null;
    boolean wasPermanentFailure = false;
    try {
        LocalStore localStore = account.getLocalStore();
        localFolder = localStore.getFolder(account.getOutboxFolderName());
        if (!localFolder.exists()) {
            Timber.v("Outbox does not exist");
            return;
        }
        for (MessagingListener l : getListeners()) {
            l.sendPendingMessagesStarted(account);
        }
        localFolder.open(Folder.OPEN_MODE_RW);
        List<LocalMessage> localMessages = localFolder.getMessages(null);
        int progress = 0;
        int todo = localMessages.size();
        for (MessagingListener l : getListeners()) {
            l.synchronizeMailboxProgress(account, account.getSentFolderName(), progress, todo);
        }
        /*
             * The profile we will use to pull all of the content
             * for a given local message into memory for sending.
             */
        FetchProfile fp = new FetchProfile();
        fp.add(FetchProfile.Item.ENVELOPE);
        fp.add(FetchProfile.Item.BODY);
        Timber.i("Scanning folder '%s' (%d) for messages to send", account.getOutboxFolderName(), localFolder.getId());
        Transport transport = transportProvider.getTransport(K9.app, account);
        for (LocalMessage message : localMessages) {
            if (message.isSet(Flag.DELETED)) {
                message.destroy();
                continue;
            }
            try {
                AtomicInteger count = new AtomicInteger(0);
                AtomicInteger oldCount = sendCount.putIfAbsent(message.getUid(), count);
                if (oldCount != null) {
                    count = oldCount;
                }
                Timber.i("Send count for message %s is %d", message.getUid(), count.get());
                if (count.incrementAndGet() > K9.MAX_SEND_ATTEMPTS) {
                    Timber.e("Send count for message %s can't be delivered after %d attempts. " + "Giving up until the user restarts the device", message.getUid(), MAX_SEND_ATTEMPTS);
                    notificationController.showSendFailedNotification(account, new MessagingException(message.getSubject()));
                    continue;
                }
                localFolder.fetch(Collections.singletonList(message), fp, null);
                try {
                    if (message.getHeader(K9.IDENTITY_HEADER).length > 0) {
                        Timber.v("The user has set the Outbox and Drafts folder to the same thing. " + "This message appears to be a draft, so K-9 will not send it");
                        continue;
                    }
                    message.setFlag(Flag.X_SEND_IN_PROGRESS, true);
                    Timber.i("Sending message with UID %s", message.getUid());
                    transport.sendMessage(message);
                    message.setFlag(Flag.X_SEND_IN_PROGRESS, false);
                    message.setFlag(Flag.SEEN, true);
                    progress++;
                    for (MessagingListener l : getListeners()) {
                        l.synchronizeMailboxProgress(account, account.getSentFolderName(), progress, todo);
                    }
                    moveOrDeleteSentMessage(account, localStore, localFolder, message);
                } catch (AuthenticationFailedException e) {
                    lastFailure = e;
                    wasPermanentFailure = false;
                    handleAuthenticationFailure(account, false);
                    handleSendFailure(account, localStore, localFolder, message, e, wasPermanentFailure);
                } catch (CertificateValidationException e) {
                    lastFailure = e;
                    wasPermanentFailure = false;
                    notifyUserIfCertificateProblem(account, e, false);
                    handleSendFailure(account, localStore, localFolder, message, e, wasPermanentFailure);
                } catch (MessagingException e) {
                    lastFailure = e;
                    wasPermanentFailure = e.isPermanentFailure();
                    handleSendFailure(account, localStore, localFolder, message, e, wasPermanentFailure);
                } catch (Exception e) {
                    lastFailure = e;
                    wasPermanentFailure = true;
                    handleSendFailure(account, localStore, localFolder, message, e, wasPermanentFailure);
                }
            } catch (Exception e) {
                lastFailure = e;
                wasPermanentFailure = false;
                Timber.e(e, "Failed to fetch message for sending");
                addErrorMessage(account, "Failed to fetch message for sending", e);
                notifySynchronizeMailboxFailed(account, localFolder, e);
            }
        }
        for (MessagingListener l : getListeners()) {
            l.sendPendingMessagesCompleted(account);
        }
        if (lastFailure != null) {
            if (wasPermanentFailure) {
                notificationController.showSendFailedNotification(account, lastFailure);
            } else {
                notificationController.showSendFailedNotification(account, lastFailure);
            }
        }
    } catch (UnavailableStorageException e) {
        Timber.i("Failed to send pending messages because storage is not available - trying again later.");
        throw new UnavailableAccountException(e);
    } catch (Exception e) {
        Timber.v(e, "Failed to send pending messages");
        for (MessagingListener l : getListeners()) {
            l.sendPendingMessagesFailed(account);
        }
        addErrorMessage(account, null, e);
    } finally {
        if (lastFailure == null) {
            notificationController.clearSendFailedNotification(account);
        }
        closeFolder(localFolder);
    }
}
Also used : LocalMessage(com.fsck.k9.mailstore.LocalMessage) FetchProfile(com.fsck.k9.mail.FetchProfile) MessagingException(com.fsck.k9.mail.MessagingException) AuthenticationFailedException(com.fsck.k9.mail.AuthenticationFailedException) UnavailableStorageException(com.fsck.k9.mailstore.UnavailableStorageException) LocalStore(com.fsck.k9.mailstore.LocalStore) CertificateValidationException(com.fsck.k9.mail.CertificateValidationException) UnavailableStorageException(com.fsck.k9.mailstore.UnavailableStorageException) IOException(java.io.IOException) MessagingException(com.fsck.k9.mail.MessagingException) AuthenticationFailedException(com.fsck.k9.mail.AuthenticationFailedException) SuppressLint(android.annotation.SuppressLint) LocalFolder(com.fsck.k9.mailstore.LocalFolder) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) CertificateValidationException(com.fsck.k9.mail.CertificateValidationException) Transport(com.fsck.k9.mail.Transport) VisibleForTesting(android.support.annotation.VisibleForTesting)

Example 2 with MessagingListener

use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.

the class MessagingController method searchLocalMessagesSynchronous.

@VisibleForTesting
void searchLocalMessagesSynchronous(final LocalSearch search, final MessagingListener listener) {
    final AccountStats stats = new AccountStats();
    final Set<String> uuidSet = new HashSet<>(Arrays.asList(search.getAccountUuids()));
    List<Account> accounts = Preferences.getPreferences(context).getAccounts();
    boolean allAccounts = uuidSet.contains(SearchSpecification.ALL_ACCOUNTS);
    // for every account we want to search do the query in the localstore
    for (final Account account : accounts) {
        if (!allAccounts && !uuidSet.contains(account.getUuid())) {
            continue;
        }
        // Collecting statistics of the search result
        MessageRetrievalListener<LocalMessage> retrievalListener = new MessageRetrievalListener<LocalMessage>() {

            @Override
            public void messageStarted(String message, int number, int ofTotal) {
            }

            @Override
            public void messagesFinished(int number) {
            }

            @Override
            public void messageFinished(LocalMessage message, int number, int ofTotal) {
                if (!isMessageSuppressed(message)) {
                    List<LocalMessage> messages = new ArrayList<>();
                    messages.add(message);
                    stats.unreadMessageCount += (!message.isSet(Flag.SEEN)) ? 1 : 0;
                    stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0;
                    if (listener != null) {
                        listener.listLocalMessagesAddMessages(account, null, messages);
                    }
                }
            }
        };
        // build and do the query in the localstore
        try {
            LocalStore localStore = account.getLocalStore();
            localStore.searchForMessages(retrievalListener, search);
        } catch (Exception e) {
            addErrorMessage(account, null, e);
        }
    }
    // publish the total search statistics
    if (listener != null) {
        listener.searchStats(stats);
    }
}
Also used : SearchAccount(com.fsck.k9.search.SearchAccount) Account(com.fsck.k9.Account) LocalMessage(com.fsck.k9.mailstore.LocalMessage) ArrayList(java.util.ArrayList) LocalStore(com.fsck.k9.mailstore.LocalStore) CertificateValidationException(com.fsck.k9.mail.CertificateValidationException) UnavailableStorageException(com.fsck.k9.mailstore.UnavailableStorageException) IOException(java.io.IOException) MessagingException(com.fsck.k9.mail.MessagingException) AuthenticationFailedException(com.fsck.k9.mail.AuthenticationFailedException) MessageRetrievalListener(com.fsck.k9.mail.MessageRetrievalListener) AccountStats(com.fsck.k9.AccountStats) HashSet(java.util.HashSet) VisibleForTesting(android.support.annotation.VisibleForTesting)

Example 3 with MessagingListener

use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.

the class MessagingController method downloadMessages.

/**
     * Fetches the messages described by inputMessages from the remote store and writes them to
     * local storage.
     *
     * @param account
     *         The account the remote store belongs to.
     * @param remoteFolder
     *         The remote folder to download messages from.
     * @param localFolder
     *         The {@link LocalFolder} instance corresponding to the remote folder.
     * @param inputMessages
     *         A list of messages objects that store the UIDs of which messages to download.
     * @param flagSyncOnly
     *         Only flags will be fetched from the remote store if this is {@code true}.
     * @param purgeToVisibleLimit
     *         If true, local messages will be purged down to the limit of visible messages.
     *
     * @return The number of downloaded messages that are not flagged as {@link Flag#SEEN}.
     *
     * @throws MessagingException
     */
private int downloadMessages(final Account account, final Folder remoteFolder, final LocalFolder localFolder, List<Message> inputMessages, boolean flagSyncOnly, boolean purgeToVisibleLimit) throws MessagingException {
    final Date earliestDate = account.getEarliestPollDate();
    // now
    Date downloadStarted = new Date();
    if (earliestDate != null) {
        Timber.d("Only syncing messages after %s", earliestDate);
    }
    final String folder = remoteFolder.getName();
    int unreadBeforeStart = 0;
    try {
        AccountStats stats = account.getStats(context);
        unreadBeforeStart = stats.unreadMessageCount;
    } catch (MessagingException e) {
        Timber.e(e, "Unable to getUnreadMessageCount for account: %s", account);
    }
    List<Message> syncFlagMessages = new ArrayList<>();
    List<Message> unsyncedMessages = new ArrayList<>();
    final AtomicInteger newMessages = new AtomicInteger(0);
    List<Message> messages = new ArrayList<>(inputMessages);
    for (Message message : messages) {
        evaluateMessageForDownload(message, folder, localFolder, remoteFolder, account, unsyncedMessages, syncFlagMessages, flagSyncOnly);
    }
    final AtomicInteger progress = new AtomicInteger(0);
    final int todo = unsyncedMessages.size() + syncFlagMessages.size();
    for (MessagingListener l : getListeners()) {
        l.synchronizeMailboxProgress(account, folder, progress.get(), todo);
    }
    Timber.d("SYNC: Have %d unsynced messages", unsyncedMessages.size());
    messages.clear();
    final List<Message> largeMessages = new ArrayList<>();
    final List<Message> smallMessages = new ArrayList<>();
    if (!unsyncedMessages.isEmpty()) {
        /*
             * Reverse the order of the messages. Depending on the server this may get us
             * fetch results for newest to oldest. If not, no harm done.
             */
        Collections.sort(unsyncedMessages, new UidReverseComparator());
        int visibleLimit = localFolder.getVisibleLimit();
        int listSize = unsyncedMessages.size();
        if ((visibleLimit > 0) && (listSize > visibleLimit)) {
            unsyncedMessages = unsyncedMessages.subList(0, visibleLimit);
        }
        FetchProfile fp = new FetchProfile();
        if (remoteFolder.supportsFetchingFlags()) {
            fp.add(FetchProfile.Item.FLAGS);
        }
        fp.add(FetchProfile.Item.ENVELOPE);
        Timber.d("SYNC: About to fetch %d unsynced messages for folder %s", unsyncedMessages.size(), folder);
        fetchUnsyncedMessages(account, remoteFolder, unsyncedMessages, smallMessages, largeMessages, progress, todo, fp);
        String updatedPushState = localFolder.getPushState();
        for (Message message : unsyncedMessages) {
            String newPushState = remoteFolder.getNewPushState(updatedPushState, message);
            if (newPushState != null) {
                updatedPushState = newPushState;
            }
        }
        localFolder.setPushState(updatedPushState);
        Timber.d("SYNC: Synced unsynced messages for folder %s", folder);
    }
    Timber.d("SYNC: Have %d large messages and %d small messages out of %d unsynced messages", largeMessages.size(), smallMessages.size(), unsyncedMessages.size());
    unsyncedMessages.clear();
    /*
         * Grab the content of the small messages first. This is going to
         * be very fast and at very worst will be a single up of a few bytes and a single
         * download of 625k.
         */
    FetchProfile fp = new FetchProfile();
    //TODO: Only fetch small and large messages if we have some
    fp.add(FetchProfile.Item.BODY);
    //        fp.add(FetchProfile.Item.FLAGS);
    //        fp.add(FetchProfile.Item.ENVELOPE);
    downloadSmallMessages(account, remoteFolder, localFolder, smallMessages, progress, unreadBeforeStart, newMessages, todo, fp);
    smallMessages.clear();
    /*
         * Now do the large messages that require more round trips.
         */
    fp = new FetchProfile();
    fp.add(FetchProfile.Item.STRUCTURE);
    downloadLargeMessages(account, remoteFolder, localFolder, largeMessages, progress, unreadBeforeStart, newMessages, todo, fp);
    largeMessages.clear();
    /*
         * Refresh the flags for any messages in the local store that we didn't just
         * download.
         */
    refreshLocalMessageFlags(account, remoteFolder, localFolder, syncFlagMessages, progress, todo);
    Timber.d("SYNC: Synced remote messages for folder %s, %d new messages", folder, newMessages.get());
    if (purgeToVisibleLimit) {
        localFolder.purgeToVisibleLimit(new MessageRemovalListener() {

            @Override
            public void messageRemoved(Message message) {
                for (MessagingListener l : getListeners()) {
                    l.synchronizeMailboxRemovedMessage(account, folder, message);
                }
            }
        });
    }
    // If the oldest message seen on this sync is newer than
    // the oldest message seen on the previous sync, then
    // we want to move our high-water mark forward
    // this is all here just for pop which only syncs inbox
    // this would be a little wrong for IMAP (we'd want a folder-level pref, not an account level pref.)
    // fortunately, we just don't care.
    Long oldestMessageTime = localFolder.getOldestMessageDate();
    if (oldestMessageTime != null) {
        Date oldestExtantMessage = new Date(oldestMessageTime);
        if (oldestExtantMessage.before(downloadStarted) && oldestExtantMessage.after(new Date(account.getLatestOldMessageSeenTime()))) {
            account.setLatestOldMessageSeenTime(oldestExtantMessage.getTime());
            account.save(Preferences.getPreferences(context));
        }
    }
    return newMessages.get();
}
Also used : FetchProfile(com.fsck.k9.mail.FetchProfile) LocalMessage(com.fsck.k9.mailstore.LocalMessage) MimeMessage(com.fsck.k9.mail.internet.MimeMessage) Message(com.fsck.k9.mail.Message) MessagingException(com.fsck.k9.mail.MessagingException) ArrayList(java.util.ArrayList) Date(java.util.Date) SuppressLint(android.annotation.SuppressLint) MessageRemovalListener(com.fsck.k9.mailstore.MessageRemovalListener) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AccountStats(com.fsck.k9.AccountStats)

Example 4 with MessagingListener

use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.

the class MessagingController method sendMessage.

/**
     * Stores the given message in the Outbox and starts a sendPendingMessages command to
     * attempt to send the message.
     */
public void sendMessage(final Account account, final Message message, MessagingListener listener) {
    try {
        LocalStore localStore = account.getLocalStore();
        LocalFolder localFolder = localStore.getFolder(account.getOutboxFolderName());
        localFolder.open(Folder.OPEN_MODE_RW);
        localFolder.appendMessages(Collections.singletonList(message));
        Message localMessage = localFolder.getMessage(message.getUid());
        localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true);
        localFolder.close();
        sendPendingMessages(account, listener);
    } catch (Exception e) {
        /*
            for (MessagingListener l : getListeners())
            {
                // TODO general failed
            }
            */
        addErrorMessage(account, null, e);
    }
}
Also used : LocalFolder(com.fsck.k9.mailstore.LocalFolder) LocalMessage(com.fsck.k9.mailstore.LocalMessage) MimeMessage(com.fsck.k9.mail.internet.MimeMessage) Message(com.fsck.k9.mail.Message) LocalStore(com.fsck.k9.mailstore.LocalStore) CertificateValidationException(com.fsck.k9.mail.CertificateValidationException) UnavailableStorageException(com.fsck.k9.mailstore.UnavailableStorageException) IOException(java.io.IOException) MessagingException(com.fsck.k9.mail.MessagingException) AuthenticationFailedException(com.fsck.k9.mail.AuthenticationFailedException)

Example 5 with MessagingListener

use of com.fsck.k9.controller.MessagingListener in project k-9 by k9mail.

the class MessagingController method loadMoreMessages.

public void loadMoreMessages(Account account, String folder, MessagingListener listener) {
    try {
        LocalStore localStore = account.getLocalStore();
        LocalFolder localFolder = localStore.getFolder(folder);
        if (localFolder.getVisibleLimit() > 0) {
            localFolder.setVisibleLimit(localFolder.getVisibleLimit() + account.getDisplayCount());
        }
        synchronizeMailbox(account, folder, listener, null);
    } catch (MessagingException me) {
        addErrorMessage(account, null, me);
        throw new RuntimeException("Unable to set visible limit on folder", me);
    }
}
Also used : LocalFolder(com.fsck.k9.mailstore.LocalFolder) MessagingException(com.fsck.k9.mail.MessagingException) LocalStore(com.fsck.k9.mailstore.LocalStore)

Aggregations

MessagingException (com.fsck.k9.mail.MessagingException)25 LocalFolder (com.fsck.k9.mailstore.LocalFolder)20 LocalStore (com.fsck.k9.mailstore.LocalStore)20 LocalMessage (com.fsck.k9.mailstore.LocalMessage)18 UnavailableStorageException (com.fsck.k9.mailstore.UnavailableStorageException)15 SuppressLint (android.annotation.SuppressLint)14 Folder (com.fsck.k9.mail.Folder)14 Message (com.fsck.k9.mail.Message)14 MimeMessage (com.fsck.k9.mail.internet.MimeMessage)14 AuthenticationFailedException (com.fsck.k9.mail.AuthenticationFailedException)13 CertificateValidationException (com.fsck.k9.mail.CertificateValidationException)13 IOException (java.io.IOException)13 Store (com.fsck.k9.mail.Store)12 Pop3Store (com.fsck.k9.mail.store.pop3.Pop3Store)12 ArrayList (java.util.ArrayList)9 FetchProfile (com.fsck.k9.mail.FetchProfile)7 VisibleForTesting (android.support.annotation.VisibleForTesting)6 Account (com.fsck.k9.Account)6 Date (java.util.Date)6 SearchAccount (com.fsck.k9.search.SearchAccount)5