summaryrefslogtreecommitdiffstats
path: root/mailnews/base/src/nsMsgWindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/base/src/nsMsgWindow.cpp')
-rw-r--r--mailnews/base/src/nsMsgWindow.cpp534
1 files changed, 534 insertions, 0 deletions
diff --git a/mailnews/base/src/nsMsgWindow.cpp b/mailnews/base/src/nsMsgWindow.cpp
new file mode 100644
index 000000000..b94cbc0e1
--- /dev/null
+++ b/mailnews/base/src/nsMsgWindow.cpp
@@ -0,0 +1,534 @@
+/* -*- 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 "nsMsgWindow.h"
+#include "nsIURILoader.h"
+#include "nsCURILoader.h"
+#include "nsIDocShell.h"
+#include "nsIDocShellTreeItem.h"
+#include "nsIDOMElement.h"
+#include "mozIDOMWindow.h"
+#include "nsTransactionManagerCID.h"
+#include "nsIComponentManager.h"
+#include "nsILoadGroup.h"
+#include "nsIMsgMailNewsUrl.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIWebProgress.h"
+#include "nsIWebProgressListener.h"
+#include "nsPIDOMWindow.h"
+#include "nsIPrompt.h"
+#include "nsICharsetConverterManager.h"
+#include "nsIChannel.h"
+#include "nsIRequestObserver.h"
+#include "netCore.h"
+#include "prmem.h"
+#include "plbase64.h"
+#include "nsMsgI18N.h"
+#include "nsIWebNavigation.h"
+#include "nsMsgContentPolicy.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIAuthPrompt.h"
+#include "nsMsgUtils.h"
+
+// used to dispatch urls to default protocol handlers
+#include "nsCExternalHandlerService.h"
+#include "nsIExternalProtocolService.h"
+
+static NS_DEFINE_CID(kTransactionManagerCID, NS_TRANSACTIONMANAGER_CID);
+
+NS_IMPL_ISUPPORTS(nsMsgWindow,
+ nsIMsgWindow,
+ nsIURIContentListener,
+ nsISupportsWeakReference,
+ nsIMsgWindowTest)
+
+nsMsgWindow::nsMsgWindow()
+{
+ mCharsetOverride = false;
+ m_stopped = false;
+}
+
+nsMsgWindow::~nsMsgWindow()
+{
+ CloseWindow();
+}
+
+nsresult nsMsgWindow::Init()
+{
+ // register ourselves as a content listener with the uri dispatcher service
+ nsresult rv;
+ nsCOMPtr<nsIURILoader> dispatcher =
+ do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = dispatcher->RegisterContentListener(this);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // create Undo/Redo Transaction Manager
+ mTransactionManager = do_CreateInstance(kTransactionManagerCID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return mTransactionManager->SetMaxTransactionCount(-1);
+}
+
+NS_IMETHODIMP nsMsgWindow::GetMessageWindowDocShell(nsIDocShell ** aDocShell)
+{
+ *aDocShell = nullptr;
+ nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mMessageWindowDocShellWeak));
+ if (!docShell)
+ {
+ // if we don't have a docshell, then we need to look up the message pane docshell
+ nsCOMPtr<nsIDocShell> rootShell(do_QueryReferent(mRootDocShellWeak));
+ if (rootShell)
+ {
+ nsCOMPtr<nsIDocShellTreeItem> msgDocShellItem;
+ if(rootShell)
+ rootShell->FindChildWithName(NS_LITERAL_STRING("messagepane"),
+ true, false, nullptr, nullptr,
+ getter_AddRefs(msgDocShellItem));
+ NS_ENSURE_TRUE(msgDocShellItem, NS_ERROR_FAILURE);
+ docShell = do_QueryInterface(msgDocShellItem);
+ // we don't own mMessageWindowDocShell so don't try to keep a reference to it!
+ mMessageWindowDocShellWeak = do_GetWeakReference(docShell);
+ }
+ }
+ docShell.swap(*aDocShell);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::CloseWindow()
+{
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIURILoader> dispatcher = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
+ if (dispatcher) // on shut down it's possible dispatcher will be null.
+ rv = dispatcher->UnRegisterContentListener(this);
+
+ mMsgWindowCommands = nullptr;
+ mStatusFeedback = nullptr;
+
+ StopUrls();
+
+ nsCOMPtr<nsIDocShell> messagePaneDocShell(do_QueryReferent(mMessageWindowDocShellWeak));
+ if (messagePaneDocShell)
+ {
+ nsCOMPtr<nsIURIContentListener> listener(do_GetInterface(messagePaneDocShell));
+ if (listener)
+ listener->SetParentContentListener(nullptr);
+ SetRootDocShell(nullptr);
+ mMessageWindowDocShellWeak = nullptr;
+ }
+
+ // in case nsMsgWindow leaks, make sure other stuff doesn't leak.
+ mTransactionManager = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetStatusFeedback(nsIMsgStatusFeedback **aStatusFeedback)
+{
+ NS_ENSURE_ARG_POINTER(aStatusFeedback);
+ NS_IF_ADDREF(*aStatusFeedback = mStatusFeedback);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetStatusFeedback(nsIMsgStatusFeedback * aStatusFeedback)
+{
+ mStatusFeedback = aStatusFeedback;
+ nsCOMPtr<nsIDocShell> messageWindowDocShell;
+ GetMessageWindowDocShell(getter_AddRefs(messageWindowDocShell));
+
+ // register our status feedback object as a web progress listener
+ nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(messageWindowDocShell));
+ if (webProgress && mStatusFeedback && messageWindowDocShell)
+ {
+ nsCOMPtr<nsIWebProgressListener> webProgressListener = do_QueryInterface(mStatusFeedback);
+ webProgress->AddProgressListener(webProgressListener, nsIWebProgress::NOTIFY_ALL);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetWindowCommands(nsIMsgWindowCommands * aMsgWindowCommands)
+{
+ mMsgWindowCommands = aMsgWindowCommands;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetWindowCommands(nsIMsgWindowCommands **aMsgWindowCommands)
+{
+ NS_ENSURE_ARG_POINTER(aMsgWindowCommands);
+ NS_IF_ADDREF(*aMsgWindowCommands = mMsgWindowCommands);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetMsgHeaderSink(nsIMsgHeaderSink * *aMsgHdrSink)
+{
+ NS_ENSURE_ARG_POINTER(aMsgHdrSink);
+ NS_IF_ADDREF(*aMsgHdrSink = mMsgHeaderSink);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetMsgHeaderSink(nsIMsgHeaderSink * aMsgHdrSink)
+{
+ mMsgHeaderSink = aMsgHdrSink;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetTransactionManager(nsITransactionManager * *aTransactionManager)
+{
+ NS_ENSURE_ARG_POINTER(aTransactionManager);
+ NS_IF_ADDREF(*aTransactionManager = mTransactionManager);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetTransactionManager(nsITransactionManager * aTransactionManager)
+{
+ mTransactionManager = aTransactionManager;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetOpenFolder(nsIMsgFolder * *aOpenFolder)
+{
+ NS_ENSURE_ARG_POINTER(aOpenFolder);
+ NS_IF_ADDREF(*aOpenFolder = mOpenFolder);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetOpenFolder(nsIMsgFolder * aOpenFolder)
+{
+ mOpenFolder = aOpenFolder;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetRootDocShell(nsIDocShell * *aDocShell)
+{
+ if (mRootDocShellWeak)
+ CallQueryReferent(mRootDocShellWeak.get(), aDocShell);
+ else
+ *aDocShell = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetAuthPrompt(nsIAuthPrompt * *aAuthPrompt)
+{
+ NS_ENSURE_ARG_POINTER(aAuthPrompt);
+
+ // testing only
+ if (mAuthPrompt)
+ {
+ NS_ADDREF(*aAuthPrompt = mAuthPrompt);
+ return NS_OK;
+ }
+
+ if (!mRootDocShellWeak)
+ return NS_ERROR_FAILURE;
+
+ nsresult rv;
+ nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mRootDocShellWeak.get(), &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIAuthPrompt> prompt = do_GetInterface(docShell, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ prompt.swap(*aAuthPrompt);
+
+ return rv;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetAuthPrompt(nsIAuthPrompt* aAuthPrompt)
+{
+ mAuthPrompt = aAuthPrompt;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetRootDocShell(nsIDocShell * aDocShell)
+{
+ nsresult rv;
+ nsCOMPtr<nsIWebProgressListener> contentPolicyListener =
+ do_GetService(NS_MSGCONTENTPOLICY_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // remove the content policy webProgressListener from the root doc shell
+ // we're currently holding, so we don't keep listening for loads that
+ // we don't care about
+ if (mRootDocShellWeak) {
+ nsCOMPtr<nsIWebProgress> oldWebProgress =
+ do_QueryReferent(mRootDocShellWeak, &rv);
+ if (NS_SUCCEEDED(rv)) {
+ rv = oldWebProgress->RemoveProgressListener(contentPolicyListener);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "failed to remove old progress listener");
+ }
+ }
+
+ // Query for the doc shell and release it
+ mRootDocShellWeak = nullptr;
+ if (aDocShell)
+ {
+ mRootDocShellWeak = do_GetWeakReference(aDocShell);
+
+ nsCOMPtr<nsIDocShell> messagePaneDocShell;
+ GetMessageWindowDocShell(getter_AddRefs(messagePaneDocShell));
+ nsCOMPtr<nsIURIContentListener> listener(do_GetInterface(messagePaneDocShell));
+ if (listener)
+ listener->SetParentContentListener(this);
+
+ // set the contentPolicy webProgressListener on the root docshell for this
+ // window so that it can allow JavaScript for non-message content
+ nsCOMPtr<nsIWebProgress> docShellProgress =
+ do_QueryInterface(aDocShell, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = docShellProgress->AddProgressListener(contentPolicyListener,
+ nsIWebProgress::NOTIFY_LOCATION);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetMailCharacterSet(nsACString& aMailCharacterSet)
+{
+ aMailCharacterSet = mMailCharacterSet;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetMailCharacterSet(const nsACString& aMailCharacterSet)
+{
+ mMailCharacterSet.Assign(aMailCharacterSet);
+
+ // Convert to a canonical charset name instead of using the charset name from the message header as is.
+ // This is needed for charset menu item to have a check mark correctly.
+ nsresult rv;
+ nsCOMPtr <nsICharsetConverterManager> ccm =
+ do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return ccm->GetCharsetAlias(PromiseFlatCString(aMailCharacterSet).get(),
+ mMailCharacterSet);
+}
+
+NS_IMETHODIMP nsMsgWindow::GetCharsetOverride(bool *aCharsetOverride)
+{
+ NS_ENSURE_ARG_POINTER(aCharsetOverride);
+ *aCharsetOverride = mCharsetOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetCharsetOverride(bool aCharsetOverride)
+{
+ mCharsetOverride = aCharsetOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetDomWindow(mozIDOMWindowProxy **aWindow)
+{
+ NS_ENSURE_ARG_POINTER(aWindow);
+ if (mDomWindow)
+ CallQueryReferent(mDomWindow.get(), aWindow);
+ else
+ *aWindow = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetDomWindow(mozIDOMWindowProxy * aWindow)
+{
+ NS_ENSURE_ARG_POINTER(aWindow);
+ mDomWindow = do_GetWeakReference(aWindow);
+
+ nsCOMPtr<nsPIDOMWindowOuter> win = nsPIDOMWindowOuter::From(aWindow);
+ nsIDocShell *docShell = nullptr;
+ if (win)
+ docShell = win->GetDocShell();
+
+ nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
+
+ if(docShellAsItem)
+ {
+ nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
+ docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
+
+ nsCOMPtr<nsIDocShell> rootAsShell(do_QueryInterface(rootAsItem));
+ SetRootDocShell(rootAsShell);
+
+ // force ourselves to figure out the message pane
+ nsCOMPtr<nsIDocShell> messageWindowDocShell;
+ GetMessageWindowDocShell(getter_AddRefs(messageWindowDocShell));
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetNotificationCallbacks(nsIInterfaceRequestor * aNotificationCallbacks)
+{
+ mNotificationCallbacks = aNotificationCallbacks;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetNotificationCallbacks(nsIInterfaceRequestor **aNotificationCallbacks)
+{
+ NS_ENSURE_ARG_POINTER(aNotificationCallbacks);
+ NS_IF_ADDREF(*aNotificationCallbacks = mNotificationCallbacks);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::StopUrls()
+{
+ m_stopped = true;
+ nsCOMPtr<nsIWebNavigation> webnav(do_QueryReferent(mRootDocShellWeak));
+ return webnav ? webnav->Stop(nsIWebNavigation::STOP_NETWORK) : NS_ERROR_FAILURE;
+}
+
+// nsIURIContentListener support
+NS_IMETHODIMP nsMsgWindow::OnStartURIOpen(nsIURI* aURI, bool* aAbortOpen)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::DoContent(const nsACString& aContentType, bool aIsContentPreferred,
+ nsIRequest *request, nsIStreamListener **aContentHandler, bool *aAbortProcess)
+{
+ if (!aContentType.IsEmpty())
+ {
+ // forward the DoContent call to our docshell
+ nsCOMPtr<nsIDocShell> messageWindowDocShell;
+ GetMessageWindowDocShell(getter_AddRefs(messageWindowDocShell));
+ nsCOMPtr<nsIURIContentListener> ctnListener = do_QueryInterface(messageWindowDocShell);
+ if (ctnListener)
+ {
+ nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request);
+ if (!aChannel) return NS_ERROR_FAILURE;
+
+ // get the url for the channel...let's hope it is a mailnews url so we can set our msg hdr sink on it..
+ // right now, this is the only way I can think of to force the msg hdr sink into the mime converter so it can
+ // get too it later...
+ nsCOMPtr<nsIURI> uri;
+ aChannel->GetURI(getter_AddRefs(uri));
+ if (uri)
+ {
+ nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl(do_QueryInterface(uri));
+ if (mailnewsUrl)
+ mailnewsUrl->SetMsgWindow(this);
+ }
+ return ctnListener->DoContent(aContentType, aIsContentPreferred, request, aContentHandler, aAbortProcess);
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgWindow::IsPreferred(const char * aContentType,
+ char ** aDesiredContentType,
+ bool * aCanHandleContent)
+{
+ *aCanHandleContent = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::CanHandleContent(const char * aContentType,
+ bool aIsContentPreferred,
+ char ** aDesiredContentType,
+ bool * aCanHandleContent)
+
+{
+ // the mail window knows nothing about the default content types
+ // its docshell can handle...ask the content area if it can handle
+ // the content type...
+
+ nsCOMPtr<nsIDocShell> messageWindowDocShell;
+ GetMessageWindowDocShell(getter_AddRefs(messageWindowDocShell));
+ nsCOMPtr<nsIURIContentListener> ctnListener (do_GetInterface(messageWindowDocShell));
+ if (ctnListener)
+ return ctnListener->CanHandleContent(aContentType, aIsContentPreferred,
+ aDesiredContentType, aCanHandleContent);
+ else
+ *aCanHandleContent = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetParentContentListener(nsIURIContentListener** aParent)
+{
+ NS_ENSURE_ARG_POINTER(aParent);
+ *aParent = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetParentContentListener(nsIURIContentListener* aParent)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetLoadCookie(nsISupports ** aLoadCookie)
+{
+ NS_ENSURE_ARG_POINTER(aLoadCookie);
+ *aLoadCookie = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetLoadCookie(nsISupports * aLoadCookie)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgWindow::GetPromptDialog(nsIPrompt **aPrompt)
+{
+ NS_ENSURE_ARG_POINTER(aPrompt);
+
+ // testing only
+ if (mPromptDialog)
+ {
+ NS_ADDREF(*aPrompt = mPromptDialog);
+ return NS_OK;
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsIDocShell> rootShell(do_QueryReferent(mRootDocShellWeak, &rv));
+ if (rootShell)
+ {
+ nsCOMPtr<nsIPrompt> dialog;
+ dialog = do_GetInterface(rootShell, &rv);
+ dialog.swap(*aPrompt);
+ }
+ return rv;
+}
+
+NS_IMETHODIMP nsMsgWindow::SetPromptDialog(nsIPrompt* aPromptDialog)
+{
+ mPromptDialog = aPromptDialog;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgWindow::DisplayHTMLInMessagePane(const nsAString& title, const nsAString& body, bool clearMsgHdr)
+{
+ if (clearMsgHdr && mMsgWindowCommands)
+ mMsgWindowCommands->ClearMsgPane();
+
+ nsString htmlStr;
+ htmlStr.Append(NS_LITERAL_STRING("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"></head><body>"));
+ htmlStr.Append(body);
+ htmlStr.Append(NS_LITERAL_STRING("</body></html>"));
+
+ char *encodedHtml = PL_Base64Encode(NS_ConvertUTF16toUTF8(htmlStr).get(), 0, nullptr);
+ if (!encodedHtml)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsCString dataSpec;
+ dataSpec = "data:text/html;base64,";
+ dataSpec += encodedHtml;
+
+ PR_FREEIF(encodedHtml);
+
+ nsCOMPtr <nsIDocShell> docShell;
+ GetMessageWindowDocShell(getter_AddRefs(docShell));
+ NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
+ NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
+
+ return webNav->LoadURI(NS_ConvertASCIItoUTF16(dataSpec).get(),
+ nsIWebNavigation::LOAD_FLAGS_NONE,
+ nullptr, nullptr, nullptr);
+}
+
+NS_IMPL_GETSET(nsMsgWindow, Stopped, bool, m_stopped)