diff options
Diffstat (limited to '')
-rw-r--r-- | comm/mailnews/base/src/nsMsgOfflineManager.cpp | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/comm/mailnews/base/src/nsMsgOfflineManager.cpp b/comm/mailnews/base/src/nsMsgOfflineManager.cpp new file mode 100644 index 0000000000..7d6935fc89 --- /dev/null +++ b/comm/mailnews/base/src/nsMsgOfflineManager.cpp @@ -0,0 +1,352 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * The offline manager service - manages going online and offline, and + * synchronization + */ +#include "msgCore.h" +#include "netCore.h" +#include "nsMsgOfflineManager.h" +#include "nsIServiceManager.h" +#include "nsIImapService.h" +#include "nsIMsgSendLater.h" +#include "nsIMsgAccountManager.h" +#include "nsIIOService.h" +#include "nsNetCID.h" +#include "nsINntpService.h" +#include "nsIMsgStatusFeedback.h" +#include "nsServiceManagerUtils.h" +#include "mozilla/Components.h" + +#define NS_MSGSENDLATER_CID \ + { /* E15C83F1-1CF4-11d3-8EF0-00A024A7D144 */ \ + 0xe15c83f1, 0x1cf4, 0x11d3, { \ + 0x8e, 0xf0, 0x0, 0xa0, 0x24, 0xa7, 0xd1, 0x44 \ + } \ + } +static NS_DEFINE_CID(kMsgSendLaterCID, NS_MSGSENDLATER_CID); + +NS_IMPL_ISUPPORTS(nsMsgOfflineManager, nsIMsgOfflineManager, + nsIMsgSendLaterListener, nsIObserver, + nsISupportsWeakReference, nsIUrlListener) + +nsMsgOfflineManager::nsMsgOfflineManager() + : m_inProgress(false), + m_sendUnsentMessages(false), + m_downloadNews(false), + m_downloadMail(false), + m_playbackOfflineImapOps(false), + m_goOfflineWhenDone(false), + m_curState(eNoState), + m_curOperation(eNoOp) {} + +nsMsgOfflineManager::~nsMsgOfflineManager() {} + +/* attribute nsIMsgWindow window; */ +NS_IMETHODIMP nsMsgOfflineManager::GetWindow(nsIMsgWindow** aWindow) { + NS_ENSURE_ARG(aWindow); + NS_IF_ADDREF(*aWindow = m_window); + return NS_OK; +} +NS_IMETHODIMP nsMsgOfflineManager::SetWindow(nsIMsgWindow* aWindow) { + m_window = aWindow; + if (m_window) + m_window->GetStatusFeedback(getter_AddRefs(m_statusFeedback)); + else + m_statusFeedback = nullptr; + return NS_OK; +} + +/* attribute boolean inProgress; */ +NS_IMETHODIMP nsMsgOfflineManager::GetInProgress(bool* aInProgress) { + NS_ENSURE_ARG(aInProgress); + *aInProgress = m_inProgress; + return NS_OK; +} + +NS_IMETHODIMP nsMsgOfflineManager::SetInProgress(bool aInProgress) { + m_inProgress = aInProgress; + return NS_OK; +} + +nsresult nsMsgOfflineManager::StopRunning(nsresult exitStatus) { + m_inProgress = false; + return exitStatus; +} + +nsresult nsMsgOfflineManager::AdvanceToNextState(nsresult exitStatus) { + // NS_BINDING_ABORTED is used for the user pressing stop, which + // should cause us to abort the offline process. Other errors + // should allow us to continue. + if (exitStatus == NS_BINDING_ABORTED) { + return StopRunning(exitStatus); + } + if (m_curOperation == eGoingOnline) { + switch (m_curState) { + case eNoState: + + m_curState = eSendingUnsent; + if (m_sendUnsentMessages) { + SendUnsentMessages(); + } else + AdvanceToNextState(NS_OK); + break; + case eSendingUnsent: + + m_curState = eSynchronizingOfflineImapChanges; + if (m_playbackOfflineImapOps) + return SynchronizeOfflineImapChanges(); + else + AdvanceToNextState(NS_OK); // recurse to next state. + break; + case eSynchronizingOfflineImapChanges: + m_curState = eDone; + return StopRunning(exitStatus); + default: + NS_ASSERTION(false, "unhandled current state when going online"); + } + } else if (m_curOperation == eDownloadingForOffline) { + switch (m_curState) { + case eNoState: + m_curState = eDownloadingNews; + if (m_downloadNews) + DownloadOfflineNewsgroups(); + else + AdvanceToNextState(NS_OK); + break; + case eSendingUnsent: + if (m_goOfflineWhenDone) { + SetOnlineState(false); + } + break; + case eDownloadingNews: + m_curState = eDownloadingMail; + if (m_downloadMail) + DownloadMail(); + else + AdvanceToNextState(NS_OK); + break; + case eDownloadingMail: + m_curState = eSendingUnsent; + if (m_sendUnsentMessages) + SendUnsentMessages(); + else + AdvanceToNextState(NS_OK); + break; + default: + NS_ASSERTION(false, + "unhandled current state when downloading for offline"); + } + } + return NS_OK; +} + +nsresult nsMsgOfflineManager::SynchronizeOfflineImapChanges() { + nsresult rv = NS_OK; + nsCOMPtr<nsIImapService> imapService = + do_GetService("@mozilla.org/messenger/imapservice;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + return imapService->PlaybackAllOfflineOperations( + m_window, this, getter_AddRefs(mOfflineImapSync)); +} + +nsresult nsMsgOfflineManager::SendUnsentMessages() { + nsresult rv; + nsCOMPtr<nsIMsgSendLater> pMsgSendLater(do_GetService(kMsgSendLaterCID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIMsgAccountManager> accountManager = + do_GetService("@mozilla.org/messenger/account-manager;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + // now we have to iterate over the identities, finding the *unique* unsent + // messages folder for each one, determine if they have unsent messages, and + // if so, add them to the list of identities to send unsent messages from. + // However, I think there's only ever one unsent messages folder at the + // moment, so I think we'll go with that for now. + nsTArray<RefPtr<nsIMsgIdentity>> identities; + + if (NS_SUCCEEDED(rv) && accountManager) { + rv = accountManager->GetAllIdentities(identities); + NS_ENSURE_SUCCESS(rv, rv); + } + nsCOMPtr<nsIMsgIdentity> identityToUse; + for (auto thisIdentity : identities) { + if (thisIdentity) { + nsCOMPtr<nsIMsgFolder> outboxFolder; + pMsgSendLater->GetUnsentMessagesFolder(thisIdentity, + getter_AddRefs(outboxFolder)); + if (outboxFolder) { + int32_t numMessages; + outboxFolder->GetTotalMessages(false, &numMessages); + if (numMessages > 0) { + identityToUse = thisIdentity; + break; + } + } + } + } + if (identityToUse) { +#ifdef MOZ_SUITE + if (m_statusFeedback) pMsgSendLater->SetStatusFeedback(m_statusFeedback); +#endif + + pMsgSendLater->AddListener(this); + rv = pMsgSendLater->SendUnsentMessages(identityToUse); + ShowStatus("sendingUnsent"); + // if we succeeded, return - we'll run the next operation when the + // send finishes. Otherwise, advance to the next state. + if (NS_SUCCEEDED(rv)) return rv; + } + return AdvanceToNextState(rv); +} + +#define MESSENGER_STRING_URL "chrome://messenger/locale/messenger.properties" + +nsresult nsMsgOfflineManager::ShowStatus(const char* statusMsgName) { + if (!mStringBundle) { + nsCOMPtr<nsIStringBundleService> sBundleService = + mozilla::components::StringBundle::Service(); + NS_ENSURE_TRUE(sBundleService, NS_ERROR_UNEXPECTED); + sBundleService->CreateBundle(MESSENGER_STRING_URL, + getter_AddRefs(mStringBundle)); + return NS_OK; + } + + nsString statusString; + nsresult res = mStringBundle->GetStringFromName(statusMsgName, statusString); + + if (NS_SUCCEEDED(res) && m_statusFeedback) + m_statusFeedback->ShowStatusString(statusString); + + return res; +} + +nsresult nsMsgOfflineManager::DownloadOfflineNewsgroups() { + nsresult rv; + ShowStatus("downloadingNewsgroups"); + nsCOMPtr<nsINntpService> nntpService( + do_GetService("@mozilla.org/messenger/nntpservice;1", &rv)); + if (NS_SUCCEEDED(rv) && nntpService) + rv = nntpService->DownloadNewsgroupsForOffline(m_window, this); + + if (NS_FAILED(rv)) return AdvanceToNextState(rv); + return rv; +} + +nsresult nsMsgOfflineManager::DownloadMail() { + nsresult rv = NS_OK; + ShowStatus("downloadingMail"); + nsCOMPtr<nsIImapService> imapService = + do_GetService("@mozilla.org/messenger/imapservice;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + return imapService->DownloadAllOffineImapFolders(m_window, this); + // ### we should do get new mail on pop servers, and download imap messages + // for offline use. +} + +NS_IMETHODIMP nsMsgOfflineManager::GoOnline(bool sendUnsentMessages, + bool playbackOfflineImapOperations, + nsIMsgWindow* aMsgWindow) { + m_sendUnsentMessages = sendUnsentMessages; + m_playbackOfflineImapOps = playbackOfflineImapOperations; + m_curOperation = eGoingOnline; + m_curState = eNoState; + SetWindow(aMsgWindow); + SetOnlineState(true); + if (!m_sendUnsentMessages && !playbackOfflineImapOperations) + return NS_OK; + else + AdvanceToNextState(NS_OK); + return NS_OK; +} + +NS_IMETHODIMP nsMsgOfflineManager::SynchronizeForOffline( + bool downloadNews, bool downloadMail, bool sendUnsentMessages, + bool goOfflineWhenDone, nsIMsgWindow* aMsgWindow) { + m_curOperation = eDownloadingForOffline; + m_downloadNews = downloadNews; + m_downloadMail = downloadMail; + m_sendUnsentMessages = sendUnsentMessages; + SetWindow(aMsgWindow); + m_goOfflineWhenDone = goOfflineWhenDone; + m_curState = eNoState; + if (!downloadNews && !downloadMail && !sendUnsentMessages) { + if (goOfflineWhenDone) return SetOnlineState(false); + } else + return AdvanceToNextState(NS_OK); + return NS_OK; +} + +nsresult nsMsgOfflineManager::SetOnlineState(bool online) { + nsCOMPtr<nsIIOService> netService = mozilla::components::IO::Service(); + NS_ENSURE_TRUE(netService, NS_ERROR_UNEXPECTED); + return netService->SetOffline(!online); +} + +// nsIUrlListener methods + +NS_IMETHODIMP +nsMsgOfflineManager::OnStartRunningUrl(nsIURI* aUrl) { return NS_OK; } + +NS_IMETHODIMP +nsMsgOfflineManager::OnStopRunningUrl(nsIURI* aUrl, nsresult aExitCode) { + mOfflineImapSync = nullptr; + + AdvanceToNextState(aExitCode); + return NS_OK; +} + +NS_IMETHODIMP nsMsgOfflineManager::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* someData) { + return NS_OK; +} + +// nsIMsgSendLaterListener implementation +NS_IMETHODIMP +nsMsgOfflineManager::OnStartSending(uint32_t aTotalMessageCount) { + return NS_OK; +} + +NS_IMETHODIMP +nsMsgOfflineManager::OnMessageStartSending(uint32_t aCurrentMessage, + uint32_t aTotalMessageCount, + nsIMsgDBHdr* aMessageHeader, + nsIMsgIdentity* aIdentity) { + return NS_OK; +} + +NS_IMETHODIMP +nsMsgOfflineManager::OnMessageSendProgress(uint32_t aCurrentMessage, + uint32_t aTotalMessageCount, + uint32_t aMessageSendPercent, + uint32_t aMessageCopyPercent) { + if (m_statusFeedback && aTotalMessageCount) + return m_statusFeedback->ShowProgress((100 * aCurrentMessage) / + aTotalMessageCount); + + return NS_OK; +} + +NS_IMETHODIMP +nsMsgOfflineManager::OnMessageSendError(uint32_t aCurrentMessage, + nsIMsgDBHdr* aMessageHeader, + nsresult aStatus, + const char16_t* aMsg) { + return NS_OK; +} + +NS_IMETHODIMP +nsMsgOfflineManager::OnStopSending(nsresult aStatus, const char16_t* aMsg, + uint32_t aTotalTried, uint32_t aSuccessful) { +#ifdef NS_DEBUG + if (NS_SUCCEEDED(aStatus)) + printf( + "SendLaterListener::OnStopSending: Tried to send %d messages. %d " + "successful.\n", + aTotalTried, aSuccessful); +#endif + return AdvanceToNextState(aStatus); +} |