diff options
Diffstat (limited to 'mailnews/base/src/nsMsgMailSession.cpp')
-rw-r--r-- | mailnews/base/src/nsMsgMailSession.cpp | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/mailnews/base/src/nsMsgMailSession.cpp b/mailnews/base/src/nsMsgMailSession.cpp new file mode 100644 index 0000000000..f9e396988c --- /dev/null +++ b/mailnews/base/src/nsMsgMailSession.cpp @@ -0,0 +1,761 @@ +/* -*- 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 "nsMsgBaseCID.h" +#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 "nsIDocument.h" +#include "nsIDOMDocument.h" +#include "nsIDOMElement.h" +#include "nsIObserverService.h" +#include "nsIAppStartup.h" +#include "nsToolkitCompsCID.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" + +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(NS_MSGSHUTDOWNSERVICE_CONTRACTID, &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::OnItemPropertyChanged(nsIMsgFolder *aItem, + nsIAtom *aProperty, + const char* aOldValue, + const char* aNewValue) +{ + NOTIFY_FOLDER_LISTENERS(propertyChanged, OnItemPropertyChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::OnItemUnicharPropertyChanged(nsIMsgFolder *aItem, + nsIAtom *aProperty, + const char16_t* aOldValue, + const char16_t* aNewValue) +{ + NOTIFY_FOLDER_LISTENERS(unicharPropertyChanged, OnItemUnicharPropertyChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::OnItemIntPropertyChanged(nsIMsgFolder *aItem, + nsIAtom *aProperty, + int64_t aOldValue, + int64_t aNewValue) +{ + NOTIFY_FOLDER_LISTENERS(intPropertyChanged, OnItemIntPropertyChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::OnItemBoolPropertyChanged(nsIMsgFolder *aItem, + nsIAtom *aProperty, + bool aOldValue, + bool aNewValue) +{ + NOTIFY_FOLDER_LISTENERS(boolPropertyChanged, OnItemBoolPropertyChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgMailSession::OnItemPropertyFlagChanged(nsIMsgDBHdr *aItem, + nsIAtom *aProperty, + uint32_t aOldValue, + uint32_t aNewValue) +{ + NOTIFY_FOLDER_LISTENERS(propertyFlagChanged, OnItemPropertyFlagChanged, + (aItem, aProperty, aOldValue, aNewValue)); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::OnItemAdded(nsIMsgFolder *aParentItem, + nsISupports *aItem) +{ + NOTIFY_FOLDER_LISTENERS(added, OnItemAdded, (aParentItem, aItem)); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::OnItemRemoved(nsIMsgFolder *aParentItem, + nsISupports *aItem) +{ + NOTIFY_FOLDER_LISTENERS(removed, OnItemRemoved, (aParentItem, aItem)); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMailSession::OnItemEvent(nsIMsgFolder *aFolder, + nsIAtom *aEvent) +{ + NOTIFY_FOLDER_LISTENERS(event, OnItemEvent, (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<nsIPrompt> dialog; + msgWindow->GetPromptDialog(getter_AddRefs(dialog)); + + if (!dialog) // if we didn't get one, use the default.... + { + nsresult rv; + nsCOMPtr<nsIWindowWatcher> wwatch = + do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + wwatch->GetNewPrompter(0, getter_AddRefs(dialog)); + } + + if (dialog) + return dialog->Alert(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; + +#if defined (XP_UNIX) + // The window managers under Unix/X11 do not support ZOrder information, + // so we have to use the normal enumeration call here. + rv = windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnum)); +#else + rv = windowMediator->GetZOrderDOMWindowEnumerator(nullptr, true, + getter_AddRefs(windowEnum)); +#endif + + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsISupports> windowSupports; + nsCOMPtr<nsPIDOMWindowOuter> topMostWindow; + nsCOMPtr<nsIDOMDocument> domDocument; + nsCOMPtr<nsIDOMElement> domElement; + nsAutoString windowType; + bool more; + + // loop to get the top most with attibute "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); + + topMostWindow = do_QueryInterface(windowSupports, &rv); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(topMostWindow, NS_ERROR_FAILURE); + + domDocument = do_QueryInterface(topMostWindow->GetDoc()); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE); + + rv = domDocument->GetDocumentElement(getter_AddRefs(domElement)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE); + + rv = domElement->GetAttribute(NS_LITERAL_STRING("windowtype"), windowType); + NS_ENSURE_SUCCESS(rv, rv); + + if (windowType.EqualsLiteral("mail:3pane") || + windowType.EqualsLiteral("mail:messageWindow")) + break; + + windowEnum->HasMoreElements(&more); + } + + // identified the top most window + if (more) + { + // 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(NS_MSGACCOUNTMANAGER_CONTRACTID, &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 char *aURI, nsIMsgWindow *aMsgWindow, char **aURL) +{ + NS_ENSURE_ARG_POINTER(aURI); + NS_ENSURE_ARG_POINTER(aURL); + + // convert the rdf msg uri into a url that represents the message... + nsCOMPtr <nsIMsgMessageService> msgService; + nsresult rv = GetMessageServiceFromURI(nsDependentCString(aURI), getter_AddRefs(msgService)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_NULL_POINTER); + + nsCOMPtr<nsIURI> tURI; + rv = msgService->GetUrlForUri(aURI, getter_AddRefs(tURI), aMsgWindow); + NS_ENSURE_SUCCESS(rv, NS_ERROR_NULL_POINTER); + + nsAutoCString urlString; + if (NS_SUCCEEDED(tURI->GetSpec(urlString))) + { + *aURL = ToNewCString(urlString); + NS_ENSURE_ARG_POINTER(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); + + bool baseDirExists = false; + nsresult rv = defaultsDir->Exists(&baseDirExists); + NS_ENSURE_SUCCESS(rv, rv); + + if (baseDirExists) { + nsCOMPtr<nsIXULChromeRegistry> packageRegistry = + mozilla::services::GetXULChromeRegistryService(); + if (packageRegistry) { + nsAutoCString localeName; + rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global-region"), false, localeName); + + if (NS_SUCCEEDED(rv) && !localeName.IsEmpty()) { + bool localeDirExists = false; + nsCOMPtr<nsIFile> localeDataDir; + + rv = defaultsDir->Clone(getter_AddRefs(localeDataDir)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = localeDataDir->AppendNative(localeName); + NS_ENSURE_SUCCESS(rv, rv); + + rv = localeDataDir->Exists(&localeDirExists); + NS_ENSURE_SUCCESS(rv, rv); + + if (localeDirExists) { + // use locale provider instead + rv = defaultsDir->AppendNative(localeName); + NS_ENSURE_SUCCESS(rv, rv); + } + } + } + } + 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); + + NS_IF_ADDREF(*dataFilesDir = defaultsDir); + + return rv; +} + +/********************************************************************************/ + +NS_IMPL_ISUPPORTS(nsMsgShutdownService, nsIMsgShutdownService, nsIUrlListener, nsIObserver) + +nsMsgShutdownService::nsMsgShutdownService() +: 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(NS_MSGMAILSESSION_CONTRACTID); + 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 = + do_GetService(NS_APPSTARTUP_CONTRACTID); + NS_ENSURE_TRUE_VOID(appStartup); + NS_ENSURE_SUCCESS_VOID(appStartup->Quit(mQuitMode)); + } +} + +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(NS_MSGPROGRESS_CONTRACTID); + NS_ENSURE_TRUE(mMsgProgress, NS_ERROR_FAILURE); + + nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID); + 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.xul", + 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; +} |