/* -*- 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 "nsMsgProgress.h" #include "mozIDOMWindow.h" #include "mozilla/Components.h" #include "mozilla/dom/BrowsingContext.h" #include "nsArray.h" #include "nsComponentManagerUtils.h" #include "nsError.h" #include "nsIMsgComposeProgressParams.h" #include "nsIMutableArray.h" #include "nsIStringBundle.h" #include "nsISupportsPrimitives.h" #include "nsIWindowWatcher.h" #include "nsMsgUtils.h" #include "nsPIDOMWindow.h" #include "nsXPCOM.h" NS_IMPL_ISUPPORTS(nsMsgProgress, nsIMsgStatusFeedback, nsIMsgProgress, nsIWebProgressListener, nsIProgressEventSink, nsISupportsWeakReference) nsMsgProgress::nsMsgProgress() { m_closeProgress = false; m_processCanceled = false; m_pendingStateFlags = -1; m_pendingStateValue = NS_OK; } nsMsgProgress::~nsMsgProgress() { (void)ReleaseListeners(); } NS_IMETHODIMP nsMsgProgress::OpenProgressDialog( mozIDOMWindowProxy* parentDOMWindow, const char* dialogURL, nsIMsgComposeProgressParams* parameters) { NS_ENSURE_ARG_POINTER(dialogURL); // Set up window.arguments... nsCOMPtr array = nsArray::Create(); array->AppendElement(static_cast(this)); array->AppendElement(parameters); // Open the dialog. nsCOMPtr wwatch = mozilla::components::WindowWatcher::Service(); nsCOMPtr newWindow; return wwatch->OpenWindow(parentDOMWindow, nsDependentCString(dialogURL), "_blank"_ns, "chrome,dependent,centerscreen"_ns, array, getter_AddRefs(newWindow)); } NS_IMETHODIMP nsMsgProgress::CloseProgressDialog(bool forceClose) { m_closeProgress = true; return OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP, forceClose ? NS_ERROR_FAILURE : NS_OK); } NS_IMETHODIMP nsMsgProgress::GetProcessCanceledByUser( bool* aProcessCanceledByUser) { NS_ENSURE_ARG_POINTER(aProcessCanceledByUser); *aProcessCanceledByUser = m_processCanceled; return NS_OK; } NS_IMETHODIMP nsMsgProgress::SetProcessCanceledByUser( bool aProcessCanceledByUser) { m_processCanceled = aProcessCanceledByUser; OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP, NS_BINDING_ABORTED); return NS_OK; } NS_IMETHODIMP nsMsgProgress::RegisterListener( nsIWebProgressListener* listener) { if (!listener) // Nothing to do with a null listener! return NS_OK; NS_ENSURE_ARG(this != listener); // Check for self-reference (see bug 271700) nsWeakPtr listenerWeak = do_GetWeakReference(listener); if (!listenerWeak) { return NS_ERROR_INVALID_ARG; } if (mListenerInfoList.Contains(listenerWeak)) { // The listener is already registered! return NS_ERROR_FAILURE; } mListenerInfoList.AppendElement(ListenerInfo(listenerWeak)); if (m_closeProgress || m_processCanceled) listener->OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP, NS_OK); else { listener->OnStatusChange(nullptr, nullptr, NS_OK, m_pendingStatus.get()); if (m_pendingStateFlags != -1) listener->OnStateChange(nullptr, nullptr, m_pendingStateFlags, m_pendingStateValue); } return NS_OK; } NS_IMETHODIMP nsMsgProgress::UnregisterListener( nsIWebProgressListener* listener) { nsWeakPtr listenerWeak = do_GetWeakReference(listener); if (!listenerWeak) { return NS_ERROR_INVALID_ARG; } return mListenerInfoList.RemoveElement(listenerWeak) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP nsMsgProgress::OnStateChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, uint32_t aStateFlags, nsresult aStatus) { m_pendingStateFlags = aStateFlags; m_pendingStateValue = aStatus; nsCOMPtr msgWindow(do_QueryReferent(m_msgWindow)); if (aStateFlags == nsIWebProgressListener::STATE_STOP && msgWindow && NS_FAILED(aStatus)) { msgWindow->SetStatusFeedback(nullptr); } ListenerArray::ForwardIterator iter(mListenerInfoList); while (iter.HasMore()) { ListenerInfo& info = iter.GetNext(); nsCOMPtr listener = do_QueryReferent(info.mWeakListener); if (!listener) { mListenerInfoList.RemoveElement(info); continue; } listener->OnStateChange(aWebProgress, aRequest, aStateFlags, aStatus); } return NS_OK; } NS_IMETHODIMP nsMsgProgress::OnProgressChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, int32_t aCurSelfProgress, int32_t aMaxSelfProgress, int32_t aCurTotalProgress, int32_t aMaxTotalProgress) { ListenerArray::ForwardIterator iter(mListenerInfoList); while (iter.HasMore()) { ListenerInfo& info = iter.GetNext(); nsCOMPtr listener = do_QueryReferent(info.mWeakListener); if (!listener) { mListenerInfoList.RemoveElement(info); continue; } listener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress); } return NS_OK; } NS_IMETHODIMP nsMsgProgress::OnLocationChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, nsIURI* location, uint32_t aFlags) { return NS_OK; } NS_IMETHODIMP nsMsgProgress::OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, nsresult aStatus, const char16_t* aMessage) { if (aMessage && *aMessage) m_pendingStatus = aMessage; ListenerArray::ForwardIterator iter(mListenerInfoList); while (iter.HasMore()) { ListenerInfo& info = iter.GetNext(); nsCOMPtr listener = do_QueryReferent(info.mWeakListener); if (!listener) { mListenerInfoList.RemoveElement(info); continue; } listener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage); } return NS_OK; } NS_IMETHODIMP nsMsgProgress::OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, uint32_t state) { return NS_OK; } NS_IMETHODIMP nsMsgProgress::OnContentBlockingEvent(nsIWebProgress* aWebProgress, nsIRequest* aRequest, uint32_t aEvent) { return NS_OK; } nsresult nsMsgProgress::ReleaseListeners() { mListenerInfoList.Clear(); return NS_OK; } NS_IMETHODIMP nsMsgProgress::ShowStatusString(const nsAString& aStatus) { return OnStatusChange(nullptr, nullptr, NS_OK, PromiseFlatString(aStatus).get()); } NS_IMETHODIMP nsMsgProgress::StartMeteors() { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsMsgProgress::StopMeteors() { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsMsgProgress::ShowProgress(int32_t percent) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsMsgProgress::SetWrappedStatusFeedback( nsIMsgStatusFeedback* aJSStatusFeedback) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsMsgProgress::SetMsgWindow(nsIMsgWindow* aMsgWindow) { m_msgWindow = do_GetWeakReference(aMsgWindow); return NS_OK; } NS_IMETHODIMP nsMsgProgress::GetMsgWindow(nsIMsgWindow** aMsgWindow) { NS_ENSURE_ARG_POINTER(aMsgWindow); if (m_msgWindow) CallQueryReferent(m_msgWindow.get(), aMsgWindow); else *aMsgWindow = nullptr; return NS_OK; } NS_IMETHODIMP nsMsgProgress::OnProgress(nsIRequest* request, int64_t aProgress, int64_t aProgressMax) { // XXX: What should the nsIWebProgress be? // XXX: This truncates 64-bit to 32-bit return OnProgressChange(nullptr, request, int32_t(aProgress), int32_t(aProgressMax), int32_t(aProgress) /* current total progress */, int32_t(aProgressMax) /* max total progress */); } NS_IMETHODIMP nsMsgProgress::OnStatus(nsIRequest* request, nsresult aStatus, const char16_t* aStatusArg) { nsString msg; nsAutoString host; host.Append(aStatusArg); nsresult rv = FormatStatusMessage(aStatus, host, msg); NS_ENSURE_SUCCESS(rv, rv); return ShowStatusString(msg); }