diff options
Diffstat (limited to 'comm/mailnews/base/src/nsMsgMailSession.cpp')
-rw-r--r-- | comm/mailnews/base/src/nsMsgMailSession.cpp | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/comm/mailnews/base/src/nsMsgMailSession.cpp b/comm/mailnews/base/src/nsMsgMailSession.cpp new file mode 100644 index 0000000000..ac34d5d487 --- /dev/null +++ b/comm/mailnews/base/src/nsMsgMailSession.cpp @@ -0,0 +1,671 @@ +/* -*- 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/. */ + +#include "msgCore.h" // for pre-compiled headers +#include "nsMsgMailSession.h" +#include "nsIMsgMessageService.h" +#include "nsMsgUtils.h" +#include "nsIMsgAccountManager.h" +#include "nsIChromeRegistry.h" +#include "nsIDirectoryService.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsPIDOMWindow.h" +#include "nsIDocShell.h" +#include "mozilla/dom/Document.h" +#include "nsIObserverService.h" +#include "nsIAppStartup.h" +#include "nsISupportsPrimitives.h" +#include "nsIAppShellService.h" +#include "nsAppShellCID.h" +#include "nsIWindowMediator.h" +#include "nsIWindowWatcher.h" +#include "nsIMsgMailNewsUrl.h" +#include "prcmon.h" +#include "nsThreadUtils.h" +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsIProperties.h" +#include "mozilla/Services.h" +#include "mozilla/dom/Element.h" +#include "mozilla/Components.h" +#include "nsFocusManager.h" +#include "nsIPromptService.h" +#include "nsEmbedCID.h" + +NS_IMPL_ISUPPORTS(nsMsgMailSession, nsIMsgMailSession, nsIFolderListener) + +nsMsgMailSession::nsMsgMailSession() {} + +nsMsgMailSession::~nsMsgMailSession() { Shutdown(); } + +nsresult nsMsgMailSession::Init() { + // Ensures the shutdown service is initialised + nsresult rv; + nsCOMPtr<nsIMsgShutdownService> shutdownService = + do_GetService("@mozilla.org/messenger/msgshutdownservice;1", &rv); + return rv; +} + +nsresult nsMsgMailSession::Shutdown() { return NS_OK; } + +NS_IMETHODIMP nsMsgMailSession::AddFolderListener(nsIFolderListener* aListener, + uint32_t aNotifyFlags) { + NS_ENSURE_ARG_POINTER(aListener); + + // we don't care about the notification flags for equivalence purposes + size_t index = mListeners.IndexOf(aListener); + NS_ASSERTION(index == size_t(-1), "tried to add duplicate listener"); + if (index == size_t(-1)) { + folderListener newListener(aListener, aNotifyFlags); + mListeners.AppendElement(newListener); + } + + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::RemoveFolderListener( + nsIFolderListener* aListener) { + NS_ENSURE_ARG_POINTER(aListener); + + mListeners.RemoveElement(aListener); + return NS_OK; +} + +#define NOTIFY_FOLDER_LISTENERS(propertyflag_, propertyfunc_, params_) \ + PR_BEGIN_MACRO \ + nsTObserverArray<folderListener>::ForwardIterator iter(mListeners); \ + while (iter.HasMore()) { \ + const folderListener& fL = iter.GetNext(); \ + if (fL.mNotifyFlags & nsIFolderListener::propertyflag_) \ + fL.mListener->propertyfunc_ params_; \ + } \ + PR_END_MACRO + +NS_IMETHODIMP +nsMsgMailSession::OnFolderPropertyChanged(nsIMsgFolder* aItem, + const nsACString& aProperty, + const nsACString& aOldValue, + const nsACString& aNewValue) { + NOTIFY_FOLDER_LISTENERS(propertyChanged, OnFolderPropertyChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::OnFolderUnicharPropertyChanged(nsIMsgFolder* aItem, + const nsACString& aProperty, + const nsAString& aOldValue, + const nsAString& aNewValue) { + NOTIFY_FOLDER_LISTENERS(unicharPropertyChanged, + OnFolderUnicharPropertyChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::OnFolderIntPropertyChanged(nsIMsgFolder* aItem, + const nsACString& aProperty, + int64_t aOldValue, + int64_t aNewValue) { + NOTIFY_FOLDER_LISTENERS(intPropertyChanged, OnFolderIntPropertyChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::OnFolderBoolPropertyChanged(nsIMsgFolder* aItem, + const nsACString& aProperty, + bool aOldValue, bool aNewValue) { + NOTIFY_FOLDER_LISTENERS(boolPropertyChanged, OnFolderBoolPropertyChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::OnFolderPropertyFlagChanged(nsIMsgDBHdr* aItem, + const nsACString& aProperty, + uint32_t aOldValue, + uint32_t aNewValue) { + NOTIFY_FOLDER_LISTENERS(propertyFlagChanged, OnFolderPropertyFlagChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::OnFolderAdded(nsIMsgFolder* parent, + nsIMsgFolder* child) { + NOTIFY_FOLDER_LISTENERS(added, OnFolderAdded, (parent, child)); + return NS_OK; +} +NS_IMETHODIMP nsMsgMailSession::OnMessageAdded(nsIMsgFolder* parent, + nsIMsgDBHdr* msg) { + NOTIFY_FOLDER_LISTENERS(added, OnMessageAdded, (parent, msg)); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::OnFolderRemoved(nsIMsgFolder* parent, + nsIMsgFolder* child) { + NOTIFY_FOLDER_LISTENERS(removed, OnFolderRemoved, (parent, child)); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::OnMessageRemoved(nsIMsgFolder* parent, + nsIMsgDBHdr* msg) { + NOTIFY_FOLDER_LISTENERS(removed, OnMessageRemoved, (parent, msg)); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::OnFolderEvent(nsIMsgFolder* aFolder, + const nsACString& aEvent) { + NOTIFY_FOLDER_LISTENERS(event, OnFolderEvent, (aFolder, aEvent)); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::AddUserFeedbackListener( + nsIMsgUserFeedbackListener* aListener) { + NS_ENSURE_ARG_POINTER(aListener); + + size_t index = mFeedbackListeners.IndexOf(aListener); + NS_ASSERTION(index == size_t(-1), "tried to add duplicate listener"); + if (index == size_t(-1)) mFeedbackListeners.AppendElement(aListener); + + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::RemoveUserFeedbackListener( + nsIMsgUserFeedbackListener* aListener) { + NS_ENSURE_ARG_POINTER(aListener); + + mFeedbackListeners.RemoveElement(aListener); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::AlertUser(const nsAString& aMessage, + nsIMsgMailNewsUrl* aUrl) { + bool listenersNotified = false; + nsTObserverArray<nsCOMPtr<nsIMsgUserFeedbackListener>>::ForwardIterator iter( + mFeedbackListeners); + nsCOMPtr<nsIMsgUserFeedbackListener> listener; + + while (iter.HasMore()) { + bool notified = false; + listener = iter.GetNext(); + listener->OnAlert(aMessage, aUrl, ¬ified); + listenersNotified = listenersNotified || notified; + } + + // If the listeners notified the user, then we don't need to. Also exit if + // aUrl is null because we won't have a nsIMsgWindow in that case. + if (listenersNotified || !aUrl) return NS_OK; + + // If the url hasn't got a message window, then the error was a generated as a + // result of background activity (e.g. autosync, biff, etc), and hence we + // shouldn't prompt either. + nsCOMPtr<nsIMsgWindow> msgWindow; + aUrl->GetMsgWindow(getter_AddRefs(msgWindow)); + + if (!msgWindow) return NS_OK; + + nsCOMPtr<mozIDOMWindowProxy> domWindow; + msgWindow->GetDomWindow(getter_AddRefs(domWindow)); + + nsresult rv; + nsCOMPtr<nsIPromptService> dlgService( + do_GetService(NS_PROMPTSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + dlgService->Alert(domWindow, nullptr, PromiseFlatString(aMessage).get()); + + return NS_OK; +} + +nsresult nsMsgMailSession::GetTopmostMsgWindow(nsIMsgWindow** aMsgWindow) { + NS_ENSURE_ARG_POINTER(aMsgWindow); + + *aMsgWindow = nullptr; + + uint32_t count = mWindows.Count(); + + if (count == 1) { + NS_ADDREF(*aMsgWindow = mWindows[0]); + return (*aMsgWindow) ? NS_OK : NS_ERROR_FAILURE; + } else if (count > 1) { + // If multiple message windows then we have lots more work. + nsresult rv; + + // The msgWindows array does not hold z-order info. Use mediator to get + // the top most window then match that with the msgWindows array. + nsCOMPtr<nsIWindowMediator> windowMediator = + do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsISimpleEnumerator> windowEnum; + + rv = windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnum)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsISupports> windowSupports; + nsCOMPtr<nsPIDOMWindowOuter> topMostWindow; + nsAutoString windowType; + bool more; + + // loop to get the top most with attribute "mail:3pane" or + // "mail:messageWindow" + windowEnum->HasMoreElements(&more); + while (more) { + rv = windowEnum->GetNext(getter_AddRefs(windowSupports)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(windowSupports, NS_ERROR_FAILURE); + + nsCOMPtr<nsPIDOMWindowOuter> window = + do_QueryInterface(windowSupports, &rv); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + mozilla::dom::Document* domDocument = window->GetDoc(); + NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE); + + mozilla::dom::Element* domElement = domDocument->GetDocumentElement(); + NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE); + + domElement->GetAttribute(u"windowtype"_ns, windowType); + if (windowType.EqualsLiteral("mail:3pane") || + windowType.EqualsLiteral("mail:messageWindow")) { + // topMostWindow is the last 3pane/messageWindow found, not necessarily + // the top most. + topMostWindow = window; + RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager(); + nsCOMPtr<mozIDOMWindowProxy> currentWindow = + do_QueryInterface(windowSupports, &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<mozIDOMWindowProxy> activeWindow; + rv = fm->GetActiveWindow(getter_AddRefs(activeWindow)); + NS_ENSURE_SUCCESS(rv, rv); + if (currentWindow == activeWindow) { + // We are sure topMostWindow is really the top most now. + break; + } + } + + windowEnum->HasMoreElements(&more); + } + + // identified the top most window + if (topMostWindow) { + // use this for the match + nsIDocShell* topDocShell = topMostWindow->GetDocShell(); + + // loop for the msgWindow array to find the match + nsCOMPtr<nsIDocShell> docShell; + + while (count) { + nsIMsgWindow* msgWindow = mWindows[--count]; + + rv = msgWindow->GetRootDocShell(getter_AddRefs(docShell)); + NS_ENSURE_SUCCESS(rv, rv); + + if (topDocShell == docShell) { + NS_IF_ADDREF(*aMsgWindow = msgWindow); + break; + } + } + } + } + + return (*aMsgWindow) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsMsgMailSession::AddMsgWindow(nsIMsgWindow* msgWindow) { + NS_ENSURE_ARG_POINTER(msgWindow); + + mWindows.AppendObject(msgWindow); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::RemoveMsgWindow(nsIMsgWindow* msgWindow) { + mWindows.RemoveObject(msgWindow); + // Mac keeps a hidden window open so the app doesn't shut down when + // the last window is closed. So don't shutdown the account manager in that + // case. Similarly, for suite, we don't want to disable mailnews when the + // last mail window is closed. +#if !defined(XP_MACOSX) && !defined(MOZ_SUITE) + if (!mWindows.Count()) { + nsresult rv; + nsCOMPtr<nsIMsgAccountManager> accountManager = + do_GetService("@mozilla.org/messenger/account-manager;1", &rv); + if (NS_FAILED(rv)) return rv; + accountManager->CleanupOnExit(); + } +#endif + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::IsFolderOpenInWindow(nsIMsgFolder* folder, + bool* aResult) { + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = false; + + uint32_t count = mWindows.Count(); + + for (uint32_t i = 0; i < count; i++) { + nsCOMPtr<nsIMsgFolder> openFolder; + mWindows[i]->GetOpenFolder(getter_AddRefs(openFolder)); + if (folder == openFolder.get()) { + *aResult = true; + break; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::ConvertMsgURIToMsgURL(const nsACString& aURI, + nsIMsgWindow* aMsgWindow, + nsACString& aURL) { + // convert the rdf msg uri into a url that represents the message... + nsCOMPtr<nsIMsgMessageService> msgService; + nsresult rv = GetMessageServiceFromURI(aURI, getter_AddRefs(msgService)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_NULL_POINTER); + + nsCOMPtr<nsIURI> tURI; + rv = msgService->GetUrlForUri(aURI, aMsgWindow, getter_AddRefs(tURI)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_NULL_POINTER); + + rv = tURI->GetSpec(aURL); + return rv; +} + +//------------------------------------------------------------------------- +// GetSelectedLocaleDataDir - If a locale is selected, appends the selected +// locale to the defaults data dir and returns +// that new defaults data dir +//------------------------------------------------------------------------- +nsresult nsMsgMailSession::GetSelectedLocaleDataDir(nsIFile* defaultsDir) { + NS_ENSURE_ARG_POINTER(defaultsDir); + + return NS_OK; +} + +//----------------------------------------------------------------------------- +// GetDataFilesDir - Gets the application's default folder and then appends the +// subdirectory named passed in as param dirName. If there is +// a selected locale, will append that to the dir path before +// returning the value +//----------------------------------------------------------------------------- +NS_IMETHODIMP +nsMsgMailSession::GetDataFilesDir(const char* dirName, nsIFile** dataFilesDir) { + NS_ENSURE_ARG_POINTER(dirName); + NS_ENSURE_ARG_POINTER(dataFilesDir); + + nsresult rv; + nsCOMPtr<nsIProperties> directoryService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIFile> defaultsDir; + rv = directoryService->Get(NS_APP_DEFAULTS_50_DIR, NS_GET_IID(nsIFile), + getter_AddRefs(defaultsDir)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = defaultsDir->AppendNative(nsDependentCString(dirName)); + if (NS_SUCCEEDED(rv)) rv = GetSelectedLocaleDataDir(defaultsDir); + + defaultsDir.forget(dataFilesDir); + + return rv; +} + +/********************************************************************************/ + +NS_IMPL_ISUPPORTS(nsMsgShutdownService, nsIMsgShutdownService, nsIUrlListener, + nsIObserver) + +nsMsgShutdownService::nsMsgShutdownService() + : mTaskIndex(0), + mQuitMode(nsIAppStartup::eAttemptQuit), + mProcessedShutdown(false), + mQuitForced(false), + mReadyToQuit(false) { + nsCOMPtr<nsIObserverService> observerService = + mozilla::services::GetObserverService(); + if (observerService) { + observerService->AddObserver(this, "quit-application-requested", false); + observerService->AddObserver(this, "quit-application-granted", false); + observerService->AddObserver(this, "quit-application", false); + } +} + +nsMsgShutdownService::~nsMsgShutdownService() { + nsCOMPtr<nsIObserverService> observerService = + mozilla::services::GetObserverService(); + if (observerService) { + observerService->RemoveObserver(this, "quit-application-requested"); + observerService->RemoveObserver(this, "quit-application-granted"); + observerService->RemoveObserver(this, "quit-application"); + } +} + +nsresult nsMsgShutdownService::ProcessNextTask() { + bool shutdownTasksDone = true; + + uint32_t count = mShutdownTasks.Length(); + if (mTaskIndex < count) { + shutdownTasksDone = false; + + nsCOMPtr<nsIMsgShutdownTask> curTask = mShutdownTasks[mTaskIndex]; + nsString taskName; + curTask->GetCurrentTaskName(taskName); + SetStatusText(taskName); + + nsCOMPtr<nsIMsgMailSession> mailSession = + do_GetService("@mozilla.org/messenger/services/session;1"); + NS_ENSURE_TRUE(mailSession, NS_ERROR_FAILURE); + + nsCOMPtr<nsIMsgWindow> topMsgWindow; + mailSession->GetTopmostMsgWindow(getter_AddRefs(topMsgWindow)); + + bool taskIsRunning = true; + nsresult rv = curTask->DoShutdownTask(this, topMsgWindow, &taskIsRunning); + if (NS_FAILED(rv) || !taskIsRunning) { + // We have failed, let's go on to the next task. + mTaskIndex++; + mMsgProgress->OnProgressChange(nullptr, nullptr, 0, 0, + (int32_t)mTaskIndex, count); + ProcessNextTask(); + } + } + + if (shutdownTasksDone) { + if (mMsgProgress) + mMsgProgress->OnStateChange(nullptr, nullptr, + nsIWebProgressListener::STATE_STOP, NS_OK); + AttemptShutdown(); + } + + return NS_OK; +} + +void nsMsgShutdownService::AttemptShutdown() { + if (mQuitForced) { + PR_CEnterMonitor(this); + mReadyToQuit = true; + PR_CNotifyAll(this); + PR_CExitMonitor(this); + } else { + nsCOMPtr<nsIAppStartup> appStartup = + mozilla::components::AppStartup::Service(); + NS_ENSURE_TRUE_VOID(appStartup); + bool userAllowedQuit = true; + NS_ENSURE_SUCCESS_VOID(appStartup->Quit(mQuitMode, 0, &userAllowedQuit)); + } +} + +NS_IMETHODIMP nsMsgShutdownService::SetShutdownListener( + nsIWebProgressListener* inListener) { + NS_ENSURE_TRUE(mMsgProgress, NS_ERROR_FAILURE); + mMsgProgress->RegisterListener(inListener); + return NS_OK; +} + +NS_IMETHODIMP nsMsgShutdownService::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) { + // Due to bug 459376 we don't always get quit-application-requested and + // quit-application-granted. quit-application-requested is preferred, but if + // we don't then we have to hook onto quit-application, but we don't want + // to do the checking twice so we set some flags to prevent that. + if (!strcmp(aTopic, "quit-application-granted")) { + // Quit application has been requested and granted, therefore we will shut + // down. + mProcessedShutdown = true; + return NS_OK; + } + + // If we've already processed a shutdown notification, no need to do it again. + if (!strcmp(aTopic, "quit-application")) { + if (mProcessedShutdown) + return NS_OK; + else + mQuitForced = true; + } + + nsCOMPtr<nsIObserverService> observerService = + mozilla::services::GetObserverService(); + NS_ENSURE_STATE(observerService); + + nsCOMPtr<nsISimpleEnumerator> listenerEnum; + nsresult rv = observerService->EnumerateObservers( + "msg-shutdown", getter_AddRefs(listenerEnum)); + if (NS_SUCCEEDED(rv) && listenerEnum) { + bool hasMore; + listenerEnum->HasMoreElements(&hasMore); + if (!hasMore) return NS_OK; + + while (hasMore) { + nsCOMPtr<nsISupports> curObject; + listenerEnum->GetNext(getter_AddRefs(curObject)); + + nsCOMPtr<nsIMsgShutdownTask> curTask = do_QueryInterface(curObject); + if (curTask) { + bool shouldRunTask; + curTask->GetNeedsToRunTask(&shouldRunTask); + if (shouldRunTask) mShutdownTasks.AppendObject(curTask); + } + + listenerEnum->HasMoreElements(&hasMore); + } + + if (mShutdownTasks.Count() < 1) return NS_ERROR_FAILURE; + + mTaskIndex = 0; + + mMsgProgress = do_CreateInstance("@mozilla.org/messenger/progress;1"); + NS_ENSURE_TRUE(mMsgProgress, NS_ERROR_FAILURE); + + nsCOMPtr<nsIMsgMailSession> mailSession = + do_GetService("@mozilla.org/messenger/services/session;1"); + NS_ENSURE_TRUE(mailSession, NS_ERROR_FAILURE); + + nsCOMPtr<nsIMsgWindow> topMsgWindow; + mailSession->GetTopmostMsgWindow(getter_AddRefs(topMsgWindow)); + + nsCOMPtr<mozIDOMWindowProxy> internalDomWin; + if (topMsgWindow) + topMsgWindow->GetDomWindow(getter_AddRefs(internalDomWin)); + + if (!internalDomWin) { + // First see if there is a window open. + nsCOMPtr<nsIWindowMediator> winMed = + do_GetService(NS_WINDOWMEDIATOR_CONTRACTID); + winMed->GetMostRecentWindow(nullptr, getter_AddRefs(internalDomWin)); + + // If not use the hidden window. + if (!internalDomWin) { + nsCOMPtr<nsIAppShellService> appShell( + do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); + appShell->GetHiddenDOMWindow(getter_AddRefs(internalDomWin)); + NS_ENSURE_TRUE(internalDomWin, + NS_ERROR_FAILURE); // bail if we don't get a window. + } + } + + if (!mQuitForced) { + nsCOMPtr<nsISupportsPRBool> stopShutdown = do_QueryInterface(aSubject); + stopShutdown->SetData(true); + + // If the attempted quit was a restart, be sure to restart the app once + // the tasks have been run. This is usually the case when addons or + // updates are going to be installed. + if (aData && nsDependentString(aData).EqualsLiteral("restart")) + mQuitMode |= nsIAppStartup::eRestart; + } + + mMsgProgress->OpenProgressDialog( + internalDomWin, topMsgWindow, + "chrome://messenger/content/shutdownWindow.xhtml", false, nullptr); + + if (mQuitForced) { + nsCOMPtr<nsIThread> thread(do_GetCurrentThread()); + + mReadyToQuit = false; + while (!mReadyToQuit) { + PR_CEnterMonitor(this); + // Waiting for 50 milliseconds + PR_CWait(this, PR_MicrosecondsToInterval(50000UL)); + PR_CExitMonitor(this); + NS_ProcessPendingEvents(thread); + } + } + } + + return NS_OK; +} + +// nsIUrlListener +NS_IMETHODIMP nsMsgShutdownService::OnStartRunningUrl(nsIURI* url) { + return NS_OK; +} + +NS_IMETHODIMP nsMsgShutdownService::OnStopRunningUrl(nsIURI* url, + nsresult aExitCode) { + mTaskIndex++; + + if (mMsgProgress) { + int32_t numTasks = mShutdownTasks.Count(); + mMsgProgress->OnProgressChange(nullptr, nullptr, 0, 0, (int32_t)mTaskIndex, + numTasks); + } + + ProcessNextTask(); + return NS_OK; +} + +NS_IMETHODIMP nsMsgShutdownService::GetNumTasks(int32_t* inNumTasks) { + *inNumTasks = mShutdownTasks.Count(); + return NS_OK; +} + +NS_IMETHODIMP nsMsgShutdownService::StartShutdownTasks() { + ProcessNextTask(); + return NS_OK; +} + +NS_IMETHODIMP nsMsgShutdownService::CancelShutdownTasks() { + AttemptShutdown(); + return NS_OK; +} + +NS_IMETHODIMP nsMsgShutdownService::SetStatusText( + const nsAString& inStatusString) { + nsString statusString(inStatusString); + if (mMsgProgress) + mMsgProgress->OnStatusChange(nullptr, nullptr, NS_OK, + nsString(statusString).get()); + return NS_OK; +} |