Search in sources :

Example 11 with FetchProfile

use of com.fsck.k9.mail.FetchProfile in project k-9 by k9mail.

the class MessagingController method refreshLocalMessageFlags.

private void refreshLocalMessageFlags(final Account account, final Folder remoteFolder, final LocalFolder localFolder, List<Message> syncFlagMessages, final AtomicInteger progress, final int todo) throws MessagingException {
    final String folder = remoteFolder.getName();
    if (remoteFolder.supportsFetchingFlags()) {
        Timber.d("SYNC: About to sync flags for %d remote messages for folder %s", syncFlagMessages.size(), folder);
        FetchProfile fp = new FetchProfile();
        fp.add(FetchProfile.Item.FLAGS);
        List<Message> undeletedMessages = new LinkedList<>();
        for (Message message : syncFlagMessages) {
            if (!message.isSet(Flag.DELETED)) {
                undeletedMessages.add(message);
            }
        }
        remoteFolder.fetch(undeletedMessages, fp, null);
        for (Message remoteMessage : syncFlagMessages) {
            LocalMessage localMessage = localFolder.getMessage(remoteMessage.getUid());
            boolean messageChanged = syncFlags(localMessage, remoteMessage);
            if (messageChanged) {
                boolean shouldBeNotifiedOf = false;
                if (localMessage.isSet(Flag.DELETED) || isMessageSuppressed(localMessage)) {
                    for (MessagingListener l : getListeners()) {
                        l.synchronizeMailboxRemovedMessage(account, folder, localMessage);
                    }
                } else {
                    if (shouldNotifyForMessage(account, localFolder, localMessage)) {
                        shouldBeNotifiedOf = true;
                    }
                }
                // we're only interested in messages that need removing
                if (!shouldBeNotifiedOf) {
                    MessageReference messageReference = localMessage.makeMessageReference();
                    notificationController.removeNewMailNotification(account, messageReference);
                }
            }
            progress.incrementAndGet();
            for (MessagingListener l : getListeners()) {
                l.synchronizeMailboxProgress(account, folder, progress.get(), todo);
            }
        }
    }
}
Also used : LocalMessage(com.fsck.k9.mailstore.LocalMessage) 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) MessageReference(com.fsck.k9.activity.MessageReference) LinkedList(java.util.LinkedList)

Example 12 with FetchProfile

use of com.fsck.k9.mail.FetchProfile in project k-9 by k9mail.

the class RawMessageProvider method loadMessage.

private LocalMessage loadMessage(MessageReference messageReference) {
    String accountUuid = messageReference.getAccountUuid();
    long folderId = messageReference.getFolderId();
    String uid = messageReference.getUid();
    Account account = Preferences.getPreferences(getContext()).getAccount(accountUuid);
    if (account == null) {
        Timber.w("Account not found: %s", accountUuid);
        return null;
    }
    try {
        LocalStore localStore = DI.get(LocalStoreProvider.class).getInstance(account);
        LocalFolder localFolder = localStore.getFolder(folderId);
        localFolder.open();
        LocalMessage message = localFolder.getMessage(uid);
        if (message == null || message.getDatabaseId() == 0) {
            Timber.w("Message not found: folder=%s, uid=%s", folderId, uid);
            return null;
        }
        FetchProfile fetchProfile = new FetchProfile();
        fetchProfile.add(FetchProfile.Item.BODY);
        localFolder.fetch(Collections.singletonList(message), fetchProfile, null);
        return message;
    } catch (MessagingException e) {
        Timber.e(e, "Error loading message: folder=%d, uid=%s", folderId, uid);
        return null;
    }
}
Also used : LocalFolder(com.fsck.k9.mailstore.LocalFolder) Account(com.fsck.k9.Account) LocalMessage(com.fsck.k9.mailstore.LocalMessage) FetchProfile(com.fsck.k9.mail.FetchProfile) MessagingException(com.fsck.k9.mail.MessagingException) LocalStore(com.fsck.k9.mailstore.LocalStore) LocalStoreProvider(com.fsck.k9.mailstore.LocalStoreProvider)

Example 13 with FetchProfile

use of com.fsck.k9.mail.FetchProfile 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.
 */
