summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/base/src/nsMsgMailNewsUrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/base/src/nsMsgMailNewsUrl.cpp')
-rw-r--r--comm/mailnews/base/src/nsMsgMailNewsUrl.cpp1070
1 files changed, 1070 insertions, 0 deletions
diff --git a/comm/mailnews/base/src/nsMsgMailNewsUrl.cpp b/comm/mailnews/base/src/nsMsgMailNewsUrl.cpp
new file mode 100644
index 0000000000..3796aeaef2
--- /dev/null
+++ b/comm/mailnews/base/src/nsMsgMailNewsUrl.cpp
@@ -0,0 +1,1070 @@
+/* -*- 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"
+#include "nsMsgMailNewsUrl.h"
+#include "nsIMsgAccountManager.h"
+#include "nsString.h"
+#include "nsILoadGroup.h"
+#include "nsIDocShell.h"
+#include "nsIWebProgress.h"
+#include "nsIWebProgressListener.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIIOService.h"
+#include "nsNetCID.h"
+#include "nsIStreamListener.h"
+#include "nsIOutputStream.h"
+#include "nsIInputStream.h"
+#include "nsNetUtil.h"
+#include "nsIFile.h"
+#include "prmem.h"
+#include <time.h>
+#include "nsMsgUtils.h"
+#include "mozilla/Components.h"
+#include "nsProxyRelease.h"
+#include "mozilla/Encoding.h"
+#include "nsDocShellLoadState.h"
+#include "nsContentUtils.h"
+#include "nsIObjectInputStream.h"
+#include "nsIObjectOutputStream.h"
+#include "nsIChannel.h"
+
+nsMsgMailNewsUrl::nsMsgMailNewsUrl() {
+ // nsIURI specific state
+ m_runningUrl = false;
+ m_updatingFolder = false;
+ m_msgIsInLocalCache = false;
+ m_suppressErrorMsgs = false;
+ m_hasNormalizedOrigin = false; // SetSpecInternal() will set this correctly.
+ mMaxProgress = -1;
+}
+
+#define NOTIFY_URL_LISTENERS(propertyfunc_, params_) \
+ PR_BEGIN_MACRO \
+ nsTObserverArray<nsCOMPtr<nsIUrlListener>>::ForwardIterator iter( \
+ mUrlListeners); \
+ while (iter.HasMore()) { \
+ nsCOMPtr<nsIUrlListener> listener = iter.GetNext(); \
+ listener->propertyfunc_ params_; \
+ } \
+ PR_END_MACRO
+
+nsMsgMailNewsUrl::~nsMsgMailNewsUrl() {
+ // In IMAP this URL is created and destroyed on the imap thread,
+ // so we must ensure that releases of XPCOM objects (which might be
+ // implemented by non-threadsafe JS components) are released on the
+ // main thread.
+ NS_ReleaseOnMainThread("nsMsgMailNewsUrl::m_baseURL", m_baseURL.forget());
+ NS_ReleaseOnMainThread("nsMsgMailNewsUrl::mMimeHeaders",
+ mMimeHeaders.forget());
+ NS_ReleaseOnMainThread("nsMsgMailNewsUrl::m_searchSession",
+ m_searchSession.forget());
+
+ nsTObserverArray<nsCOMPtr<nsIUrlListener>>::ForwardIterator iter(
+ mUrlListeners);
+ while (iter.HasMore()) {
+ nsCOMPtr<nsIUrlListener> listener = iter.GetNext();
+ if (listener)
+ NS_ReleaseOnMainThread("nsMsgMailNewsUrl::mUrlListeners",
+ listener.forget());
+ }
+}
+
+NS_IMPL_ADDREF(nsMsgMailNewsUrl)
+NS_IMPL_RELEASE(nsMsgMailNewsUrl)
+
+// We want part URLs to QI to nsIURIWithSpecialOrigin so we can give
+// them a "normalized" origin. URLs that already have a "normalized"
+// origin should not QI to nsIURIWithSpecialOrigin.
+NS_INTERFACE_MAP_BEGIN(nsMsgMailNewsUrl)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMsgMailNewsUrl)
+ NS_INTERFACE_MAP_ENTRY(nsIMsgMailNewsUrl)
+ NS_INTERFACE_MAP_ENTRY(nsIURL)
+ NS_INTERFACE_MAP_ENTRY(nsIURI)
+ NS_INTERFACE_MAP_ENTRY(nsISerializable)
+ NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
+ NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIURIWithSpecialOrigin,
+ m_hasNormalizedOrigin)
+NS_INTERFACE_MAP_END
+
+//--------------------------
+// Support for serialization
+//--------------------------
+// nsMsgMailNewsUrl is only partly serialized by serializing the "base URL"
+// which is an nsStandardURL, or by only serializing the Spec. This may
+// cause problems in the future. See bug 1512356 and bug 1515337 for details,
+// follow-up in bug 1512698.
+
+NS_IMETHODIMP_(void)
+nsMsgMailNewsUrl::Serialize(mozilla::ipc::URIParams& aParams) {
+ m_baseURL->Serialize(aParams);
+}
+
+//----------------------------
+// Support for nsISerializable
+//----------------------------
+NS_IMETHODIMP nsMsgMailNewsUrl::Read(nsIObjectInputStream* stream) {
+ nsAutoCString urlstr;
+ nsresult rv = NS_ReadOptionalCString(stream, urlstr);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIIOService> ioService = mozilla::components::IO::Service();
+ NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
+ nsCOMPtr<nsIURI> url;
+ rv = ioService->NewURI(urlstr, nullptr, nullptr, getter_AddRefs(url));
+ NS_ENSURE_SUCCESS(rv, rv);
+ m_baseURL = do_QueryInterface(url);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::Write(nsIObjectOutputStream* stream) {
+ nsAutoCString urlstr;
+ nsresult rv = m_baseURL->GetSpec(urlstr);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return NS_WriteOptionalStringZ(stream, urlstr.get());
+}
+
+//-------------------------
+// Support for nsIClassInfo
+//-------------------------
+NS_IMETHODIMP nsMsgMailNewsUrl::GetInterfaces(nsTArray<nsIID>& array) {
+ array.Clear();
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetScriptableHelper(
+ nsIXPCScriptable** _retval) {
+ *_retval = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetContractID(nsACString& aContractID) {
+ aContractID.SetIsVoid(true);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetClassDescription(
+ nsACString& aClassDescription) {
+ aClassDescription.SetIsVoid(true);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetClassID(nsCID** aClassID) {
+ *aClassID = (nsCID*)moz_xmalloc(sizeof(nsCID));
+ return GetClassIDNoAlloc(*aClassID);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetFlags(uint32_t* aFlags) {
+ *aFlags = 0;
+ return NS_OK;
+}
+
+#define NS_MSGMAILNEWSURL_CID \
+ { \
+ 0x3fdae3ab, 0x4ac1, 0x4ad4, { \
+ 0xb2, 0x8a, 0x28, 0xd0, 0xfa, 0x36, 0x39, 0x29 \
+ } \
+ }
+static NS_DEFINE_CID(kNS_MSGMAILNEWSURL_CID, NS_MSGMAILNEWSURL_CID);
+NS_IMETHODIMP nsMsgMailNewsUrl::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
+ *aClassIDNoAlloc = kNS_MSGMAILNEWSURL_CID;
+ return NS_OK;
+}
+
+//------------------------------------
+// Support for nsIURIWithSpecialOrigin
+//------------------------------------
+NS_IMETHODIMP nsMsgMailNewsUrl::GetOrigin(nsIURI** aOrigin) {
+ MOZ_ASSERT(m_hasNormalizedOrigin,
+ "nsMsgMailNewsUrl::GetOrigin() can only be called for URLs with "
+ "normalized spec");
+
+ if (!m_normalizedOrigin) {
+ nsCOMPtr<nsIMsgMessageUrl> msgUrl;
+ QueryInterface(NS_GET_IID(nsIMsgMessageUrl), getter_AddRefs(msgUrl));
+
+ nsAutoCString spec;
+ if (!msgUrl || NS_FAILED(msgUrl->GetNormalizedSpec(spec))) {
+ MOZ_ASSERT(false, "Can't get normalized spec");
+ // just use the normal spec.
+ GetSpec(spec);
+ }
+
+ nsresult rv = NS_NewURI(getter_AddRefs(m_normalizedOrigin), spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ NS_IF_ADDREF(*aOrigin = m_normalizedOrigin);
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Begin nsIMsgMailNewsUrl specific support
+////////////////////////////////////////////////////////////////////////////////////
+
+nsresult nsMsgMailNewsUrl::GetUrlState(bool* aRunningUrl) {
+ if (aRunningUrl) *aRunningUrl = m_runningUrl;
+
+ return NS_OK;
+}
+
+nsresult nsMsgMailNewsUrl::SetUrlState(bool aRunningUrl, nsresult aExitCode) {
+ // if we already knew this running state, return, unless the url was aborted
+ if (m_runningUrl == aRunningUrl && aExitCode != NS_MSG_ERROR_URL_ABORTED) {
+ return NS_OK;
+ }
+ m_runningUrl = aRunningUrl;
+ nsCOMPtr<nsIMsgStatusFeedback> statusFeedback;
+
+ // put this back - we need it for urls that don't run through the doc loader
+ if (NS_SUCCEEDED(GetStatusFeedback(getter_AddRefs(statusFeedback))) &&
+ statusFeedback) {
+ if (m_runningUrl)
+ statusFeedback->StartMeteors();
+ else {
+ statusFeedback->ShowProgress(0);
+ statusFeedback->StopMeteors();
+ }
+ }
+
+ if (m_runningUrl) {
+ NOTIFY_URL_LISTENERS(OnStartRunningUrl, (this));
+ } else {
+ NOTIFY_URL_LISTENERS(OnStopRunningUrl, (this, aExitCode));
+ mUrlListeners.Clear();
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::RegisterListener(nsIUrlListener* aUrlListener) {
+ NS_ENSURE_ARG_POINTER(aUrlListener);
+ mUrlListeners.AppendElement(aUrlListener);
+ return NS_OK;
+}
+
+nsresult nsMsgMailNewsUrl::UnRegisterListener(nsIUrlListener* aUrlListener) {
+ NS_ENSURE_ARG_POINTER(aUrlListener);
+
+ // Due to the way mailnews is structured, some listeners attempt to remove
+ // themselves twice. This may in fact be an error in the coding, however
+ // if they didn't do it as they do currently, then they could fail to remove
+ // their listeners.
+ mUrlListeners.RemoveElement(aUrlListener);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetServer(
+ nsIMsgIncomingServer** aIncomingServer) {
+ // mscott --> we could cache a copy of the server here....but if we did, we
+ // run the risk of leaking the server if any single url gets leaked....of
+ // course that shouldn't happen...but it could. so i'm going to look it up
+ // every time and we can look at caching it later.
+
+ nsresult rv;
+
+ nsAutoCString urlstr;
+ rv = m_baseURL->GetSpec(urlstr);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIURL> url;
+ rv = NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
+ .SetSpec(urlstr)
+ .Finalize(url);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoCString scheme;
+ rv = GetScheme(scheme);
+ if (NS_SUCCEEDED(rv)) {
+ if (scheme.EqualsLiteral("pop")) scheme.AssignLiteral("pop3");
+ // we use "nntp" in the server list so translate it here.
+ if (scheme.EqualsLiteral("news")) scheme.AssignLiteral("nntp");
+ rv = NS_MutateURI(url).SetScheme(scheme).Finalize(url);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIMsgAccountManager> accountManager =
+ do_GetService("@mozilla.org/messenger/account-manager;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIMsgIncomingServer> server;
+ rv = accountManager->FindServerByURI(url, aIncomingServer);
+ if (!*aIncomingServer && scheme.EqualsLiteral("imap")) {
+ // look for any imap server with this host name so clicking on
+ // other users folder urls will work. We could override this method
+ // for imap urls, or we could make caching of servers work and
+ // just set the server in the imap code for this case.
+ rv = NS_MutateURI(url).SetUserPass(EmptyCString()).Finalize(url);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = accountManager->FindServerByURI(url, aIncomingServer);
+ }
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetMsgWindow(nsIMsgWindow** aMsgWindow) {
+ NS_ENSURE_ARG_POINTER(aMsgWindow);
+ *aMsgWindow = nullptr;
+
+ nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
+ msgWindow.forget(aMsgWindow);
+ return *aMsgWindow ? NS_OK : NS_ERROR_NULL_POINTER;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetMsgWindow(nsIMsgWindow* aMsgWindow) {
+#ifdef DEBUG_David_Bienvenu
+ NS_ASSERTION(aMsgWindow || !m_msgWindowWeak,
+ "someone crunching non-null msg window");
+#endif
+ m_msgWindowWeak = do_GetWeakReference(aMsgWindow);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetStatusFeedback(
+ nsIMsgStatusFeedback** aMsgFeedback) {
+ // note: it is okay to return a null status feedback and not return an error
+ // it's possible the url really doesn't have status feedback
+ *aMsgFeedback = nullptr;
+ if (!m_statusFeedbackWeak) {
+ nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
+ if (msgWindow) msgWindow->GetStatusFeedback(aMsgFeedback);
+ } else {
+ nsCOMPtr<nsIMsgStatusFeedback> statusFeedback(
+ do_QueryReferent(m_statusFeedbackWeak));
+ statusFeedback.forget(aMsgFeedback);
+ }
+ return *aMsgFeedback ? NS_OK : NS_ERROR_NULL_POINTER;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetStatusFeedback(
+ nsIMsgStatusFeedback* aMsgFeedback) {
+ if (aMsgFeedback) m_statusFeedbackWeak = do_GetWeakReference(aMsgFeedback);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetMaxProgress(int64_t* aMaxProgress) {
+ *aMaxProgress = mMaxProgress;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetMaxProgress(int64_t aMaxProgress) {
+ mMaxProgress = aMaxProgress;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetLoadGroup(nsILoadGroup** aLoadGroup) {
+ *aLoadGroup = nullptr;
+ // note: it is okay to return a null load group and not return an error
+ // it's possible the url really doesn't have load group
+ nsCOMPtr<nsILoadGroup> loadGroup(do_QueryReferent(m_loadGroupWeak));
+ if (!loadGroup) {
+ nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
+ if (msgWindow) {
+ // XXXbz This is really weird... why are we getting some
+ // random loadgroup we're not really a part of?
+ nsCOMPtr<nsIDocShell> docShell;
+ msgWindow->GetRootDocShell(getter_AddRefs(docShell));
+ loadGroup = do_GetInterface(docShell);
+ m_loadGroupWeak = do_GetWeakReference(loadGroup);
+ }
+ }
+ loadGroup.forget(aLoadGroup);
+ return *aLoadGroup ? NS_OK : NS_ERROR_NULL_POINTER;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetUpdatingFolder(bool* aResult) {
+ NS_ENSURE_ARG(aResult);
+ *aResult = m_updatingFolder;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetUpdatingFolder(bool updatingFolder) {
+ m_updatingFolder = updatingFolder;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetMsgIsInLocalCache(bool* aMsgIsInLocalCache) {
+ NS_ENSURE_ARG(aMsgIsInLocalCache);
+ *aMsgIsInLocalCache = m_msgIsInLocalCache;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetMsgIsInLocalCache(bool aMsgIsInLocalCache) {
+ m_msgIsInLocalCache = aMsgIsInLocalCache;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetSuppressErrorMsgs(bool* aSuppressErrorMsgs) {
+ NS_ENSURE_ARG(aSuppressErrorMsgs);
+ *aSuppressErrorMsgs = m_suppressErrorMsgs;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetSuppressErrorMsgs(bool aSuppressErrorMsgs) {
+ m_suppressErrorMsgs = aSuppressErrorMsgs;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetErrorCode(nsACString& aErrorCode) {
+ aErrorCode = m_errorCode;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetErrorCode(const nsACString& aErrorCode) {
+ m_errorCode.Assign(aErrorCode);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetErrorMessage(nsAString& aErrorMessage) {
+ aErrorMessage = m_errorMessage;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetErrorMessage(
+ const nsAString& aErrorMessage) {
+ m_errorMessage.Assign(aErrorMessage);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetSeeOtherURI(const nsACString& aSeeOtherURI) {
+ m_seeOtherURI.Assign(aSeeOtherURI);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetSeeOtherURI(nsACString& aSeeOtherURI) {
+ aSeeOtherURI = m_seeOtherURI;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::IsUrlType(uint32_t type, bool* isType) {
+ // base class doesn't know about any specific types
+ NS_ENSURE_ARG(isType);
+ *isType = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetSearchSession(
+ nsIMsgSearchSession* aSearchSession) {
+ if (aSearchSession) m_searchSession = aSearchSession;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetSearchSession(
+ nsIMsgSearchSession** aSearchSession) {
+ NS_ENSURE_ARG(aSearchSession);
+ NS_IF_ADDREF(*aSearchSession = m_searchSession);
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// End nsIMsgMailNewsUrl specific support
+////////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////
+// Begin nsIURI support
+////////////////////////////////////////////////////////////////////////////////////
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetSpec(nsACString& aSpec) {
+ return m_baseURL->GetSpec(aSpec);
+}
+
+nsresult nsMsgMailNewsUrl::CreateURL(const nsACString& aSpec, nsIURL** aURL) {
+ nsCOMPtr<nsIURL> url;
+ nsresult rv = NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
+ .SetSpec(aSpec)
+ .Finalize(url);
+ NS_ENSURE_SUCCESS(rv, rv);
+ url.forget(aURL);
+ return NS_OK;
+}
+
+#define FILENAME_PART_LEN 10
+
+nsresult nsMsgMailNewsUrl::SetSpecInternal(const nsACString& aSpec) {
+ nsAutoCString spec(aSpec);
+ // Parse out "filename" attribute if present.
+ char *start, *end;
+ start = PL_strcasestr(spec.BeginWriting(), "?filename=");
+ if (!start) start = PL_strcasestr(spec.BeginWriting(), "&filename=");
+ if (start) { // Make sure we only get our own value.
+ end = PL_strcasestr((char*)(start + FILENAME_PART_LEN), "&");
+ if (end) {
+ *end = 0;
+ mAttachmentFileName = start + FILENAME_PART_LEN;
+ *end = '&';
+ } else
+ mAttachmentFileName = start + FILENAME_PART_LEN;
+ }
+
+ // Now, set the rest.
+ nsresult rv = CreateURL(aSpec, getter_AddRefs(m_baseURL));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Check whether the URL is in normalized form.
+ nsCOMPtr<nsIMsgMessageUrl> msgUrl;
+ QueryInterface(NS_GET_IID(nsIMsgMessageUrl), getter_AddRefs(msgUrl));
+
+ nsAutoCString normalizedSpec;
+ if (!msgUrl || NS_FAILED(msgUrl->GetNormalizedSpec(normalizedSpec))) {
+ // If we can't get the normalized spec, never QI this to
+ // nsIURIWithSpecialOrigin.
+ m_hasNormalizedOrigin = false;
+ } else {
+ m_hasNormalizedOrigin = !spec.Equals(normalizedSpec);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetPrePath(nsACString& aPrePath) {
+ return m_baseURL->GetPrePath(aPrePath);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetScheme(nsACString& aScheme) {
+ return m_baseURL->GetScheme(aScheme);
+}
+
+nsresult nsMsgMailNewsUrl::SetScheme(const nsACString& aScheme) {
+ return NS_MutateURI(m_baseURL).SetScheme(aScheme).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetUserPass(nsACString& aUserPass) {
+ return m_baseURL->GetUserPass(aUserPass);
+}
+
+nsresult nsMsgMailNewsUrl::SetUserPass(const nsACString& aUserPass) {
+ return NS_MutateURI(m_baseURL).SetUserPass(aUserPass).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetUsername(nsACString& aUsername) {
+ /* note: this will return an escaped string */
+ return m_baseURL->GetUsername(aUsername);
+}
+
+nsresult nsMsgMailNewsUrl::SetUsername(const nsACString& aUsername) {
+ return NS_MutateURI(m_baseURL).SetUsername(aUsername).Finalize(m_baseURL);
+}
+
+nsresult nsMsgMailNewsUrl::SetUsernameInternal(const nsACString& aUsername) {
+ return NS_MutateURI(m_baseURL).SetUsername(aUsername).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetPassword(nsACString& aPassword) {
+ return m_baseURL->GetPassword(aPassword);
+}
+
+nsresult nsMsgMailNewsUrl::SetPassword(const nsACString& aPassword) {
+ return NS_MutateURI(m_baseURL).SetPassword(aPassword).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetHostPort(nsACString& aHostPort) {
+ return m_baseURL->GetHostPort(aHostPort);
+}
+
+nsresult nsMsgMailNewsUrl::SetHostPort(const nsACString& aHostPort) {
+ return NS_MutateURI(m_baseURL).SetHostPort(aHostPort).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetHost(nsACString& aHost) {
+ return m_baseURL->GetHost(aHost);
+}
+
+nsresult nsMsgMailNewsUrl::SetHost(const nsACString& aHost) {
+ return NS_MutateURI(m_baseURL).SetHost(aHost).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetPort(int32_t* aPort) {
+ return m_baseURL->GetPort(aPort);
+}
+
+nsresult nsMsgMailNewsUrl::SetPort(int32_t aPort) {
+ return NS_MutateURI(m_baseURL).SetPort(aPort).Finalize(m_baseURL);
+}
+
+nsresult nsMsgMailNewsUrl::SetPortInternal(int32_t aPort) {
+ return NS_MutateURI(m_baseURL).SetPort(aPort).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetPathQueryRef(nsACString& aPath) {
+ return m_baseURL->GetPathQueryRef(aPath);
+}
+
+nsresult nsMsgMailNewsUrl::SetPathQueryRef(const nsACString& aPath) {
+ return NS_MutateURI(m_baseURL).SetPathQueryRef(aPath).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetAsciiHost(nsACString& aHostA) {
+ return m_baseURL->GetAsciiHost(aHostA);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetAsciiHostPort(nsACString& aHostPortA) {
+ return m_baseURL->GetAsciiHostPort(aHostPortA);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetAsciiSpec(nsACString& aSpecA) {
+ return m_baseURL->GetAsciiSpec(aSpecA);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetBaseURI(nsIURI** aBaseURI) {
+ NS_ENSURE_ARG_POINTER(aBaseURI);
+ return m_baseURL->QueryInterface(NS_GET_IID(nsIURI), (void**)aBaseURI);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::Equals(nsIURI* other, bool* _retval) {
+ // The passed-in URI might be a mail news url. Pass our inner URL to its
+ // Equals method. The other mail news url will then pass its inner URL to
+ // to the Equals method of our inner URL. Other URIs will return false.
+ if (other) return other->Equals(m_baseURL, _retval);
+
+ return m_baseURL->Equals(other, _retval);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::EqualsExceptRef(nsIURI* other, bool* result) {
+ // The passed-in URI might be a mail news url. Pass our inner URL to its
+ // Equals method. The other mail news url will then pass its inner URL to
+ // to the Equals method of our inner URL. Other URIs will return false.
+ if (other) return other->EqualsExceptRef(m_baseURL, result);
+
+ return m_baseURL->EqualsExceptRef(other, result);
+}
+
+NS_IMETHODIMP
+nsMsgMailNewsUrl::GetSpecIgnoringRef(nsACString& result) {
+ return m_baseURL->GetSpecIgnoringRef(result);
+}
+
+NS_IMETHODIMP
+nsMsgMailNewsUrl::GetDisplaySpec(nsACString& aUnicodeSpec) {
+ return m_baseURL->GetDisplaySpec(aUnicodeSpec);
+}
+
+NS_IMETHODIMP
+nsMsgMailNewsUrl::GetDisplayHostPort(nsACString& aHostPort) {
+ return m_baseURL->GetDisplayHostPort(aHostPort);
+}
+
+NS_IMETHODIMP
+nsMsgMailNewsUrl::GetDisplayHost(nsACString& aHost) {
+ return m_baseURL->GetDisplayHost(aHost);
+}
+
+NS_IMETHODIMP
+nsMsgMailNewsUrl::GetDisplayPrePath(nsACString& aPrePath) {
+ return m_baseURL->GetDisplayPrePath(aPrePath);
+}
+
+NS_IMETHODIMP
+nsMsgMailNewsUrl::GetHasRef(bool* result) {
+ return m_baseURL->GetHasRef(result);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SchemeIs(const char* aScheme, bool* _retval) {
+ return m_baseURL->SchemeIs(aScheme, _retval);
+}
+
+nsresult nsMsgMailNewsUrl::Clone(nsIURI** _retval) {
+ nsresult rv;
+ nsAutoCString urlSpec;
+ nsCOMPtr<nsIIOService> ioService = mozilla::components::IO::Service();
+ NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
+ rv = GetSpec(urlSpec);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIURI> newUri;
+ rv = ioService->NewURI(urlSpec, nullptr, nullptr, getter_AddRefs(newUri));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // add the msg window to the cloned url
+ nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
+ if (msgWindow) {
+ nsCOMPtr<nsIMsgMailNewsUrl> msgMailNewsUrl = do_QueryInterface(newUri, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ msgMailNewsUrl->SetMsgWindow(msgWindow);
+ }
+
+ newUri.forget(_retval);
+ return rv;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::Resolve(const nsACString& relativePath,
+ nsACString& result) {
+ // only resolve anchor urls....i.e. urls which start with '#' against the
+ // mailnews url... everything else shouldn't be resolved against mailnews
+ // urls.
+ nsresult rv = NS_OK;
+
+ if (relativePath.IsEmpty()) {
+ // Return base URL.
+ rv = GetSpec(result);
+ } else if (!relativePath.IsEmpty() &&
+ relativePath.First() == '#') // an anchor
+ {
+ rv = m_baseURL->Resolve(relativePath, result);
+ } else {
+ // if relativePath is a complete url with it's own scheme then allow it...
+ nsCOMPtr<nsIIOService> ioService = mozilla::components::IO::Service();
+ NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
+ nsAutoCString scheme;
+
+ rv = ioService->ExtractScheme(relativePath, scheme);
+ // if we have a fully qualified scheme then pass the relative path back as
+ // the result
+ if (NS_SUCCEEDED(rv) && !scheme.IsEmpty()) {
+ result = relativePath;
+ rv = NS_OK;
+ } else {
+ result.Truncate();
+ rv = NS_ERROR_FAILURE;
+ }
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetDirectory(nsACString& aDirectory) {
+ return m_baseURL->GetDirectory(aDirectory);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetFileName(nsACString& aFileName) {
+ if (!mAttachmentFileName.IsEmpty()) {
+ aFileName = mAttachmentFileName;
+ return NS_OK;
+ }
+ return m_baseURL->GetFileName(aFileName);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetFileBaseName(nsACString& aFileBaseName) {
+ return m_baseURL->GetFileBaseName(aFileBaseName);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetFileExtension(nsACString& aFileExtension) {
+ if (!mAttachmentFileName.IsEmpty()) {
+ int32_t pos = mAttachmentFileName.RFindChar(char16_t('.'));
+ if (pos > 0)
+ aFileExtension =
+ Substring(mAttachmentFileName, pos + 1 /* skip the '.' */);
+ return NS_OK;
+ }
+ return m_baseURL->GetFileExtension(aFileExtension);
+}
+
+nsresult nsMsgMailNewsUrl::SetFileNameInternal(const nsACString& aFileName) {
+ mAttachmentFileName = aFileName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetQuery(nsACString& aQuery) {
+ return m_baseURL->GetQuery(aQuery);
+}
+
+nsresult nsMsgMailNewsUrl::SetQuery(const nsACString& aQuery) {
+ return NS_MutateURI(m_baseURL).SetQuery(aQuery).Finalize(m_baseURL);
+}
+
+nsresult nsMsgMailNewsUrl::SetQueryInternal(const nsACString& aQuery) {
+ return NS_MutateURI(m_baseURL).SetQuery(aQuery).Finalize(m_baseURL);
+}
+
+nsresult nsMsgMailNewsUrl::SetQueryWithEncoding(
+ const nsACString& aQuery, const mozilla::Encoding* aEncoding) {
+ return NS_MutateURI(m_baseURL)
+ .SetQueryWithEncoding(aQuery, aEncoding)
+ .Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetRef(nsACString& aRef) {
+ return m_baseURL->GetRef(aRef);
+}
+
+nsresult nsMsgMailNewsUrl::SetRef(const nsACString& aRef) {
+ return NS_MutateURI(m_baseURL).SetRef(aRef).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetFilePath(nsACString& o_DirFile) {
+ return m_baseURL->GetFilePath(o_DirFile);
+}
+
+nsresult nsMsgMailNewsUrl::SetFilePath(const nsACString& i_DirFile) {
+ return NS_MutateURI(m_baseURL).SetFilePath(i_DirFile).Finalize(m_baseURL);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetCommonBaseSpec(nsIURI* uri2,
+ nsACString& result) {
+ return m_baseURL->GetCommonBaseSpec(uri2, result);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetRelativeSpec(nsIURI* uri2,
+ nsACString& result) {
+ return m_baseURL->GetRelativeSpec(uri2, result);
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetMemCacheEntry(nsICacheEntry* memCacheEntry) {
+ m_memCacheEntry = memCacheEntry;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetMemCacheEntry(
+ nsICacheEntry** memCacheEntry) {
+ NS_ENSURE_ARG(memCacheEntry);
+ nsresult rv = NS_OK;
+
+ if (m_memCacheEntry) {
+ NS_ADDREF(*memCacheEntry = m_memCacheEntry);
+ } else {
+ *memCacheEntry = nullptr;
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetMimeHeaders(nsIMimeHeaders** mimeHeaders) {
+ NS_ENSURE_ARG_POINTER(mimeHeaders);
+ NS_IF_ADDREF(*mimeHeaders = mMimeHeaders);
+ return (mMimeHeaders) ? NS_OK : NS_ERROR_NULL_POINTER;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetMimeHeaders(nsIMimeHeaders* mimeHeaders) {
+ mMimeHeaders = mimeHeaders;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::LoadURI(nsIDocShell* docShell,
+ uint32_t aLoadFlags) {
+ NS_ENSURE_ARG_POINTER(docShell);
+ RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(this);
+ loadState->SetLoadFlags(aLoadFlags);
+ loadState->SetLoadType(MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags));
+ loadState->SetFirstParty(false);
+ loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
+ return docShell->LoadURI(loadState, false);
+}
+
+#define SAVE_BUF_SIZE FILE_IO_BUFFER_SIZE
+class nsMsgSaveAsListener : public nsIStreamListener {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIREQUESTOBSERVER
+ NS_DECL_NSISTREAMLISTENER
+
+ nsMsgSaveAsListener(nsIFile* aFile, bool addDummyEnvelope);
+ nsresult SetupMsgWriteStream(nsIFile* aFile, bool addDummyEnvelope);
+
+ protected:
+ virtual ~nsMsgSaveAsListener();
+ nsCOMPtr<nsIOutputStream> m_outputStream;
+ nsCOMPtr<nsIFile> m_outputFile;
+ bool m_addDummyEnvelope;
+ bool m_writtenData;
+ uint32_t m_leftOver;
+ char m_dataBuffer[SAVE_BUF_SIZE +
+ 1]; // temporary buffer for this save operation
+};
+
+NS_IMPL_ISUPPORTS(nsMsgSaveAsListener, nsIStreamListener, nsIRequestObserver)
+
+nsMsgSaveAsListener::nsMsgSaveAsListener(nsIFile* aFile,
+ bool addDummyEnvelope) {
+ m_outputFile = aFile;
+ m_writtenData = false;
+ m_addDummyEnvelope = addDummyEnvelope;
+ m_leftOver = 0;
+}
+
+nsMsgSaveAsListener::~nsMsgSaveAsListener() {}
+
+NS_IMETHODIMP nsMsgSaveAsListener::OnStartRequest(nsIRequest* request) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgSaveAsListener::OnStopRequest(nsIRequest* request, nsresult aStatus) {
+ if (m_outputStream) {
+ m_outputStream->Flush();
+ m_outputStream->Close();
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgSaveAsListener::OnDataAvailable(nsIRequest* request,
+ nsIInputStream* inStream,
+ uint64_t srcOffset,
+ uint32_t count) {
+ nsresult rv;
+ uint64_t available;
+ rv = inStream->Available(&available);
+ if (!m_writtenData) {
+ m_writtenData = true;
+ rv = SetupMsgWriteStream(m_outputFile, m_addDummyEnvelope);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ bool useCanonicalEnding = false;
+ // We know the request is an nsIChannel we can get a URI from, but this is
+ // probably bad form. See Bug 1528662.
+ nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "error QI nsIRequest to nsIChannel failed");
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIURI> uri;
+ rv = channel->GetURI(getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(uri);
+ if (msgUrl) msgUrl->GetCanonicalLineEnding(&useCanonicalEnding);
+
+ const char* lineEnding = (useCanonicalEnding) ? CRLF : MSG_LINEBREAK;
+ uint32_t lineEndingLength = (useCanonicalEnding) ? 2 : MSG_LINEBREAK_LEN;
+
+ uint32_t readCount, maxReadCount = SAVE_BUF_SIZE - m_leftOver;
+ uint32_t writeCount;
+ char *start, *end, lastCharInPrevBuf = '\0';
+ uint32_t linebreak_len = 0;
+
+ while (count > 0) {
+ if (count < maxReadCount) maxReadCount = count;
+ rv = inStream->Read(m_dataBuffer + m_leftOver, maxReadCount, &readCount);
+ if (NS_FAILED(rv)) return rv;
+
+ m_leftOver += readCount;
+ m_dataBuffer[m_leftOver] = '\0';
+
+ start = m_dataBuffer;
+ // make sure we don't insert another LF, accidentally, by ignoring
+ // second half of CRLF spanning blocks.
+ if (lastCharInPrevBuf == '\r' && *start == '\n') start++;
+
+ end = PL_strpbrk(start, "\r\n");
+ if (end) linebreak_len = (end[0] == '\r' && end[1] == '\n') ? 2 : 1;
+
+ count -= readCount;
+ maxReadCount = SAVE_BUF_SIZE - m_leftOver;
+
+ if (!end && count > maxReadCount)
+ // must be a very very long line; sorry cannot handle it
+ return NS_ERROR_FAILURE;
+
+ while (start && end) {
+ if (m_outputStream && PL_strncasecmp(start, "X-Mozilla-Status:", 17) &&
+ PL_strncasecmp(start, "X-Mozilla-Status2:", 18) &&
+ PL_strncmp(start, "From - ", 7)) {
+ rv = m_outputStream->Write(start, end - start, &writeCount);
+ nsresult tmp =
+ m_outputStream->Write(lineEnding, lineEndingLength, &writeCount);
+ if (NS_FAILED(tmp)) {
+ rv = tmp;
+ }
+ }
+ start = end + linebreak_len;
+ if (start >= m_dataBuffer + m_leftOver) {
+ maxReadCount = SAVE_BUF_SIZE;
+ m_leftOver = 0;
+ break;
+ }
+ end = PL_strpbrk(start, "\r\n");
+ if (end) linebreak_len = (end[0] == '\r' && end[1] == '\n') ? 2 : 1;
+ if (start && !end) {
+ m_leftOver -= (start - m_dataBuffer);
+ memcpy(m_dataBuffer, start,
+ m_leftOver + 1); // including null
+ maxReadCount = SAVE_BUF_SIZE - m_leftOver;
+ }
+ }
+ if (NS_FAILED(rv)) return rv;
+ if (end) lastCharInPrevBuf = *end;
+ }
+ return rv;
+
+ // rv = m_outputStream->WriteFrom(inStream, std::min(available, count),
+ // &bytesWritten);
+}
+
+nsresult nsMsgSaveAsListener::SetupMsgWriteStream(nsIFile* aFile,
+ bool addDummyEnvelope) {
+ // If the file already exists, delete it, but do this before
+ // getting the outputstream.
+ // Due to bug 328027, the nsSaveMsgListener created in
+ // nsMessenger::SaveAs now opens the stream on the nsIFile
+ // object, thus creating an empty file. Actual save operations for
+ // IMAP and NNTP use this nsMsgSaveAsListener here, though, so we
+ // have to close the stream before deleting the file, else data
+ // would still be written happily into a now non-existing file.
+ // (Windows doesn't care, btw, just unixoids do...)
+ aFile->Remove(false);
+
+ nsresult rv = MsgNewBufferedFileOutputStream(getter_AddRefs(m_outputStream),
+ aFile, -1, 0666);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (m_outputStream && addDummyEnvelope) {
+ nsAutoCString result;
+ uint32_t writeCount;
+
+ time_t now = time((time_t*)0);
+ char* ct = ctime(&now);
+ // Remove the ending new-line character.
+ ct[24] = '\0';
+ result = "From - ";
+ result += ct;
+ result += MSG_LINEBREAK;
+ m_outputStream->Write(result.get(), result.Length(), &writeCount);
+
+ result = "X-Mozilla-Status: 0001";
+ result += MSG_LINEBREAK;
+ result += "X-Mozilla-Status2: 00000000";
+ result += MSG_LINEBREAK;
+ m_outputStream->Write(result.get(), result.Length(), &writeCount);
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetSaveAsListener(
+ bool addDummyEnvelope, nsIFile* aFile, nsIStreamListener** aSaveListener) {
+ NS_ENSURE_ARG_POINTER(aSaveListener);
+ nsMsgSaveAsListener* saveAsListener =
+ new nsMsgSaveAsListener(aFile, addDummyEnvelope);
+ return saveAsListener->QueryInterface(NS_GET_IID(nsIStreamListener),
+ (void**)aSaveListener);
+}
+
+NS_IMETHODIMP
+nsMsgMailNewsUrl::SetFailedSecInfo(nsITransportSecurityInfo* secInfo) {
+ mFailedSecInfo = secInfo;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetFailedSecInfo(
+ nsITransportSecurityInfo** secInfo) {
+ NS_ENSURE_ARG_POINTER(secInfo);
+ NS_IF_ADDREF(*secInfo = mFailedSecInfo);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::SetFolder(nsIMsgFolder* /* aFolder */) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetFolder(nsIMsgFolder** /* aFolder */) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP nsMsgMailNewsUrl::GetIsMessageUri(bool* aIsMessageUri) {
+ NS_ENSURE_ARG(aIsMessageUri);
+ nsAutoCString scheme;
+ m_baseURL->GetScheme(scheme);
+ *aIsMessageUri = StringEndsWith(scheme, "-message"_ns);
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(nsMsgMailNewsUrl::Mutator, nsIURISetters, nsIURIMutator)
+
+NS_IMETHODIMP
+nsMsgMailNewsUrl::Mutate(nsIURIMutator** aMutator) {
+ RefPtr<nsMsgMailNewsUrl::Mutator> mutator = new nsMsgMailNewsUrl::Mutator();
+ nsresult rv = mutator->InitFromURI(this);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ mutator.forget(aMutator);
+ return NS_OK;
+}