@Test public void sendPendingMessagesSynchronous_shouldSetProgress() throws MessagingException { setupAccountWithMessageToSend(); controller.sendPendingMessagesSynchronous(account); verify(listener).synchronizeMailboxProgress(account, "SentID", "Sent", 0, 1); }
@VisibleForTesting protected void sendPendingMessagesSynchronous(final Account account) { LocalFolder localOutboxFolder = null; Exception lastFailure = null; boolean wasPermanentFailure = false; try { LocalStore localStore = account.getLocalStore(); localOutboxFolder = localStore.getFolder( account.getOutboxFolderId()); String sentFolderId = account.getSentFolderId(); LocalFolder localSentFolder = localStore.getFolder(sentFolderId); String sentFolderName = localSentFolder != null ? localSentFolder.getName() : sentFolderId; if (!localOutboxFolder.exists()) { Timber.v("Outbox does not exist"); return; } for (MessagingListener l : getListeners()) { l.sendPendingMessagesStarted(account); } localOutboxFolder.open(Folder.OPEN_MODE_RW); List<LocalMessage> localMessages = localOutboxFolder.getMessages(null); int progress = 0; int todo = localMessages.size(); for (MessagingListener l : getListeners()) { l.synchronizeMailboxProgress(account, sentFolderId, sentFolderName, progress, todo); } 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.getOutboxFolderId(), localOutboxFolder.getDatabaseId()); Transport transport = transportProvider.getTransport(QMail.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() > QMail.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; } localOutboxFolder.fetch(Collections.singletonList(message), fp, null); try { if (message.getHeader(QMail.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, sentFolderId, sentFolderName, progress, todo); } moveOrDeleteSentMessage(account, localStore, localOutboxFolder, message); } catch (AuthenticationFailedException e) { lastFailure = e; wasPermanentFailure = false; handleAuthenticationFailure(account, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (CertificateValidationException e) { lastFailure = e; wasPermanentFailure = false; notifyUserIfCertificateProblem(account, e, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (MessagingException e) { lastFailure = e; wasPermanentFailure = e.isPermanentFailure(); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (Exception e) { lastFailure = e; wasPermanentFailure = true; handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } } catch (Exception e) { lastFailure = e; wasPermanentFailure = false; Timber.e(e, "Failed to fetch message for sending"); notifySynchronizeMailboxFailed(account, localOutboxFolder, 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); } } finally { if (lastFailure == null) { notificationController.clearSendFailedNotification(account); } closeFolder(localOutboxFolder); } }
MessagingController { @VisibleForTesting protected void sendPendingMessagesSynchronous(final Account account) { LocalFolder localOutboxFolder = null; Exception lastFailure = null; boolean wasPermanentFailure = false; try { LocalStore localStore = account.getLocalStore(); localOutboxFolder = localStore.getFolder( account.getOutboxFolderId()); String sentFolderId = account.getSentFolderId(); LocalFolder localSentFolder = localStore.getFolder(sentFolderId); String sentFolderName = localSentFolder != null ? localSentFolder.getName() : sentFolderId; if (!localOutboxFolder.exists()) { Timber.v("Outbox does not exist"); return; } for (MessagingListener l : getListeners()) { l.sendPendingMessagesStarted(account); } localOutboxFolder.open(Folder.OPEN_MODE_RW); List<LocalMessage> localMessages = localOutboxFolder.getMessages(null); int progress = 0; int todo = localMessages.size(); for (MessagingListener l : getListeners()) { l.synchronizeMailboxProgress(account, sentFolderId, sentFolderName, progress, todo); } 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.getOutboxFolderId(), localOutboxFolder.getDatabaseId()); Transport transport = transportProvider.getTransport(QMail.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() > QMail.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; } localOutboxFolder.fetch(Collections.singletonList(message), fp, null); try { if (message.getHeader(QMail.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, sentFolderId, sentFolderName, progress, todo); } moveOrDeleteSentMessage(account, localStore, localOutboxFolder, message); } catch (AuthenticationFailedException e) { lastFailure = e; wasPermanentFailure = false; handleAuthenticationFailure(account, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (CertificateValidationException e) { lastFailure = e; wasPermanentFailure = false; notifyUserIfCertificateProblem(account, e, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (MessagingException e) { lastFailure = e; wasPermanentFailure = e.isPermanentFailure(); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (Exception e) { lastFailure = e; wasPermanentFailure = true; handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } } catch (Exception e) { lastFailure = e; wasPermanentFailure = false; Timber.e(e, "Failed to fetch message for sending"); notifySynchronizeMailboxFailed(account, localOutboxFolder, 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); } } finally { if (lastFailure == null) { notificationController.clearSendFailedNotification(account); } closeFolder(localOutboxFolder); } } }
MessagingController { @VisibleForTesting protected void sendPendingMessagesSynchronous(final Account account) { LocalFolder localOutboxFolder = null; Exception lastFailure = null; boolean wasPermanentFailure = false; try { LocalStore localStore = account.getLocalStore(); localOutboxFolder = localStore.getFolder( account.getOutboxFolderId()); String sentFolderId = account.getSentFolderId(); LocalFolder localSentFolder = localStore.getFolder(sentFolderId); String sentFolderName = localSentFolder != null ? localSentFolder.getName() : sentFolderId; if (!localOutboxFolder.exists()) { Timber.v("Outbox does not exist"); return; } for (MessagingListener l : getListeners()) { l.sendPendingMessagesStarted(account); } localOutboxFolder.open(Folder.OPEN_MODE_RW); List<LocalMessage> localMessages = localOutboxFolder.getMessages(null); int progress = 0; int todo = localMessages.size(); for (MessagingListener l : getListeners()) { l.synchronizeMailboxProgress(account, sentFolderId, sentFolderName, progress, todo); } 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.getOutboxFolderId(), localOutboxFolder.getDatabaseId()); Transport transport = transportProvider.getTransport(QMail.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() > QMail.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; } localOutboxFolder.fetch(Collections.singletonList(message), fp, null); try { if (message.getHeader(QMail.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, sentFolderId, sentFolderName, progress, todo); } moveOrDeleteSentMessage(account, localStore, localOutboxFolder, message); } catch (AuthenticationFailedException e) { lastFailure = e; wasPermanentFailure = false; handleAuthenticationFailure(account, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (CertificateValidationException e) { lastFailure = e; wasPermanentFailure = false; notifyUserIfCertificateProblem(account, e, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (MessagingException e) { lastFailure = e; wasPermanentFailure = e.isPermanentFailure(); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (Exception e) { lastFailure = e; wasPermanentFailure = true; handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } } catch (Exception e) { lastFailure = e; wasPermanentFailure = false; Timber.e(e, "Failed to fetch message for sending"); notifySynchronizeMailboxFailed(account, localOutboxFolder, 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); } } finally { if (lastFailure == null) { notificationController.clearSendFailedNotification(account); } closeFolder(localOutboxFolder); } } @VisibleForTesting  MessagingController(Context context, NotificationController notificationController,
            Contacts contacts, TransportProvider transportProvider); }
MessagingController { @VisibleForTesting protected void sendPendingMessagesSynchronous(final Account account) { LocalFolder localOutboxFolder = null; Exception lastFailure = null; boolean wasPermanentFailure = false; try { LocalStore localStore = account.getLocalStore(); localOutboxFolder = localStore.getFolder( account.getOutboxFolderId()); String sentFolderId = account.getSentFolderId(); LocalFolder localSentFolder = localStore.getFolder(sentFolderId); String sentFolderName = localSentFolder != null ? localSentFolder.getName() : sentFolderId; if (!localOutboxFolder.exists()) { Timber.v("Outbox does not exist"); return; } for (MessagingListener l : getListeners()) { l.sendPendingMessagesStarted(account); } localOutboxFolder.open(Folder.OPEN_MODE_RW); List<LocalMessage> localMessages = localOutboxFolder.getMessages(null); int progress = 0; int todo = localMessages.size(); for (MessagingListener l : getListeners()) { l.synchronizeMailboxProgress(account, sentFolderId, sentFolderName, progress, todo); } 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.getOutboxFolderId(), localOutboxFolder.getDatabaseId()); Transport transport = transportProvider.getTransport(QMail.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() > QMail.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; } localOutboxFolder.fetch(Collections.singletonList(message), fp, null); try { if (message.getHeader(QMail.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, sentFolderId, sentFolderName, progress, todo); } moveOrDeleteSentMessage(account, localStore, localOutboxFolder, message); } catch (AuthenticationFailedException e) { lastFailure = e; wasPermanentFailure = false; handleAuthenticationFailure(account, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (CertificateValidationException e) { lastFailure = e; wasPermanentFailure = false; notifyUserIfCertificateProblem(account, e, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (MessagingException e) { lastFailure = e; wasPermanentFailure = e.isPermanentFailure(); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (Exception e) { lastFailure = e; wasPermanentFailure = true; handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } } catch (Exception e) { lastFailure = e; wasPermanentFailure = false; Timber.e(e, "Failed to fetch message for sending"); notifySynchronizeMailboxFailed(account, localOutboxFolder, 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); } } finally { if (lastFailure == null) { notificationController.clearSendFailedNotification(account); } closeFolder(localOutboxFolder); } } @VisibleForTesting  MessagingController(Context context, NotificationController notificationController,
            Contacts contacts, TransportProvider transportProvider); static synchronized MessagingController getInstance(Context context); void addListener(MessagingListener listener); void refreshListener(MessagingListener listener); void removeListener(MessagingListener listener); Set<MessagingListener> getListeners(); Set<MessagingListener> getListeners(MessagingListener listener); void listFolders(final Account account, final boolean refreshRemote, final MessagingListener listener); void listSubFolders(final Account account, final String parentFolderId, final boolean refreshRemote, final MessagingListener listener); void listFoldersSynchronous(final Account account, final boolean refreshRemote,
            final MessagingListener listener); void listSubFoldersSynchronous(final Account account, final String parentFolderId, final boolean refreshRemote,
            final MessagingListener listener); void searchLocalMessages(final LocalSearch search, final MessagingListener listener); Future<?> searchRemoteMessages(final String acctUuid, final String folderId, final String folderName, final String query,
            final Set<Flag> requiredFlags, final Set<Flag> forbiddenFlags, final MessagingListener listener); void loadSearchResults(final Account account, final String folderName, final List<Message> messages,
            final MessagingListener listener); void loadMoreMessages(Account account, String folderId, MessagingListener listener); void synchronizeMailbox(final Account account, final String folderId, final String folderName, final MessagingListener listener,
            final Folder providedRemoteFolder); void markAllMessagesRead(final Account account, final String folder); void setFlag(final Account account, final List<Long> messageIds, final Flag flag,
            final boolean newState); void setFlagForThreads(final Account account, final List<Long> threadRootIds,
            final Flag flag, final boolean newState); void setFlag(Account account, String folderId, List<? extends Message> messages, Flag flag,
            boolean newState); void setFlag(Account account, String folderName, String uid, Flag flag,
            boolean newState); void clearAllPending(final Account account); void loadMessageRemotePartial(final Account account, final String folderId,
            final String uid, final MessagingListener listener); void loadMessageRemote(final Account account, final String folderId,
            final String uid, final MessagingListener listener); LocalMessage loadMessage(Account account, String folderId, String uid); void loadAttachment(final Account account, final LocalMessage message, final Part part,
            final MessagingListener listener); void sendMessage(final Account account,
            final Message message,
            MessagingListener listener); void sendPendingMessages(MessagingListener listener); void sendPendingMessages(final Account account,
            MessagingListener listener); void getAccountStats(final Context context, final Account account,
            final MessagingListener listener); void getSearchAccountStats(final SearchAccount searchAccount,
            final MessagingListener listener); AccountStats getSearchAccountStatsSynchronous(final SearchAccount searchAccount,
            final MessagingListener listener); void getFolderUnreadMessageCount(final Account account, final String folderId,
            final MessagingListener l); boolean isMoveCapable(MessageReference messageReference); boolean isCopyCapable(MessageReference message); boolean isMoveCapable(final Account account); boolean isCopyCapable(final Account account); void moveMessages(final Account srcAccount, final String srcFolder,
            List<MessageReference> messageReferences, final String destFolder); void moveMessagesInThread(Account srcAccount, final String srcFolder,
            final List<MessageReference> messageReferences, final String destFolder); void moveMessage(final Account account, final String srcFolder, final MessageReference message,
            final String destFolder); void copyMessages(final Account srcAccount, final String srcFolder,
            final List<MessageReference> messageReferences, final String destFolder); void copyMessagesInThread(Account srcAccount, final String srcFolder,
            final List<MessageReference> messageReferences, final String destFolder); void copyMessage(final Account account, final String srcFolder, final MessageReference message,
            final String destFolder); void expunge(final Account account, final String folder); void deleteDraft(final Account account, long id); void deleteThreads(final List<MessageReference> messages); void deleteMessage(MessageReference message, final MessagingListener listener); void deleteMessages(List<MessageReference> messages, final MessagingListener listener); @SuppressLint("NewApi") // used for debugging only void debugClearMessagesLocally(final List<MessageReference> messages); void emptyTrash(final Account account, MessagingListener listener); void clearFolder(final Account account, final String folderId, final ActivityListener listener); void sendAlternate(Context context, Account account, LocalMessage message); void checkMail(final Context context, final Account account,
            final boolean ignoreLastCheckedTime,
            final boolean useManualWakeLock,
            final MessagingListener listener); void compact(final Account account, final MessagingListener ml); void clear(final Account account, final MessagingListener ml); void recreate(final Account account, final MessagingListener ml); void deleteAccount(Account account); Message saveDraft(final Account account, final Message message, long existingDraftId, boolean saveRemotely); long getId(Message message); MessagingListener getCheckMailListener(); void setCheckMailListener(MessagingListener checkMailListener); Collection<Pusher> getPushers(); boolean setupPushing(final Account account); void stopAllPushing(); void messagesArrived(final Account account, final Folder remoteFolder, final List<Message> messages,
            final boolean flagSyncOnly); void systemStatusChanged(); void cancelNotificationsForAccount(Account account); void cancelNotificationForMessage(Account account, MessageReference messageReference); void clearCertificateErrorNotifications(Account account, CheckDirection direction); void notifyUserIfCertificateProblem(Account account, Exception exception, boolean incoming); }
MessagingController { @VisibleForTesting protected void sendPendingMessagesSynchronous(final Account account) { LocalFolder localOutboxFolder = null; Exception lastFailure = null; boolean wasPermanentFailure = false; try { LocalStore localStore = account.getLocalStore(); localOutboxFolder = localStore.getFolder( account.getOutboxFolderId()); String sentFolderId = account.getSentFolderId(); LocalFolder localSentFolder = localStore.getFolder(sentFolderId); String sentFolderName = localSentFolder != null ? localSentFolder.getName() : sentFolderId; if (!localOutboxFolder.exists()) { Timber.v("Outbox does not exist"); return; } for (MessagingListener l : getListeners()) { l.sendPendingMessagesStarted(account); } localOutboxFolder.open(Folder.OPEN_MODE_RW); List<LocalMessage> localMessages = localOutboxFolder.getMessages(null); int progress = 0; int todo = localMessages.size(); for (MessagingListener l : getListeners()) { l.synchronizeMailboxProgress(account, sentFolderId, sentFolderName, progress, todo); } 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.getOutboxFolderId(), localOutboxFolder.getDatabaseId()); Transport transport = transportProvider.getTransport(QMail.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() > QMail.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; } localOutboxFolder.fetch(Collections.singletonList(message), fp, null); try { if (message.getHeader(QMail.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, sentFolderId, sentFolderName, progress, todo); } moveOrDeleteSentMessage(account, localStore, localOutboxFolder, message); } catch (AuthenticationFailedException e) { lastFailure = e; wasPermanentFailure = false; handleAuthenticationFailure(account, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (CertificateValidationException e) { lastFailure = e; wasPermanentFailure = false; notifyUserIfCertificateProblem(account, e, false); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (MessagingException e) { lastFailure = e; wasPermanentFailure = e.isPermanentFailure(); handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } catch (Exception e) { lastFailure = e; wasPermanentFailure = true; handleSendFailure(account, localStore, localOutboxFolder, message, e, wasPermanentFailure); } } catch (Exception e) { lastFailure = e; wasPermanentFailure = false; Timber.e(e, "Failed to fetch message for sending"); notifySynchronizeMailboxFailed(account, localOutboxFolder, 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); } } finally { if (lastFailure == null) { notificationController.clearSendFailedNotification(account); } closeFolder(localOutboxFolder); } } @VisibleForTesting  MessagingController(Context context, NotificationController notificationController,
            Contacts contacts, TransportProvider transportProvider); static synchronized MessagingController getInstance(Context context); void addListener(MessagingListener listener); void refreshListener(MessagingListener listener); void removeListener(MessagingListener listener); Set<MessagingListener> getListeners(); Set<MessagingListener> getListeners(MessagingListener listener); void listFolders(final Account account, final boolean refreshRemote, final MessagingListener listener); void listSubFolders(final Account account, final String parentFolderId, final boolean refreshRemote, final MessagingListener listener); void listFoldersSynchronous(final Account account, final boolean refreshRemote,
            final MessagingListener listener); void listSubFoldersSynchronous(final Account account, final String parentFolderId, final boolean refreshRemote,
            final MessagingListener listener); void searchLocalMessages(final LocalSearch search, final MessagingListener listener); Future<?> searchRemoteMessages(final String acctUuid, final String folderId, final String folderName, final String query,
            final Set<Flag> requiredFlags, final Set<Flag> forbiddenFlags, final MessagingListener listener); void loadSearchResults(final Account account, final String folderName, final List<Message> messages,
            final MessagingListener listener); void loadMoreMessages(Account account, String folderId, MessagingListener listener); void synchronizeMailbox(final Account account, final String folderId, final String folderName, final MessagingListener listener,
            final Folder providedRemoteFolder); void markAllMessagesRead(final Account account, final String folder); void setFlag(final Account account, final List<Long> messageIds, final Flag flag,
            final boolean newState); void setFlagForThreads(final Account account, final List<Long> threadRootIds,
            final Flag flag, final boolean newState); void setFlag(Account account, String folderId, List<? extends Message> messages, Flag flag,
            boolean newState); void setFlag(Account account, String folderName, String uid, Flag flag,
            boolean newState); void clearAllPending(final Account account); void loadMessageRemotePartial(final Account account, final String folderId,
            final String uid, final MessagingListener listener); void loadMessageRemote(final Account account, final String folderId,
            final String uid, final MessagingListener listener); LocalMessage loadMessage(Account account, String folderId, String uid); void loadAttachment(final Account account, final LocalMessage message, final Part part,
            final MessagingListener listener); void sendMessage(final Account account,
            final Message message,
            MessagingListener listener); void sendPendingMessages(MessagingListener listener); void sendPendingMessages(final Account account,
            MessagingListener listener); void getAccountStats(final Context context, final Account account,
            final MessagingListener listener); void getSearchAccountStats(final SearchAccount searchAccount,
            final MessagingListener listener); AccountStats getSearchAccountStatsSynchronous(final SearchAccount searchAccount,
            final MessagingListener listener); void getFolderUnreadMessageCount(final Account account, final String folderId,
            final MessagingListener l); boolean isMoveCapable(MessageReference messageReference); boolean isCopyCapable(MessageReference message); boolean isMoveCapable(final Account account); boolean isCopyCapable(final Account account); void moveMessages(final Account srcAccount, final String srcFolder,
            List<MessageReference> messageReferences, final String destFolder); void moveMessagesInThread(Account srcAccount, final String srcFolder,
            final List<MessageReference> messageReferences, final String destFolder); void moveMessage(final Account account, final String srcFolder, final MessageReference message,
            final String destFolder); void copyMessages(final Account srcAccount, final String srcFolder,
            final List<MessageReference> messageReferences, final String destFolder); void copyMessagesInThread(Account srcAccount, final String srcFolder,
            final List<MessageReference> messageReferences, final String destFolder); void copyMessage(final Account account, final String srcFolder, final MessageReference message,
            final String destFolder); void expunge(final Account account, final String folder); void deleteDraft(final Account account, long id); void deleteThreads(final List<MessageReference> messages); void deleteMessage(MessageReference message, final MessagingListener listener); void deleteMessages(List<MessageReference> messages, final MessagingListener listener); @SuppressLint("NewApi") // used for debugging only void debugClearMessagesLocally(final List<MessageReference> messages); void emptyTrash(final Account account, MessagingListener listener); void clearFolder(final Account account, final String folderId, final ActivityListener listener); void sendAlternate(Context context, Account account, LocalMessage message); void checkMail(final Context context, final Account account,
            final boolean ignoreLastCheckedTime,
            final boolean useManualWakeLock,
            final MessagingListener listener); void compact(final Account account, final MessagingListener ml); void clear(final Account account, final MessagingListener ml); void recreate(final Account account, final MessagingListener ml); void deleteAccount(Account account); Message saveDraft(final Account account, final Message message, long existingDraftId, boolean saveRemotely); long getId(Message message); MessagingListener getCheckMailListener(); void setCheckMailListener(MessagingListener checkMailListener); Collection<Pusher> getPushers(); boolean setupPushing(final Account account); void stopAllPushing(); void messagesArrived(final Account account, final Folder remoteFolder, final List<Message> messages,
            final boolean flagSyncOnly); void systemStatusChanged(); void cancelNotificationsForAccount(Account account); void cancelNotificationForMessage(Account account, MessageReference messageReference); void clearCertificateErrorNotifications(Account account, CheckDirection direction); void notifyUserIfCertificateProblem(Account account, Exception exception, boolean incoming); static final long INVALID_MESSAGE_ID; }