Search in sources :

Example 1 with OutboxStateRepository

use of com.fsck.k9.mailstore.OutboxStateRepository 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 OutboxStateRepository

use of com.fsck.k9.mailstore.OutboxStateRepository 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)

Example 3 with OutboxStateRepository

use of com.fsck.k9.mailstore.OutboxStateRepository 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(Account account, Message message, String plaintextSubject, MessagingListener listener) {
    try {
        Long outboxFolderId = account.getOutboxFolderId();
        if (outboxFolderId == null) {
            if (BuildConfig.DEBUG) {
                throw new AssertionError("Outbox does not exist");
            }
            Timber.w("Outbox does not exist");
            outboxFolderId = specialLocalFoldersCreator.createOutbox(account);
        }
        message.setFlag(Flag.SEEN, true);
        MessageStore messageStore = messageStoreManager.getMessageStore(account);
        SaveMessageData messageData = saveMessageDataCreator.createSaveMessageData(message, MessageDownloadState.FULL, plaintextSubject);
        long messageId = messageStore.saveLocalMessage(outboxFolderId, messageData, null);
        LocalStore localStore = localStoreProvider.getInstance(account);
        OutboxStateRepository outboxStateRepository = localStore.getOutboxStateRepository();
        outboxStateRepository.initializeOutboxState(messageId);
        sendPendingMessages(account, listener);
    } catch (Exception e) {
        Timber.e(e, "Error sending message");
    }
}
Also used : MessageStore(com.fsck.k9.mailstore.MessageStore) OutboxStateRepository(com.fsck.k9.mailstore.OutboxStateRepository) SaveMessageData(com.fsck.k9.mailstore.SaveMessageData) LocalStore(com.fsck.k9.mailstore.LocalStore) CertificateValidationException(com.fsck.k9.mail.CertificateValidationException) MessagingException(com.fsck.k9.mail.MessagingException) AuthenticationFailedException(com.fsck.k9.mail.AuthenticationFailedException)

Aggregations

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