void processPendingAppend(PendingAppend command, Account account) throws MessagingException {
    LocalStore localStore = localStoreProvider.getInstance(account);
    long folderId = command.folderId;
    LocalFolder localFolder = localStore.getFolder(folderId);
    localFolder.open();
    String folderServerId = localFolder.getServerId();
    String uid = command.uid;
    LocalMessage localMessage = localFolder.getMessage(uid);
    if (localMessage == null) {
        return;
    }
    if (!localMessage.getUid().startsWith(K9.LOCAL_UID_PREFIX)) {
        // FIXME: This should never happen. Throw in debug builds.
        return;
    }
    Backend backend = getBackend(account);
    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 messageServerId = backend.findByMessageId(folderServerId, localMessage.getMessageId());
        if (messageServerId != 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, messageServerId);
            String oldUid = localMessage.getUid();
            localMessage.setUid(messageServerId);
            localFolder.changeUid(localMessage);
            for (MessagingListener l : getListeners()) {
                l.messageUidChanged(account, folderId, 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);
    String messageServerId = backend.uploadMessage(folderServerId, localMessage);
    if (messageServerId == null) {
        // We didn't get the server UID of the uploaded message. Remove the local message now. The uploaded
        // version will be downloaded during the next sync.
        localFolder.destroyMessages(Collections.singletonList(localMessage));
    } else {
        localMessage.setUid(messageServerId);
        localFolder.changeUid(localMessage);
        for (MessagingListener l : getListeners()) {
            l.messageUidChanged(account, folderId, oldUid, localMessage.getUid());
        }
    }
}
Also used : LocalFolder(com.fsck.k9.mailstore.LocalFolder) LocalMessage(com.fsck.k9.mailstore.LocalMessage) Backend(com.fsck.k9.backend.api.Backend) FetchProfile(com.fsck.k9.mail.FetchProfile) LocalStore(com.fsck.k9.mailstore.LocalStore)

Example 14 with FetchProfile

use of com.fsck.k9.mail.FetchProfile in project k-9 by k9mail.

the class MessagingController method loadMessage.

public LocalMessage loadMessage(Account account, long folderId, String uid) throws MessagingException {
    LocalStore localStore = localStoreProvider.getInstance(account);
    LocalFolder localFolder = localStore.getFolder(folderId);
    localFolder.open();
    LocalMessage message = localFolder.getMessage(uid);
    if (message == null || message.getDatabaseId() == 0) {
        String folderName = localFolder.getName();
        throw new IllegalArgumentException("Message not found: folder=" + folderName + ", uid=" + uid);
    }
    FetchProfile fp = new FetchProfile();
    fp.add(FetchProfile.Item.BODY);
    localFolder.fetch(Collections.singletonList(message), fp, null);
    notificationController.removeNewMailNotification(account, message.makeMessageReference());
    markMessageAsOpened(account, message);
    return message;
}
Also used : LocalFolder(com.fsck.k9.mailstore.LocalFolder) LocalMessage(com.fsck.k9.mailstore.LocalMessage) FetchProfile(com.fsck.k9.mail.FetchProfile) LocalStore(com.fsck.k9.mailstore.LocalStore)

Example 15 with FetchProfile

use of com.fsck.k9.mail.FetchProfile 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)

Aggregations

FetchProfile (com.fsck.k9.mail.FetchProfile)49 Test (org.junit.Test)27 LocalMessage (com.fsck.k9.mailstore.LocalMessage)15 MessagingException (com.fsck.k9.mail.MessagingException)12 ArrayList (java.util.ArrayList)10 LocalFolder (com.fsck.k9.mailstore.LocalFolder)9 LocalStore (com.fsck.k9.mailstore.LocalStore)9 SQLiteDatabase (android.database.sqlite.SQLiteDatabase)8 Date (java.util.Date)8 Message (com.fsck.k9.mail.Message)7 SuppressLint (android.annotation.SuppressLint)6 MimeMessage (com.fsck.k9.mail.internet.MimeMessage)6 AuthenticationFailedException (com.fsck.k9.mail.AuthenticationFailedException)5 Multipart (com.fsck.k9.mail.Multipart)5 ByteArrayInputStream (java.io.ByteArrayInputStream)5 IOException (java.io.IOException)5 WebDavMessage (com.fsck.k9.mail.store.webdav.WebDavMessage)4 LinkedList (java.util.LinkedList)4 HttpResponse (org.apache.http.HttpResponse)4 StatusLine (org.apache.http.StatusLine)4