/* 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 "ExchangeProtocolHandler.h" #include "ExchangeMessageChannel.h" #include "nsIMsgIncomingServer.h" nsresult NS_CreateEwsProtocolHandler(REFNSIID aIID, void** aResult) { NS_ENSURE_ARG_POINTER(aResult); *aResult = nullptr; RefPtr instance( new ExchangeProtocolHandler("x-moz-ews"_ns)); return instance->QueryInterface(aIID, aResult); } nsresult NS_CreateGraphProtocolHandler(REFNSIID aIID, void** aResult) { NS_ENSURE_ARG_POINTER(aResult); *aResult = nullptr; RefPtr instance( new ExchangeProtocolHandler("x-moz-graph"_ns)); return instance->QueryInterface(aIID, aResult); } NS_IMPL_ISUPPORTS(ExchangeProtocolHandler, nsIProtocolHandler) ExchangeProtocolHandler::ExchangeProtocolHandler( const nsACString& exchangeScheme) : mExchangeScheme(std::move(exchangeScheme)) {} ExchangeProtocolHandler::~ExchangeProtocolHandler() = default; NS_IMETHODIMP ExchangeProtocolHandler::GetScheme(nsACString& aScheme) { aScheme.Assign(mExchangeScheme); return NS_OK; } NS_IMETHODIMP ExchangeProtocolHandler::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadinfo, nsIChannel** _retval) { nsCString spec; MOZ_TRY(aURI->GetSpec(spec)); // During "normal" message display, `nsDocShell` takes care of running our own // RFC822 converter for us. However, in some cases, we might want to run it // ourselves, e.g. when displaying an attachment (inline, PDF, etc.). // // In the case of displaying an attachment, we need to run our own converter // first (before any that `nsDocShell` deems appropriate), because when e.g. // displaying a PDF, the message/rfc822->application/pdf conversion and the // application/pdf->text/html conversion are each handled by separate stream // converters (the former by our own, and the latter by PDF.js). // // Other cases (with `convert=true` in the query) likely originate from using // `ExchangeService::StreamMessage`. In theory we could run the stream // converter there directly, but we want to centralise calls to the stream // converter service as much as possible for maintainability. bool convert = false; if (spec.Find("part=") != kNotFound || spec.Find("convert=true") != kNotFound) { convert = true; } RefPtr channel = new ExchangeMessageChannel(aURI, convert); MOZ_TRY(channel->SetLoadInfo(aLoadinfo)); // Add the attachment disposition. This forces docShell to open the // attachment instead of displaying it. Content types we have special // handlers for are white-listed. This white list also exists in // nsImapService::NewChannel, nsMailboxService::NewChannel and // nsNntpService::NewChannel, so if you're changing this, update those too. if (spec.Find("part=") >= 0 && spec.Find("type=message/rfc822") < 0 && spec.Find("type=application/x-message-display") < 0 && spec.Find("type=application/pdf") < 0) { MOZ_TRY(channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT)); } channel.forget(_retval); return NS_OK; } NS_IMETHODIMP ExchangeProtocolHandler::AllowPort(int32_t port, const char* scheme, bool* _retval) { // Because we control the entire lifetime of message URIs from creation to // loading, we should never encounter a port we don't expect. MOZ_ASSERT_UNREACHABLE("call to AllowPort on internal protocol"); NS_ENSURE_ARG_POINTER(_retval); *_retval = false; return NS_OK; }