Search in sources :

Example 1 with OutboxState

use of com.fsck.k9.mailstore.OutboxState 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) {
    Exception lastFailure = null;
    boolean wasPermanentFailure = false;
    try {
        ServerSettings serverSettings = account.getOutgoingServerSettings();
        if (serverSettings.isMissingCredentials()) {
            handleAuthenticationFailure(account, false);
            return;
        }
        LocalStore localStore = localStoreProvider.getInstance(account);
        OutboxStateRepository outboxStateRepository = localStore.getOutboxStateRepository();
        LocalFolder localFolder = localStore.getFolder(account.getOutboxFolderId());
        if (!localFolder.exists()) {
            Timber.w("Outbox does not exist");
            return;
        }
        localFolder.open();
        long outboxFolderId = localFolder.getDatabaseId();
        List<LocalMessage> localMessages = localFolder.getMessages(null);
        int progress = 0;
        int todo = localMessages.size();
        for (MessagingListener l : getListeners()) {
            l.synchronizeMailboxProgress(account, outboxFolderId, 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 Outbox folder for messages to send");
        Backend backend = getBackend(account);
        for (LocalMessage message : localMessages) {
            if (message.isSet(Flag.DELETED)) {
                // FIXME: When uploading a message to the remote Sent folder the move code creates a placeholder
                // message in the Outbox. This code gets rid of these messages. It'd be preferable if the
                // placeholder message was never created, though.
                message.destroy();
                continue;
            }
            try {
                long messageId = message.getDatabaseId();
                OutboxState outboxState = outboxStateRepository.getOutboxState(messageId);
                if (outboxState.getSendState() != SendState.READY) {
                    Timber.v("Skipping sending message %s", message.getUid());
                    notificationController.showSendFailedNotification(account, new MessagingException(message.getSubject()));
                    continue;
                }
                Timber.i("Send count for message %s is %d", message.getUid(), outboxState.getNumberOfSendAttempts());
                localFolder.fetch(Collections.singletonList(message), fp, null);
                try {
                    if (message.getHeader(K9.IDENTITY_HEADER).length > 0 || message.isSet(Flag.DRAFT)) {
                        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;
                    }
                    outboxStateRepository.incrementSendAttempts(messageId);
                    message.setFlag(Flag.X_SEND_IN_PROGRESS, true);
                    Timber.i("Sending message with UID %s", message.getUid());
                    backend.sendMessage(message);
                    message.setFlag(Flag.X_SEND_IN_PROGRESS, false);
                    message.setFlag(Flag.SEEN, true);
                    progress++;
                    for (MessagingListener l : getListeners()) {
                        l.synchronizeMailboxProgress(account, outboxFolderId, progress, todo);
                    }
                    moveOrDeleteSentMessage(account, localStore, message);
                    outboxStateRepository.removeOutboxState(messageId);
                } catch (AuthenticationFailedException e) {
                    outboxStateRepository.decrementSendAttempts(messageId);
                    lastFailure = e;
                    wasPermanentFailure = false;
                    handleAuthenticationFailure(account, false);
                    handleSendFailure(account, localFolder, message, e);
                } catch (CertificateValidationException e) {
                    outboxStateRepository.decrementSendAttempts(messageId);
                    lastFailure = e;
                    wasPermanentFailure = false;
                    notifyUserIfCertificateProblem(account, e, false);
                    handleSendFailure(account, localFolder, message, e);
                } catch (MessagingException e) {
                    lastFailure = e;
                    wasPermanentFailure = e.isPermanentFailure();
                    if (wasPermanentFailure) {
                        String errorMessage = e.getMessage();
                        outboxStateRepository.setSendAttemptError(messageId, errorMessage);
                    } else if (outboxState.getNumberOfSendAttempts() + 1 >= MAX_SEND_ATTEMPTS) {
                        outboxStateRepository.setSendAttemptsExceeded(messageId);
                    }
                    handleSendFailure(account, localFolder, message, e);
                } catch (Exception e) {
                    lastFailure = e;
                    wasPermanentFailure = true;
                    handleSendFailure(account, localFolder, message, e);
                }
            } catch (Exception e) {
                lastFailure = e;
                wasPermanentFailure = false;
                Timber.e(e, "Failed to fetch message for sending");
                notifySynchronizeMailboxFailed(account, localFolder, e);
            }
        }
        if (lastFailure != null) {
            if (wasPermanentFailure) {
                notificationController.showSendFailedNotification(account, lastFailure);
            } else {
                notificationController.showSendFailedNotification(account, lastFailure);
            }
        }
    } catch (Exception e) {
        Timber.v(e, "Failed to send pending messages");
    } finally {
        if (lastFailure == null) {
            notificationController.clearSendFailedNotification(account);
        }
    }
}
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) OutboxStateRepository(com.fsck.k9.mailstore.OutboxStateRepository) LocalStore(com.fsck.k9.mailstore.LocalStore) CertificateValidationException(com.fsck.k9.mail.CertificateValidationException) MessagingException(com.fsck.k9.mail.MessagingException) AuthenticationFailedException(com.fsck.k9.mail.AuthenticationFailedException) SuppressLint(android.annotation.SuppressLint) OutboxState(com.fsck.k9.mailstore.OutboxState) LocalFolder(com.fsck.k9.mailstore.LocalFolder) Backend(com.fsck.k9.backend.api.Backend) ServerSettings(com.fsck.k9.mail.ServerSettings) CertificateValidationException(com.fsck.k9.mail.CertificateValidationException) VisibleForTesting(androidx.annotation.VisibleForTesting)

Example 2 with OutboxState

use of com.fsck.k9.mailstore.OutboxState in project k-9 by k9mail.

the class MessagingControllerTest method setupAccountWithMessageToSend.

private void setupAccountWithMessageToSend() throws MessagingException {
    account.setOutboxFolderId(FOLDER_ID);
    account.setSentFolderId(SENT_FOLDER_ID);
    when(localStore.getFolder(SENT_FOLDER_ID)).thenReturn(sentFolder);
    when(sentFolder.getDatabaseId()).thenReturn(SENT_FOLDER_ID);
    when(localFolder.exists()).thenReturn(true);
    when(localFolder.getMessages(null)).thenReturn(Collections.singletonList(localMessageToSend1));
    when(localMessageToSend1.getUid()).thenReturn("localMessageToSend1");
    when(localMessageToSend1.getDatabaseId()).thenReturn(42L);
    when(localMessageToSend1.getHeader(K9.IDENTITY_HEADER)).thenReturn(new String[] {});
    OutboxState outboxState = new OutboxState(SendState.READY, 0, null, 0);
    OutboxStateRepository outboxStateRepository = mock(OutboxStateRepository.class);
    when(outboxStateRepository.getOutboxState(42L)).thenReturn(outboxState);
    when(localStore.getOutboxStateRepository()).thenReturn(outboxStateRepository);
    controller.addListener(listener);
}
Also used : OutboxStateRepository(com.fsck.k9.mailstore.OutboxStateRepository) OutboxState(com.fsck.k9.mailstore.OutboxState)

Aggregations

OutboxState (com.fsck.k9.mailstore.OutboxState)2 OutboxStateRepository (com.fsck.k9.mailstore.OutboxStateRepository)2 SuppressLint (android.annotation.SuppressLint)1 VisibleForTesting (androidx.annotation.VisibleForTesting)1 Backend (com.fsck.k9.backend.api.Backend)1 AuthenticationFailedException (com.fsck.k9.mail.AuthenticationFailedException)1 CertificateValidationException (com.fsck.k9.mail.CertificateValidationException)1 FetchProfile (com.fsck.k9.mail.FetchProfile)1 MessagingException (com.fsck.k9.mail.MessagingException)1 ServerSettings (com.fsck.k9.mail.ServerSettings)1 LocalFolder (com.fsck.k9.mailstore.LocalFolder)1 LocalMessage (com.fsck.k9.mailstore.LocalMessage)1 LocalStore (com.fsck.k9.mailstore.LocalStore)1