summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/base/src/nsMsgMailSession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/base/src/nsMsgMailSession.cpp')
-rw-r--r--comm/mailnews/base/src/nsMsgMailSession.cpp671
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, &notified);
+ 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;
+}