1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "msgCore.h"
7 #include "nsMsgMailNewsUrl.h"
8 #include "nsMsgBaseCID.h"
9 #include "nsMsgLocalCID.h"
10 #include "nsIMsgAccountManager.h"
11 #include "nsString.h"
12 #include "nsILoadGroup.h"
13 #include "nsIDocShell.h"
14 #include "nsIWebProgress.h"
15 #include "nsIWebProgressListener.h"
16 #include "nsIInterfaceRequestor.h"
17 #include "nsIInterfaceRequestorUtils.h"
18 #include "nsIIOService.h"
19 #include "nsNetCID.h"
20 #include "nsIStreamListener.h"
21 #include "nsIOutputStream.h"
22 #include "nsIInputStream.h"
23 #include "nsNetUtil.h"
24 #include "nsIFile.h"
25 #include "prmem.h"
26 #include <time.h>
27 #include "nsMsgUtils.h"
28 #include "mozilla/Services.h"
29 #include "nsProxyRelease.h"
30 #include "mozilla/Encoding.h"
31 #include "nsDocShellLoadState.h"
32 #include "nsContentUtils.h"
33 #include "nsIObjectInputStream.h"
34 #include "nsIObjectOutputStream.h"
35 #include "nsIChannel.h"
36 
nsMsgMailNewsUrl()37 nsMsgMailNewsUrl::nsMsgMailNewsUrl() {
38   // nsIURI specific state
39   m_runningUrl = false;
40   m_updatingFolder = false;
41   m_msgIsInLocalCache = false;
42   m_suppressErrorMsgs = false;
43   m_hasNormalizedOrigin = false;  // SetSpecInternal() will set this correctly.
44   mMaxProgress = -1;
45 }
46 
47 #define NOTIFY_URL_LISTENERS(propertyfunc_, params_)                \
48   PR_BEGIN_MACRO                                                    \
49   nsTObserverArray<nsCOMPtr<nsIUrlListener>>::ForwardIterator iter( \
50       mUrlListeners);                                               \
51   while (iter.HasMore()) {                                          \
52     nsCOMPtr<nsIUrlListener> listener = iter.GetNext();             \
53     listener->propertyfunc_ params_;                                \
54   }                                                                 \
55   PR_END_MACRO
56 
~nsMsgMailNewsUrl()57 nsMsgMailNewsUrl::~nsMsgMailNewsUrl() {
58   // In IMAP this URL is created and destroyed on the imap thread,
59   // so we must ensure that releases of XPCOM objects (which might be
60   // implemented by non-threadsafe JS components) are released on the
61   // main thread.
62   NS_ReleaseOnMainThread("nsMsgMailNewsUrl::m_baseURL", m_baseURL.forget());
63   NS_ReleaseOnMainThread("nsMsgMailNewsUrl::mMimeHeaders",
64                          mMimeHeaders.forget());
65   NS_ReleaseOnMainThread("nsMsgMailNewsUrl::m_searchSession",
66                          m_searchSession.forget());
67   NS_ReleaseOnMainThread("nsMsgMailNewsUrl::mMsgHeaderSink",
68                          mMsgHeaderSink.forget());
69 
70   nsTObserverArray<nsCOMPtr<nsIUrlListener>>::ForwardIterator iter(
71       mUrlListeners);
72   while (iter.HasMore()) {
73     nsCOMPtr<nsIUrlListener> listener = iter.GetNext();
74     if (listener)
75       NS_ReleaseOnMainThread("nsMsgMailNewsUrl::mUrlListeners",
76                              listener.forget());
77   }
78 }
79 
80 NS_IMPL_ADDREF(nsMsgMailNewsUrl)
NS_IMPL_RELEASE(nsMsgMailNewsUrl)81 NS_IMPL_RELEASE(nsMsgMailNewsUrl)
82 
83 // We want part URLs to QI to nsIURIWithSpecialOrigin so we can give
84 // them a "normalized" origin. URLs that already have a "normalized"
85 // origin should not QI to nsIURIWithSpecialOrigin.
86 NS_INTERFACE_MAP_BEGIN(nsMsgMailNewsUrl)
87   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMsgMailNewsUrl)
88   NS_INTERFACE_MAP_ENTRY(nsIMsgMailNewsUrl)
89   NS_INTERFACE_MAP_ENTRY(nsIURL)
90   NS_INTERFACE_MAP_ENTRY(nsIURI)
91   NS_INTERFACE_MAP_ENTRY(nsISerializable)
92   NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
93   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIURIWithSpecialOrigin,
94                                      m_hasNormalizedOrigin)
95 NS_INTERFACE_MAP_END
96 
97 //--------------------------
98 // Support for serialization
99 //--------------------------
100 // nsMsgMailNewsUrl is only partly serialized by serializing the "base URL"
101 // which is an nsStandardURL, or by only serializing the Spec. This may
102 // cause problems in the future. See bug 1512356 and bug 1515337 for details,
103 // follow-up in bug 1512698.
104 
105 NS_IMETHODIMP_(void)
106 nsMsgMailNewsUrl::Serialize(mozilla::ipc::URIParams& aParams) {
107   m_baseURL->Serialize(aParams);
108 }
109 
110 //----------------------------
111 // Support for nsISerializable
112 //----------------------------
Read(nsIObjectInputStream * stream)113 NS_IMETHODIMP nsMsgMailNewsUrl::Read(nsIObjectInputStream* stream) {
114   nsAutoCString urlstr;
115   nsresult rv = NS_ReadOptionalCString(stream, urlstr);
116   NS_ENSURE_SUCCESS(rv, rv);
117   nsCOMPtr<nsIIOService> ioService = mozilla::services::GetIOService();
118   NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
119   nsCOMPtr<nsIURI> url;
120   rv = ioService->NewURI(urlstr, nullptr, nullptr, getter_AddRefs(url));
121   NS_ENSURE_SUCCESS(rv, rv);
122   m_baseURL = do_QueryInterface(url);
123   return NS_OK;
124 }
125 
Write(nsIObjectOutputStream * stream)126 NS_IMETHODIMP nsMsgMailNewsUrl::Write(nsIObjectOutputStream* stream) {
127   nsAutoCString urlstr;
128   nsresult rv = m_baseURL->GetSpec(urlstr);
129   NS_ENSURE_SUCCESS(rv, rv);
130   return NS_WriteOptionalStringZ(stream, urlstr.get());
131 }
132 
133 //-------------------------
134 // Support for nsIClassInfo
135 //-------------------------
GetInterfaces(nsTArray<nsIID> & array)136 NS_IMETHODIMP nsMsgMailNewsUrl::GetInterfaces(nsTArray<nsIID>& array) {
137   array.Clear();
138   return NS_OK;
139 }
140 
GetScriptableHelper(nsIXPCScriptable ** _retval)141 NS_IMETHODIMP nsMsgMailNewsUrl::GetScriptableHelper(
142     nsIXPCScriptable** _retval) {
143   *_retval = nullptr;
144   return NS_OK;
145 }
146 
GetContractID(nsACString & aContractID)147 NS_IMETHODIMP nsMsgMailNewsUrl::GetContractID(nsACString& aContractID) {
148   aContractID.SetIsVoid(true);
149   return NS_OK;
150 }
151 
GetClassDescription(nsACString & aClassDescription)152 NS_IMETHODIMP nsMsgMailNewsUrl::GetClassDescription(
153     nsACString& aClassDescription) {
154   aClassDescription.SetIsVoid(true);
155   return NS_OK;
156 }
157 
GetClassID(nsCID ** aClassID)158 NS_IMETHODIMP nsMsgMailNewsUrl::GetClassID(nsCID** aClassID) {
159   *aClassID = (nsCID*)moz_xmalloc(sizeof(nsCID));
160   return GetClassIDNoAlloc(*aClassID);
161 }
162 
GetFlags(uint32_t * aFlags)163 NS_IMETHODIMP nsMsgMailNewsUrl::GetFlags(uint32_t* aFlags) {
164   *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
165   return NS_OK;
166 }
167 
168 static NS_DEFINE_CID(kNS_MSGMAILNEWSURL_CID, NS_MSGMAILNEWSURL_CID);
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)169 NS_IMETHODIMP nsMsgMailNewsUrl::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
170   *aClassIDNoAlloc = kNS_MSGMAILNEWSURL_CID;
171   return NS_OK;
172 }
173 
174 //------------------------------------
175 // Support for nsIURIWithSpecialOrigin
176 //------------------------------------
GetOrigin(nsIURI ** aOrigin)177 NS_IMETHODIMP nsMsgMailNewsUrl::GetOrigin(nsIURI** aOrigin) {
178   MOZ_ASSERT(m_hasNormalizedOrigin,
179              "nsMsgMailNewsUrl::GetOrigin() can only be called for URLs with "
180              "normalized spec");
181 
182   if (!m_normalizedOrigin) {
183     nsCOMPtr<nsIMsgMessageUrl> msgUrl;
184     QueryInterface(NS_GET_IID(nsIMsgMessageUrl), getter_AddRefs(msgUrl));
185 
186     nsAutoCString spec;
187     if (!msgUrl || NS_FAILED(msgUrl->GetNormalizedSpec(spec))) {
188       MOZ_ASSERT(false, "Can't get normalized spec");
189       // just use the normal spec.
190       GetSpec(spec);
191     }
192 
193     nsresult rv = NS_NewURI(getter_AddRefs(m_normalizedOrigin), spec);
194     NS_ENSURE_SUCCESS(rv, rv);
195   }
196 
197   NS_IF_ADDREF(*aOrigin = m_normalizedOrigin);
198   return NS_OK;
199 }
200 
201 ////////////////////////////////////////////////////////////////////////////////////
202 // Begin nsIMsgMailNewsUrl specific support
203 ////////////////////////////////////////////////////////////////////////////////////
204 
GetUrlState(bool * aRunningUrl)205 nsresult nsMsgMailNewsUrl::GetUrlState(bool* aRunningUrl) {
206   if (aRunningUrl) *aRunningUrl = m_runningUrl;
207 
208   return NS_OK;
209 }
210 
SetUrlState(bool aRunningUrl,nsresult aExitCode)211 nsresult nsMsgMailNewsUrl::SetUrlState(bool aRunningUrl, nsresult aExitCode) {
212   // if we already knew this running state, return, unless the url was aborted
213   if (m_runningUrl == aRunningUrl && aExitCode != NS_MSG_ERROR_URL_ABORTED)
214     return NS_OK;
215   m_runningUrl = aRunningUrl;
216   nsCOMPtr<nsIMsgStatusFeedback> statusFeedback;
217 
218   // put this back - we need it for urls that don't run through the doc loader
219   if (NS_SUCCEEDED(GetStatusFeedback(getter_AddRefs(statusFeedback))) &&
220       statusFeedback) {
221     if (m_runningUrl)
222       statusFeedback->StartMeteors();
223     else {
224       statusFeedback->ShowProgress(0);
225       statusFeedback->StopMeteors();
226     }
227   }
228 
229   if (m_runningUrl) {
230     NOTIFY_URL_LISTENERS(OnStartRunningUrl, (this));
231   } else {
232     NOTIFY_URL_LISTENERS(OnStopRunningUrl, (this, aExitCode));
233     mUrlListeners.Clear();
234   }
235 
236   return NS_OK;
237 }
238 
RegisterListener(nsIUrlListener * aUrlListener)239 NS_IMETHODIMP nsMsgMailNewsUrl::RegisterListener(nsIUrlListener* aUrlListener) {
240   NS_ENSURE_ARG_POINTER(aUrlListener);
241   mUrlListeners.AppendElement(aUrlListener);
242   return NS_OK;
243 }
244 
UnRegisterListener(nsIUrlListener * aUrlListener)245 nsresult nsMsgMailNewsUrl::UnRegisterListener(nsIUrlListener* aUrlListener) {
246   NS_ENSURE_ARG_POINTER(aUrlListener);
247 
248   // Due to the way mailnews is structured, some listeners attempt to remove
249   // themselves twice. This may in fact be an error in the coding, however
250   // if they didn't do it as they do currently, then they could fail to remove
251   // their listeners.
252   mUrlListeners.RemoveElement(aUrlListener);
253 
254   return NS_OK;
255 }
256 
GetServer(nsIMsgIncomingServer ** aIncomingServer)257 NS_IMETHODIMP nsMsgMailNewsUrl::GetServer(
258     nsIMsgIncomingServer** aIncomingServer) {
259   // mscott --> we could cache a copy of the server here....but if we did, we
260   // run the risk of leaking the server if any single url gets leaked....of
261   // course that shouldn't happen...but it could. so i'm going to look it up
262   // every time and we can look at caching it later.
263 
264   nsresult rv;
265 
266   nsAutoCString urlstr;
267   rv = m_baseURL->GetSpec(urlstr);
268   NS_ENSURE_SUCCESS(rv, rv);
269 
270   nsCOMPtr<nsIURL> url;
271   rv = NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
272            .SetSpec(urlstr)
273            .Finalize(url);
274   NS_ENSURE_SUCCESS(rv, rv);
275 
276   nsAutoCString scheme;
277   rv = GetScheme(scheme);
278   if (NS_SUCCEEDED(rv)) {
279     if (scheme.EqualsLiteral("pop")) scheme.AssignLiteral("pop3");
280     // we use "nntp" in the server list so translate it here.
281     if (scheme.EqualsLiteral("news")) scheme.AssignLiteral("nntp");
282     rv = NS_MutateURI(url).SetScheme(scheme).Finalize(url);
283     NS_ENSURE_SUCCESS(rv, rv);
284     nsCOMPtr<nsIMsgAccountManager> accountManager =
285         do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
286     NS_ENSURE_SUCCESS(rv, rv);
287 
288     nsCOMPtr<nsIMsgIncomingServer> server;
289     rv = accountManager->FindServerByURI(url, false, aIncomingServer);
290     if (!*aIncomingServer && scheme.EqualsLiteral("imap")) {
291       // look for any imap server with this host name so clicking on
292       // other users folder urls will work. We could override this method
293       // for imap urls, or we could make caching of servers work and
294       // just set the server in the imap code for this case.
295       rv = NS_MutateURI(url).SetUserPass(EmptyCString()).Finalize(url);
296       NS_ENSURE_SUCCESS(rv, rv);
297       rv = accountManager->FindServerByURI(url, false, aIncomingServer);
298     }
299   }
300 
301   return rv;
302 }
303 
GetMsgWindow(nsIMsgWindow ** aMsgWindow)304 NS_IMETHODIMP nsMsgMailNewsUrl::GetMsgWindow(nsIMsgWindow** aMsgWindow) {
305   NS_ENSURE_ARG_POINTER(aMsgWindow);
306   *aMsgWindow = nullptr;
307 
308   nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
309   msgWindow.forget(aMsgWindow);
310   return *aMsgWindow ? NS_OK : NS_ERROR_NULL_POINTER;
311 }
312 
SetMsgWindow(nsIMsgWindow * aMsgWindow)313 NS_IMETHODIMP nsMsgMailNewsUrl::SetMsgWindow(nsIMsgWindow* aMsgWindow) {
314 #ifdef DEBUG_David_Bienvenu
315   NS_ASSERTION(aMsgWindow || !m_msgWindowWeak,
316                "someone crunching non-null msg window");
317 #endif
318   m_msgWindowWeak = do_GetWeakReference(aMsgWindow);
319   return NS_OK;
320 }
321 
GetStatusFeedback(nsIMsgStatusFeedback ** aMsgFeedback)322 NS_IMETHODIMP nsMsgMailNewsUrl::GetStatusFeedback(
323     nsIMsgStatusFeedback** aMsgFeedback) {
324   // note: it is okay to return a null status feedback and not return an error
325   // it's possible the url really doesn't have status feedback
326   *aMsgFeedback = nullptr;
327   if (!m_statusFeedbackWeak) {
328     nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
329     if (msgWindow) msgWindow->GetStatusFeedback(aMsgFeedback);
330   } else {
331     nsCOMPtr<nsIMsgStatusFeedback> statusFeedback(
332         do_QueryReferent(m_statusFeedbackWeak));
333     statusFeedback.forget(aMsgFeedback);
334   }
335   return *aMsgFeedback ? NS_OK : NS_ERROR_NULL_POINTER;
336 }
337 
SetStatusFeedback(nsIMsgStatusFeedback * aMsgFeedback)338 NS_IMETHODIMP nsMsgMailNewsUrl::SetStatusFeedback(
339     nsIMsgStatusFeedback* aMsgFeedback) {
340   if (aMsgFeedback) m_statusFeedbackWeak = do_GetWeakReference(aMsgFeedback);
341   return NS_OK;
342 }
343 
GetMaxProgress(int64_t * aMaxProgress)344 NS_IMETHODIMP nsMsgMailNewsUrl::GetMaxProgress(int64_t* aMaxProgress) {
345   *aMaxProgress = mMaxProgress;
346   return NS_OK;
347 }
348 
SetMaxProgress(int64_t aMaxProgress)349 NS_IMETHODIMP nsMsgMailNewsUrl::SetMaxProgress(int64_t aMaxProgress) {
350   mMaxProgress = aMaxProgress;
351   return NS_OK;
352 }
353 
GetLoadGroup(nsILoadGroup ** aLoadGroup)354 NS_IMETHODIMP nsMsgMailNewsUrl::GetLoadGroup(nsILoadGroup** aLoadGroup) {
355   *aLoadGroup = nullptr;
356   // note: it is okay to return a null load group and not return an error
357   // it's possible the url really doesn't have load group
358   nsCOMPtr<nsILoadGroup> loadGroup(do_QueryReferent(m_loadGroupWeak));
359   if (!loadGroup) {
360     nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
361     if (msgWindow) {
362       // XXXbz This is really weird... why are we getting some
363       // random loadgroup we're not really a part of?
364       nsCOMPtr<nsIDocShell> docShell;
365       msgWindow->GetRootDocShell(getter_AddRefs(docShell));
366       loadGroup = do_GetInterface(docShell);
367       m_loadGroupWeak = do_GetWeakReference(loadGroup);
368     }
369   }
370   loadGroup.forget(aLoadGroup);
371   return *aLoadGroup ? NS_OK : NS_ERROR_NULL_POINTER;
372 }
373 
GetUpdatingFolder(bool * aResult)374 NS_IMETHODIMP nsMsgMailNewsUrl::GetUpdatingFolder(bool* aResult) {
375   NS_ENSURE_ARG(aResult);
376   *aResult = m_updatingFolder;
377   return NS_OK;
378 }
379 
SetUpdatingFolder(bool updatingFolder)380 NS_IMETHODIMP nsMsgMailNewsUrl::SetUpdatingFolder(bool updatingFolder) {
381   m_updatingFolder = updatingFolder;
382   return NS_OK;
383 }
384 
GetMsgIsInLocalCache(bool * aMsgIsInLocalCache)385 NS_IMETHODIMP nsMsgMailNewsUrl::GetMsgIsInLocalCache(bool* aMsgIsInLocalCache) {
386   NS_ENSURE_ARG(aMsgIsInLocalCache);
387   *aMsgIsInLocalCache = m_msgIsInLocalCache;
388   return NS_OK;
389 }
390 
SetMsgIsInLocalCache(bool aMsgIsInLocalCache)391 NS_IMETHODIMP nsMsgMailNewsUrl::SetMsgIsInLocalCache(bool aMsgIsInLocalCache) {
392   m_msgIsInLocalCache = aMsgIsInLocalCache;
393   return NS_OK;
394 }
395 
GetSuppressErrorMsgs(bool * aSuppressErrorMsgs)396 NS_IMETHODIMP nsMsgMailNewsUrl::GetSuppressErrorMsgs(bool* aSuppressErrorMsgs) {
397   NS_ENSURE_ARG(aSuppressErrorMsgs);
398   *aSuppressErrorMsgs = m_suppressErrorMsgs;
399   return NS_OK;
400 }
401 
SetSuppressErrorMsgs(bool aSuppressErrorMsgs)402 NS_IMETHODIMP nsMsgMailNewsUrl::SetSuppressErrorMsgs(bool aSuppressErrorMsgs) {
403   m_suppressErrorMsgs = aSuppressErrorMsgs;
404   return NS_OK;
405 }
406 
GetErrorCode(nsACString & aErrorCode)407 NS_IMETHODIMP nsMsgMailNewsUrl::GetErrorCode(nsACString& aErrorCode) {
408   aErrorCode = m_errorCode;
409   return NS_OK;
410 }
411 
SetErrorCode(const nsACString & aErrorCode)412 NS_IMETHODIMP nsMsgMailNewsUrl::SetErrorCode(const nsACString& aErrorCode) {
413   m_errorCode.Assign(aErrorCode);
414   return NS_OK;
415 }
416 
GetErrorMessage(nsAString & aErrorMessage)417 NS_IMETHODIMP nsMsgMailNewsUrl::GetErrorMessage(nsAString& aErrorMessage) {
418   aErrorMessage = m_errorMessage;
419   return NS_OK;
420 }
421 
SetErrorMessage(const nsAString & aErrorMessage)422 NS_IMETHODIMP nsMsgMailNewsUrl::SetErrorMessage(
423     const nsAString& aErrorMessage) {
424   m_errorMessage.Assign(aErrorMessage);
425   return NS_OK;
426 }
427 
IsUrlType(uint32_t type,bool * isType)428 NS_IMETHODIMP nsMsgMailNewsUrl::IsUrlType(uint32_t type, bool* isType) {
429   // base class doesn't know about any specific types
430   NS_ENSURE_ARG(isType);
431   *isType = false;
432   return NS_OK;
433 }
434 
SetSearchSession(nsIMsgSearchSession * aSearchSession)435 NS_IMETHODIMP nsMsgMailNewsUrl::SetSearchSession(
436     nsIMsgSearchSession* aSearchSession) {
437   if (aSearchSession) m_searchSession = aSearchSession;
438   return NS_OK;
439 }
440 
GetSearchSession(nsIMsgSearchSession ** aSearchSession)441 NS_IMETHODIMP nsMsgMailNewsUrl::GetSearchSession(
442     nsIMsgSearchSession** aSearchSession) {
443   NS_ENSURE_ARG(aSearchSession);
444   NS_IF_ADDREF(*aSearchSession = m_searchSession);
445   return NS_OK;
446 }
447 
448 ////////////////////////////////////////////////////////////////////////////////////
449 // End nsIMsgMailNewsUrl specific support
450 ////////////////////////////////////////////////////////////////////////////////////
451 
452 ////////////////////////////////////////////////////////////////////////////////////
453 // Begin nsIURI support
454 ////////////////////////////////////////////////////////////////////////////////////
455 
GetSpec(nsACString & aSpec)456 NS_IMETHODIMP nsMsgMailNewsUrl::GetSpec(nsACString& aSpec) {
457   return m_baseURL->GetSpec(aSpec);
458 }
459 
CreateURL(const nsACString & aSpec,nsIURL ** aURL)460 nsresult nsMsgMailNewsUrl::CreateURL(const nsACString& aSpec, nsIURL** aURL) {
461   nsCOMPtr<nsIURL> url;
462   nsresult rv = NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
463                     .SetSpec(aSpec)
464                     .Finalize(url);
465   NS_ENSURE_SUCCESS(rv, rv);
466   url.forget(aURL);
467   return NS_OK;
468 }
469 
470 #define FILENAME_PART_LEN 10
471 
SetSpecInternal(const nsACString & aSpec)472 nsresult nsMsgMailNewsUrl::SetSpecInternal(const nsACString& aSpec) {
473   nsAutoCString spec(aSpec);
474   // Parse out "filename" attribute if present.
475   char *start, *end;
476   start = PL_strcasestr(spec.BeginWriting(), "?filename=");
477   if (!start) start = PL_strcasestr(spec.BeginWriting(), "&filename=");
478   if (start) {  // Make sure we only get our own value.
479     end = PL_strcasestr((char*)(start + FILENAME_PART_LEN), "&");
480     if (end) {
481       *end = 0;
482       mAttachmentFileName = start + FILENAME_PART_LEN;
483       *end = '&';
484     } else
485       mAttachmentFileName = start + FILENAME_PART_LEN;
486   }
487 
488   // Now, set the rest.
489   nsresult rv = CreateURL(aSpec, getter_AddRefs(m_baseURL));
490   NS_ENSURE_SUCCESS(rv, rv);
491 
492   // Check whether the URL is in normalized form.
493   nsCOMPtr<nsIMsgMessageUrl> msgUrl;
494   QueryInterface(NS_GET_IID(nsIMsgMessageUrl), getter_AddRefs(msgUrl));
495 
496   nsAutoCString normalizedSpec;
497   if (!msgUrl || NS_FAILED(msgUrl->GetNormalizedSpec(normalizedSpec))) {
498     // If we can't get the normalized spec, never QI this to
499     // nsIURIWithSpecialOrigin.
500     m_hasNormalizedOrigin = false;
501   } else {
502     m_hasNormalizedOrigin = !spec.Equals(normalizedSpec);
503   }
504   return NS_OK;
505 }
506 
GetPrePath(nsACString & aPrePath)507 NS_IMETHODIMP nsMsgMailNewsUrl::GetPrePath(nsACString& aPrePath) {
508   return m_baseURL->GetPrePath(aPrePath);
509 }
510 
GetScheme(nsACString & aScheme)511 NS_IMETHODIMP nsMsgMailNewsUrl::GetScheme(nsACString& aScheme) {
512   return m_baseURL->GetScheme(aScheme);
513 }
514 
SetScheme(const nsACString & aScheme)515 nsresult nsMsgMailNewsUrl::SetScheme(const nsACString& aScheme) {
516   return NS_MutateURI(m_baseURL).SetScheme(aScheme).Finalize(m_baseURL);
517 }
518 
GetUserPass(nsACString & aUserPass)519 NS_IMETHODIMP nsMsgMailNewsUrl::GetUserPass(nsACString& aUserPass) {
520   return m_baseURL->GetUserPass(aUserPass);
521 }
522 
SetUserPass(const nsACString & aUserPass)523 nsresult nsMsgMailNewsUrl::SetUserPass(const nsACString& aUserPass) {
524   return NS_MutateURI(m_baseURL).SetUserPass(aUserPass).Finalize(m_baseURL);
525 }
526 
GetUsername(nsACString & aUsername)527 NS_IMETHODIMP nsMsgMailNewsUrl::GetUsername(nsACString& aUsername) {
528   /* note:  this will return an escaped string */
529   return m_baseURL->GetUsername(aUsername);
530 }
531 
SetUsername(const nsACString & aUsername)532 nsresult nsMsgMailNewsUrl::SetUsername(const nsACString& aUsername) {
533   return NS_MutateURI(m_baseURL).SetUsername(aUsername).Finalize(m_baseURL);
534 }
535 
SetUsernameInternal(const nsACString & aUsername)536 nsresult nsMsgMailNewsUrl::SetUsernameInternal(const nsACString& aUsername) {
537   return NS_MutateURI(m_baseURL).SetUsername(aUsername).Finalize(m_baseURL);
538 }
539 
GetPassword(nsACString & aPassword)540 NS_IMETHODIMP nsMsgMailNewsUrl::GetPassword(nsACString& aPassword) {
541   return m_baseURL->GetPassword(aPassword);
542 }
543 
SetPassword(const nsACString & aPassword)544 nsresult nsMsgMailNewsUrl::SetPassword(const nsACString& aPassword) {
545   return NS_MutateURI(m_baseURL).SetPassword(aPassword).Finalize(m_baseURL);
546 }
547 
GetHostPort(nsACString & aHostPort)548 NS_IMETHODIMP nsMsgMailNewsUrl::GetHostPort(nsACString& aHostPort) {
549   return m_baseURL->GetHostPort(aHostPort);
550 }
551 
SetHostPort(const nsACString & aHostPort)552 nsresult nsMsgMailNewsUrl::SetHostPort(const nsACString& aHostPort) {
553   return NS_MutateURI(m_baseURL).SetHostPort(aHostPort).Finalize(m_baseURL);
554 }
555 
GetHost(nsACString & aHost)556 NS_IMETHODIMP nsMsgMailNewsUrl::GetHost(nsACString& aHost) {
557   return m_baseURL->GetHost(aHost);
558 }
559 
SetHost(const nsACString & aHost)560 nsresult nsMsgMailNewsUrl::SetHost(const nsACString& aHost) {
561   return NS_MutateURI(m_baseURL).SetHost(aHost).Finalize(m_baseURL);
562 }
563 
GetPort(int32_t * aPort)564 NS_IMETHODIMP nsMsgMailNewsUrl::GetPort(int32_t* aPort) {
565   return m_baseURL->GetPort(aPort);
566 }
567 
SetPort(int32_t aPort)568 nsresult nsMsgMailNewsUrl::SetPort(int32_t aPort) {
569   return NS_MutateURI(m_baseURL).SetPort(aPort).Finalize(m_baseURL);
570 }
571 
SetPortInternal(int32_t aPort)572 nsresult nsMsgMailNewsUrl::SetPortInternal(int32_t aPort) {
573   return NS_MutateURI(m_baseURL).SetPort(aPort).Finalize(m_baseURL);
574 }
575 
GetPathQueryRef(nsACString & aPath)576 NS_IMETHODIMP nsMsgMailNewsUrl::GetPathQueryRef(nsACString& aPath) {
577   return m_baseURL->GetPathQueryRef(aPath);
578 }
579 
SetPathQueryRef(const nsACString & aPath)580 nsresult nsMsgMailNewsUrl::SetPathQueryRef(const nsACString& aPath) {
581   return NS_MutateURI(m_baseURL).SetPathQueryRef(aPath).Finalize(m_baseURL);
582 }
583 
GetAsciiHost(nsACString & aHostA)584 NS_IMETHODIMP nsMsgMailNewsUrl::GetAsciiHost(nsACString& aHostA) {
585   return m_baseURL->GetAsciiHost(aHostA);
586 }
587 
GetAsciiHostPort(nsACString & aHostPortA)588 NS_IMETHODIMP nsMsgMailNewsUrl::GetAsciiHostPort(nsACString& aHostPortA) {
589   return m_baseURL->GetAsciiHostPort(aHostPortA);
590 }
591 
GetAsciiSpec(nsACString & aSpecA)592 NS_IMETHODIMP nsMsgMailNewsUrl::GetAsciiSpec(nsACString& aSpecA) {
593   return m_baseURL->GetAsciiSpec(aSpecA);
594 }
595 
GetBaseURI(nsIURI ** aBaseURI)596 NS_IMETHODIMP nsMsgMailNewsUrl::GetBaseURI(nsIURI** aBaseURI) {
597   NS_ENSURE_ARG_POINTER(aBaseURI);
598   return m_baseURL->QueryInterface(NS_GET_IID(nsIURI), (void**)aBaseURI);
599 }
600 
Equals(nsIURI * other,bool * _retval)601 NS_IMETHODIMP nsMsgMailNewsUrl::Equals(nsIURI* other, bool* _retval) {
602   // The passed-in URI might be a mail news url. Pass our inner URL to its
603   // Equals method. The other mail news url will then pass its inner URL to
604   // to the Equals method of our inner URL. Other URIs will return false.
605   if (other) return other->Equals(m_baseURL, _retval);
606 
607   return m_baseURL->Equals(other, _retval);
608 }
609 
EqualsExceptRef(nsIURI * other,bool * result)610 NS_IMETHODIMP nsMsgMailNewsUrl::EqualsExceptRef(nsIURI* other, bool* result) {
611   // The passed-in URI might be a mail news url. Pass our inner URL to its
612   // Equals method. The other mail news url will then pass its inner URL to
613   // to the Equals method of our inner URL. Other URIs will return false.
614   if (other) return other->EqualsExceptRef(m_baseURL, result);
615 
616   return m_baseURL->EqualsExceptRef(other, result);
617 }
618 
619 NS_IMETHODIMP
GetSpecIgnoringRef(nsACString & result)620 nsMsgMailNewsUrl::GetSpecIgnoringRef(nsACString& result) {
621   return m_baseURL->GetSpecIgnoringRef(result);
622 }
623 
624 NS_IMETHODIMP
GetDisplaySpec(nsACString & aUnicodeSpec)625 nsMsgMailNewsUrl::GetDisplaySpec(nsACString& aUnicodeSpec) {
626   return GetSpec(aUnicodeSpec);
627 }
628 
629 NS_IMETHODIMP
GetDisplayHostPort(nsACString & aUnicodeHostPort)630 nsMsgMailNewsUrl::GetDisplayHostPort(nsACString& aUnicodeHostPort) {
631   return GetHostPort(aUnicodeHostPort);
632 }
633 
634 NS_IMETHODIMP
GetDisplayHost(nsACString & aUnicodeHost)635 nsMsgMailNewsUrl::GetDisplayHost(nsACString& aUnicodeHost) {
636   return GetHost(aUnicodeHost);
637 }
638 
639 NS_IMETHODIMP
GetDisplayPrePath(nsACString & aPrePath)640 nsMsgMailNewsUrl::GetDisplayPrePath(nsACString& aPrePath) {
641   return GetPrePath(aPrePath);
642 }
643 
644 NS_IMETHODIMP
GetHasRef(bool * result)645 nsMsgMailNewsUrl::GetHasRef(bool* result) {
646   return m_baseURL->GetHasRef(result);
647 }
648 
SchemeIs(const char * aScheme,bool * _retval)649 NS_IMETHODIMP nsMsgMailNewsUrl::SchemeIs(const char* aScheme, bool* _retval) {
650   return m_baseURL->SchemeIs(aScheme, _retval);
651 }
652 
Clone(nsIURI ** _retval)653 nsresult nsMsgMailNewsUrl::Clone(nsIURI** _retval) {
654   nsresult rv;
655   nsAutoCString urlSpec;
656   nsCOMPtr<nsIIOService> ioService = mozilla::services::GetIOService();
657   NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
658   rv = GetSpec(urlSpec);
659   NS_ENSURE_SUCCESS(rv, rv);
660   nsCOMPtr<nsIURI> newUri;
661   rv = ioService->NewURI(urlSpec, nullptr, nullptr, getter_AddRefs(newUri));
662   NS_ENSURE_SUCCESS(rv, rv);
663 
664   // add the msg window to the cloned url
665   nsCOMPtr<nsIMsgWindow> msgWindow(do_QueryReferent(m_msgWindowWeak));
666   if (msgWindow) {
667     nsCOMPtr<nsIMsgMailNewsUrl> msgMailNewsUrl = do_QueryInterface(newUri, &rv);
668     NS_ENSURE_SUCCESS(rv, rv);
669     msgMailNewsUrl->SetMsgWindow(msgWindow);
670   }
671 
672   newUri.forget(_retval);
673   return rv;
674 }
675 
Resolve(const nsACString & relativePath,nsACString & result)676 NS_IMETHODIMP nsMsgMailNewsUrl::Resolve(const nsACString& relativePath,
677                                         nsACString& result) {
678   // only resolve anchor urls....i.e. urls which start with '#' against the
679   // mailnews url... everything else shouldn't be resolved against mailnews
680   // urls.
681   nsresult rv = NS_OK;
682 
683   if (relativePath.IsEmpty()) {
684     // Return base URL.
685     rv = GetSpec(result);
686   } else if (!relativePath.IsEmpty() &&
687              relativePath.First() == '#')  // an anchor
688   {
689     rv = m_baseURL->Resolve(relativePath, result);
690   } else {
691     // if relativePath is a complete url with it's own scheme then allow it...
692     nsCOMPtr<nsIIOService> ioService = mozilla::services::GetIOService();
693     NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
694     nsAutoCString scheme;
695 
696     rv = ioService->ExtractScheme(relativePath, scheme);
697     // if we have a fully qualified scheme then pass the relative path back as
698     // the result
699     if (NS_SUCCEEDED(rv) && !scheme.IsEmpty()) {
700       result = relativePath;
701       rv = NS_OK;
702     } else {
703       result.Truncate();
704       rv = NS_ERROR_FAILURE;
705     }
706   }
707 
708   return rv;
709 }
710 
GetDirectory(nsACString & aDirectory)711 NS_IMETHODIMP nsMsgMailNewsUrl::GetDirectory(nsACString& aDirectory) {
712   return m_baseURL->GetDirectory(aDirectory);
713 }
714 
GetFileName(nsACString & aFileName)715 NS_IMETHODIMP nsMsgMailNewsUrl::GetFileName(nsACString& aFileName) {
716   if (!mAttachmentFileName.IsEmpty()) {
717     aFileName = mAttachmentFileName;
718     return NS_OK;
719   }
720   return m_baseURL->GetFileName(aFileName);
721 }
722 
GetFileBaseName(nsACString & aFileBaseName)723 NS_IMETHODIMP nsMsgMailNewsUrl::GetFileBaseName(nsACString& aFileBaseName) {
724   return m_baseURL->GetFileBaseName(aFileBaseName);
725 }
726 
GetFileExtension(nsACString & aFileExtension)727 NS_IMETHODIMP nsMsgMailNewsUrl::GetFileExtension(nsACString& aFileExtension) {
728   if (!mAttachmentFileName.IsEmpty()) {
729     int32_t pos = mAttachmentFileName.RFindChar(char16_t('.'));
730     if (pos > 0)
731       aFileExtension =
732           Substring(mAttachmentFileName, pos + 1 /* skip the '.' */);
733     return NS_OK;
734   }
735   return m_baseURL->GetFileExtension(aFileExtension);
736 }
737 
SetFileNameInternal(const nsACString & aFileName)738 nsresult nsMsgMailNewsUrl::SetFileNameInternal(const nsACString& aFileName) {
739   mAttachmentFileName = aFileName;
740   return NS_OK;
741 }
742 
GetQuery(nsACString & aQuery)743 NS_IMETHODIMP nsMsgMailNewsUrl::GetQuery(nsACString& aQuery) {
744   return m_baseURL->GetQuery(aQuery);
745 }
746 
SetQuery(const nsACString & aQuery)747 nsresult nsMsgMailNewsUrl::SetQuery(const nsACString& aQuery) {
748   return NS_MutateURI(m_baseURL).SetQuery(aQuery).Finalize(m_baseURL);
749 }
750 
SetQueryInternal(const nsACString & aQuery)751 nsresult nsMsgMailNewsUrl::SetQueryInternal(const nsACString& aQuery) {
752   return NS_MutateURI(m_baseURL).SetQuery(aQuery).Finalize(m_baseURL);
753 }
754 
SetQueryWithEncoding(const nsACString & aQuery,const mozilla::Encoding * aEncoding)755 nsresult nsMsgMailNewsUrl::SetQueryWithEncoding(
756     const nsACString& aQuery, const mozilla::Encoding* aEncoding) {
757   return NS_MutateURI(m_baseURL)
758       .SetQueryWithEncoding(aQuery, aEncoding)
759       .Finalize(m_baseURL);
760 }
761 
GetRef(nsACString & aRef)762 NS_IMETHODIMP nsMsgMailNewsUrl::GetRef(nsACString& aRef) {
763   return m_baseURL->GetRef(aRef);
764 }
765 
SetRef(const nsACString & aRef)766 nsresult nsMsgMailNewsUrl::SetRef(const nsACString& aRef) {
767   return NS_MutateURI(m_baseURL).SetRef(aRef).Finalize(m_baseURL);
768 }
769 
GetFilePath(nsACString & o_DirFile)770 NS_IMETHODIMP nsMsgMailNewsUrl::GetFilePath(nsACString& o_DirFile) {
771   return m_baseURL->GetFilePath(o_DirFile);
772 }
773 
SetFilePath(const nsACString & i_DirFile)774 nsresult nsMsgMailNewsUrl::SetFilePath(const nsACString& i_DirFile) {
775   return NS_MutateURI(m_baseURL).SetFilePath(i_DirFile).Finalize(m_baseURL);
776 }
777 
GetCommonBaseSpec(nsIURI * uri2,nsACString & result)778 NS_IMETHODIMP nsMsgMailNewsUrl::GetCommonBaseSpec(nsIURI* uri2,
779                                                   nsACString& result) {
780   return m_baseURL->GetCommonBaseSpec(uri2, result);
781 }
782 
GetRelativeSpec(nsIURI * uri2,nsACString & result)783 NS_IMETHODIMP nsMsgMailNewsUrl::GetRelativeSpec(nsIURI* uri2,
784                                                 nsACString& result) {
785   return m_baseURL->GetRelativeSpec(uri2, result);
786 }
787 
SetMemCacheEntry(nsICacheEntry * memCacheEntry)788 NS_IMETHODIMP nsMsgMailNewsUrl::SetMemCacheEntry(nsICacheEntry* memCacheEntry) {
789   m_memCacheEntry = memCacheEntry;
790   return NS_OK;
791 }
792 
GetMemCacheEntry(nsICacheEntry ** memCacheEntry)793 NS_IMETHODIMP nsMsgMailNewsUrl::GetMemCacheEntry(
794     nsICacheEntry** memCacheEntry) {
795   NS_ENSURE_ARG(memCacheEntry);
796   nsresult rv = NS_OK;
797 
798   if (m_memCacheEntry) {
799     NS_ADDREF(*memCacheEntry = m_memCacheEntry);
800   } else {
801     *memCacheEntry = nullptr;
802     return NS_ERROR_NULL_POINTER;
803   }
804 
805   return rv;
806 }
807 
GetMimeHeaders(nsIMimeHeaders ** mimeHeaders)808 NS_IMETHODIMP nsMsgMailNewsUrl::GetMimeHeaders(nsIMimeHeaders** mimeHeaders) {
809   NS_ENSURE_ARG_POINTER(mimeHeaders);
810   NS_IF_ADDREF(*mimeHeaders = mMimeHeaders);
811   return (mMimeHeaders) ? NS_OK : NS_ERROR_NULL_POINTER;
812 }
813 
SetMimeHeaders(nsIMimeHeaders * mimeHeaders)814 NS_IMETHODIMP nsMsgMailNewsUrl::SetMimeHeaders(nsIMimeHeaders* mimeHeaders) {
815   mMimeHeaders = mimeHeaders;
816   return NS_OK;
817 }
818 
LoadURI(nsIDocShell * docShell,uint32_t aLoadFlags)819 NS_IMETHODIMP nsMsgMailNewsUrl::LoadURI(nsIDocShell* docShell,
820                                         uint32_t aLoadFlags) {
821   NS_ENSURE_ARG_POINTER(docShell);
822   RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(this);
823   loadState->SetLoadFlags(aLoadFlags);
824   loadState->SetLoadType(MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags));
825   loadState->SetFirstParty(false);
826   loadState->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
827   return docShell->LoadURI(loadState, false);
828 }
829 
830 #define SAVE_BUF_SIZE FILE_IO_BUFFER_SIZE
831 class nsMsgSaveAsListener : public nsIStreamListener {
832  public:
833   NS_DECL_ISUPPORTS
834   NS_DECL_NSIREQUESTOBSERVER
835   NS_DECL_NSISTREAMLISTENER
836 
837   nsMsgSaveAsListener(nsIFile* aFile, bool addDummyEnvelope);
838   nsresult SetupMsgWriteStream(nsIFile* aFile, bool addDummyEnvelope);
839 
840  protected:
841   virtual ~nsMsgSaveAsListener();
842   nsCOMPtr<nsIOutputStream> m_outputStream;
843   nsCOMPtr<nsIFile> m_outputFile;
844   bool m_addDummyEnvelope;
845   bool m_writtenData;
846   uint32_t m_leftOver;
847   char m_dataBuffer[SAVE_BUF_SIZE +
848                     1];  // temporary buffer for this save operation
849 };
850 
NS_IMPL_ISUPPORTS(nsMsgSaveAsListener,nsIStreamListener,nsIRequestObserver)851 NS_IMPL_ISUPPORTS(nsMsgSaveAsListener, nsIStreamListener, nsIRequestObserver)
852 
853 nsMsgSaveAsListener::nsMsgSaveAsListener(nsIFile* aFile,
854                                          bool addDummyEnvelope) {
855   m_outputFile = aFile;
856   m_writtenData = false;
857   m_addDummyEnvelope = addDummyEnvelope;
858   m_leftOver = 0;
859 }
860 
~nsMsgSaveAsListener()861 nsMsgSaveAsListener::~nsMsgSaveAsListener() {}
862 
OnStartRequest(nsIRequest * request)863 NS_IMETHODIMP nsMsgSaveAsListener::OnStartRequest(nsIRequest* request) {
864   return NS_OK;
865 }
866 
867 NS_IMETHODIMP
OnStopRequest(nsIRequest * request,nsresult aStatus)868 nsMsgSaveAsListener::OnStopRequest(nsIRequest* request, nsresult aStatus) {
869   if (m_outputStream) {
870     m_outputStream->Flush();
871     m_outputStream->Close();
872   }
873   return NS_OK;
874 }
875 
OnDataAvailable(nsIRequest * request,nsIInputStream * inStream,uint64_t srcOffset,uint32_t count)876 NS_IMETHODIMP nsMsgSaveAsListener::OnDataAvailable(nsIRequest* request,
877                                                    nsIInputStream* inStream,
878                                                    uint64_t srcOffset,
879                                                    uint32_t count) {
880   nsresult rv;
881   uint64_t available;
882   rv = inStream->Available(&available);
883   if (!m_writtenData) {
884     m_writtenData = true;
885     rv = SetupMsgWriteStream(m_outputFile, m_addDummyEnvelope);
886     NS_ENSURE_SUCCESS(rv, rv);
887   }
888 
889   bool useCanonicalEnding = false;
890   // We know the request is an nsIChannel we can get a URI from, but this is
891   // probably bad form. See Bug 1528662.
892   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
893   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
894                        "error QI nsIRequest to nsIChannel failed");
895   NS_ENSURE_SUCCESS(rv, rv);
896   nsCOMPtr<nsIURI> uri;
897   rv = channel->GetURI(getter_AddRefs(uri));
898   NS_ENSURE_SUCCESS(rv, rv);
899   nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(uri);
900   if (msgUrl) msgUrl->GetCanonicalLineEnding(&useCanonicalEnding);
901 
902   const char* lineEnding = (useCanonicalEnding) ? CRLF : MSG_LINEBREAK;
903   uint32_t lineEndingLength = (useCanonicalEnding) ? 2 : MSG_LINEBREAK_LEN;
904 
905   uint32_t readCount, maxReadCount = SAVE_BUF_SIZE - m_leftOver;
906   uint32_t writeCount;
907   char *start, *end, lastCharInPrevBuf = '\0';
908   uint32_t linebreak_len = 0;
909 
910   while (count > 0) {
911     if (count < maxReadCount) maxReadCount = count;
912     rv = inStream->Read(m_dataBuffer + m_leftOver, maxReadCount, &readCount);
913     if (NS_FAILED(rv)) return rv;
914 
915     m_leftOver += readCount;
916     m_dataBuffer[m_leftOver] = '\0';
917 
918     start = m_dataBuffer;
919     // make sure we don't insert another LF, accidentally, by ignoring
920     // second half of CRLF spanning blocks.
921     if (lastCharInPrevBuf == '\r' && *start == '\n') start++;
922 
923     end = PL_strpbrk(start, "\r\n");
924     if (end) linebreak_len = (end[0] == '\r' && end[1] == '\n') ? 2 : 1;
925 
926     count -= readCount;
927     maxReadCount = SAVE_BUF_SIZE - m_leftOver;
928 
929     if (!end && count > maxReadCount)
930       // must be a very very long line; sorry cannot handle it
931       return NS_ERROR_FAILURE;
932 
933     while (start && end) {
934       if (m_outputStream && PL_strncasecmp(start, "X-Mozilla-Status:", 17) &&
935           PL_strncasecmp(start, "X-Mozilla-Status2:", 18) &&
936           PL_strncmp(start, "From - ", 7)) {
937         rv = m_outputStream->Write(start, end - start, &writeCount);
938         nsresult tmp =
939             m_outputStream->Write(lineEnding, lineEndingLength, &writeCount);
940         if (NS_FAILED(tmp)) {
941           rv = tmp;
942         }
943       }
944       start = end + linebreak_len;
945       if (start >= m_dataBuffer + m_leftOver) {
946         maxReadCount = SAVE_BUF_SIZE;
947         m_leftOver = 0;
948         break;
949       }
950       end = PL_strpbrk(start, "\r\n");
951       if (end) linebreak_len = (end[0] == '\r' && end[1] == '\n') ? 2 : 1;
952       if (start && !end) {
953         m_leftOver -= (start - m_dataBuffer);
954         memcpy(m_dataBuffer, start,
955                m_leftOver + 1);  // including null
956         maxReadCount = SAVE_BUF_SIZE - m_leftOver;
957       }
958     }
959     if (NS_FAILED(rv)) return rv;
960     if (end) lastCharInPrevBuf = *end;
961   }
962   return rv;
963 
964   //  rv = m_outputStream->WriteFrom(inStream, std::min(available, count),
965   //  &bytesWritten);
966 }
967 
SetupMsgWriteStream(nsIFile * aFile,bool addDummyEnvelope)968 nsresult nsMsgSaveAsListener::SetupMsgWriteStream(nsIFile* aFile,
969                                                   bool addDummyEnvelope) {
970   // If the file already exists, delete it, but do this before
971   // getting the outputstream.
972   // Due to bug 328027, the nsSaveMsgListener created in
973   // nsMessenger::SaveAs now opens the stream on the nsIFile
974   // object, thus creating an empty file. Actual save operations for
975   // IMAP and NNTP use this nsMsgSaveAsListener here, though, so we
976   // have to close the stream before deleting the file, else data
977   // would still be written happily into a now non-existing file.
978   // (Windows doesn't care, btw, just unixoids do...)
979   aFile->Remove(false);
980 
981   nsresult rv = MsgNewBufferedFileOutputStream(getter_AddRefs(m_outputStream),
982                                                aFile, -1, 0666);
983   NS_ENSURE_SUCCESS(rv, rv);
984 
985   if (m_outputStream && addDummyEnvelope) {
986     nsAutoCString result;
987     uint32_t writeCount;
988 
989     time_t now = time((time_t*)0);
990     char* ct = ctime(&now);
991     // Remove the ending new-line character.
992     ct[24] = '\0';
993     result = "From - ";
994     result += ct;
995     result += MSG_LINEBREAK;
996     m_outputStream->Write(result.get(), result.Length(), &writeCount);
997 
998     result = "X-Mozilla-Status: 0001";
999     result += MSG_LINEBREAK;
1000     result += "X-Mozilla-Status2: 00000000";
1001     result += MSG_LINEBREAK;
1002     m_outputStream->Write(result.get(), result.Length(), &writeCount);
1003   }
1004 
1005   return rv;
1006 }
1007 
GetSaveAsListener(bool addDummyEnvelope,nsIFile * aFile,nsIStreamListener ** aSaveListener)1008 NS_IMETHODIMP nsMsgMailNewsUrl::GetSaveAsListener(
1009     bool addDummyEnvelope, nsIFile* aFile, nsIStreamListener** aSaveListener) {
1010   NS_ENSURE_ARG_POINTER(aSaveListener);
1011   nsMsgSaveAsListener* saveAsListener =
1012       new nsMsgSaveAsListener(aFile, addDummyEnvelope);
1013   return saveAsListener->QueryInterface(NS_GET_IID(nsIStreamListener),
1014                                         (void**)aSaveListener);
1015 }
1016 
1017 NS_IMETHODIMP
SetFailedSecInfo(nsITransportSecurityInfo * secInfo)1018 nsMsgMailNewsUrl::SetFailedSecInfo(nsITransportSecurityInfo* secInfo) {
1019   mFailedSecInfo = secInfo;
1020   return NS_OK;
1021 }
1022 
GetFailedSecInfo(nsITransportSecurityInfo ** secInfo)1023 NS_IMETHODIMP nsMsgMailNewsUrl::GetFailedSecInfo(
1024     nsITransportSecurityInfo** secInfo) {
1025   NS_ENSURE_ARG_POINTER(secInfo);
1026   NS_IF_ADDREF(*secInfo = mFailedSecInfo);
1027   return NS_OK;
1028 }
1029 
SetFolder(nsIMsgFolder *)1030 NS_IMETHODIMP nsMsgMailNewsUrl::SetFolder(nsIMsgFolder* /* aFolder */) {
1031   return NS_ERROR_NOT_IMPLEMENTED;
1032 }
1033 
GetFolder(nsIMsgFolder **)1034 NS_IMETHODIMP nsMsgMailNewsUrl::GetFolder(nsIMsgFolder** /* aFolder */) {
1035   return NS_ERROR_NOT_IMPLEMENTED;
1036 }
1037 
GetMsgHeaderSink(nsIMsgHeaderSink ** aMsgHdrSink)1038 NS_IMETHODIMP nsMsgMailNewsUrl::GetMsgHeaderSink(
1039     nsIMsgHeaderSink** aMsgHdrSink) {
1040   NS_ENSURE_ARG_POINTER(aMsgHdrSink);
1041   NS_IF_ADDREF(*aMsgHdrSink = mMsgHeaderSink);
1042   return NS_OK;
1043 }
1044 
SetMsgHeaderSink(nsIMsgHeaderSink * aMsgHdrSink)1045 NS_IMETHODIMP nsMsgMailNewsUrl::SetMsgHeaderSink(
1046     nsIMsgHeaderSink* aMsgHdrSink) {
1047   mMsgHeaderSink = aMsgHdrSink;
1048   return NS_OK;
1049 }
1050 
GetIsMessageUri(bool * aIsMessageUri)1051 NS_IMETHODIMP nsMsgMailNewsUrl::GetIsMessageUri(bool* aIsMessageUri) {
1052   NS_ENSURE_ARG(aIsMessageUri);
1053   nsAutoCString scheme;
1054   m_baseURL->GetScheme(scheme);
1055   *aIsMessageUri = StringEndsWith(scheme, "-message"_ns);
1056   return NS_OK;
1057 }
1058 
NS_IMPL_ISUPPORTS(nsMsgMailNewsUrl::Mutator,nsIURISetters,nsIURIMutator)1059 NS_IMPL_ISUPPORTS(nsMsgMailNewsUrl::Mutator, nsIURISetters, nsIURIMutator)
1060 
1061 NS_IMETHODIMP
1062 nsMsgMailNewsUrl::Mutate(nsIURIMutator** aMutator) {
1063   RefPtr<nsMsgMailNewsUrl::Mutator> mutator = new nsMsgMailNewsUrl::Mutator();
1064   nsresult rv = mutator->InitFromURI(this);
1065   if (NS_FAILED(rv)) {
1066     return rv;
1067   }
1068   mutator.forget(aMutator);
1069   return NS_OK;
1070 }
1071