diff options
Diffstat (limited to '')
-rw-r--r-- | comm/mailnews/local/src/nsPop3Sink.cpp | 740 |
1 files changed, 740 insertions, 0 deletions
diff --git a/comm/mailnews/local/src/nsPop3Sink.cpp b/comm/mailnews/local/src/nsPop3Sink.cpp new file mode 100644 index 0000000000..2d4b7472c9 --- /dev/null +++ b/comm/mailnews/local/src/nsPop3Sink.cpp @@ -0,0 +1,740 @@ +/* -*- 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" // precompiled header... +#include "nsPop3Sink.h" +#include "prprf.h" +#include "prlog.h" +#include "nscore.h" +#include <stdio.h> +#include <time.h> +#include "nsParseMailbox.h" +#include "nsIMsgLocalMailFolder.h" +#include "nsIMsgIncomingServer.h" +#include "nsLocalUtils.h" +#include "nsMsgLocalFolderHdrs.h" +#include "nsIMsgFolder.h" // TO include biffState enum. Change to bool later... +#include "nsMsgMessageFlags.h" +#include "nsMailHeaders.h" +#include "nsIMsgAccountManager.h" +#include "nsIPop3Protocol.h" +#include "nsLocalMailFolder.h" +#include "nsIInputStream.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsIPromptService.h" +#include "nsIDocShell.h" +#include "mozIDOMWindow.h" +#include "nsEmbedCID.h" +#include "nsMsgUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsISupportsPrimitives.h" +#include "nsIObserverService.h" +#include "nsIPop3Service.h" +#include "mozilla/Logging.h" +#include "mozilla/Services.h" + +/* for logging to Error Console */ +#include "nsIScriptError.h" + +mozilla::LazyLogModule POP3LOGMODULE("POP3"); +#define POP3LOG(str) "sink: [this=%p] " str, this + +NS_IMPL_ISUPPORTS(nsPop3Sink, nsIPop3Sink) + +nsPop3Sink::nsPop3Sink() { + m_biffState = 0; + m_numNewMessages = 0; + m_numNewMessagesInFolder = 0; + m_numMsgsDownloaded = 0; + m_senderAuthed = false; + m_outFileStream = nullptr; + m_uidlDownload = false; + m_buildMessageUri = false; +} + +nsPop3Sink::~nsPop3Sink() { + MOZ_LOG(POP3LOGMODULE, mozilla::LogLevel::Debug, + (POP3LOG("Calling ReleaseFolderLock from ~nsPop3Sink"))); + ReleaseFolderLock(); +} + +partialRecord::partialRecord() : m_msgDBHdr(nullptr) {} + +partialRecord::~partialRecord() {} + +// Walk through all the messages in this folder and look for any +// PARTIAL messages. For each of those, dig through the mailbox and +// find the Account that the message belongs to. If that Account +// matches the current Account, then look for the Uidl and save +// this message for later processing. +nsresult nsPop3Sink::FindPartialMessages() { + nsCOMPtr<nsIMsgEnumerator> messages; + bool hasMore = false; + bool isOpen = false; + nsLocalFolderScanState folderScanState; + nsCOMPtr<nsIMsgDatabase> db; + nsCOMPtr<nsIMsgLocalMailFolder> localFolder = do_QueryInterface(m_folder); + m_folder->GetMsgDatabase(getter_AddRefs(db)); + if (!localFolder || !db) + return NS_ERROR_FAILURE; // we need it to grub through the folder + + nsresult rv = db->EnumerateMessages(getter_AddRefs(messages)); + if (messages) messages->HasMoreElements(&hasMore); + while (hasMore && NS_SUCCEEDED(rv)) { + uint32_t flags = 0; + nsCOMPtr<nsIMsgDBHdr> msgDBHdr; + rv = messages->GetNext(getter_AddRefs(msgDBHdr)); + if (!NS_SUCCEEDED(rv)) break; + msgDBHdr->GetFlags(&flags); + if (flags & nsMsgMessageFlags::Partial) { + // Open the various streams we need to seek and read from the mailbox + if (!isOpen) { + rv = localFolder->GetFolderScanState(&folderScanState); + if (NS_SUCCEEDED(rv)) + isOpen = true; + else + break; + } + rv = localFolder->GetUidlFromFolder(&folderScanState, msgDBHdr); + if (!NS_SUCCEEDED(rv)) break; + + // If we got the uidl, see if this partial message belongs to this + // account. Add it to the array if so... + if (folderScanState.m_uidl && + m_accountKey.Equals(folderScanState.m_accountKey, + nsCaseInsensitiveCStringComparator)) { + partialRecord* partialMsg = new partialRecord(); + if (partialMsg) { + partialMsg->m_uidl = folderScanState.m_uidl; + partialMsg->m_msgDBHdr = msgDBHdr; + m_partialMsgsArray.AppendElement(partialMsg); + } + } + } + messages->HasMoreElements(&hasMore); + } + if (isOpen && folderScanState.m_inputStream) + folderScanState.m_inputStream->Close(); + return rv; +} + +// For all the partial messages saved by FindPartialMessages, +// ask the protocol handler if they still exist on the server. +// Any messages that don't exist any more are deleted from the +// msgDB. +void nsPop3Sink::CheckPartialMessages(nsIPop3Protocol* protocol) { + uint32_t count = m_partialMsgsArray.Length(); + bool deleted = false; + + for (uint32_t i = 0; i < count; i++) { + partialRecord* partialMsg; + bool found = true; + partialMsg = m_partialMsgsArray.ElementAt(i); + protocol->CheckMessage(partialMsg->m_uidl.get(), &found); + if (!found && partialMsg->m_msgDBHdr) { + if (m_newMailParser) + m_newMailParser->m_mailDB->DeleteHeader(partialMsg->m_msgDBHdr, nullptr, + false, true); + deleted = true; + } + delete partialMsg; + } + m_partialMsgsArray.Clear(); + if (deleted) { + nsCOMPtr<nsIMsgLocalMailFolder> localFolder = do_QueryInterface(m_folder); + if (localFolder) localFolder->NotifyDelete(); + } +} + +nsresult nsPop3Sink::BeginMailDelivery(bool uidlDownload, + nsIMsgWindow* aMsgWindow, bool* aBool) { + nsresult rv; + nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(m_popServer); + if (!server) return NS_ERROR_UNEXPECTED; + + m_window = aMsgWindow; + + nsCOMPtr<nsIMsgAccountManager> acctMgr = + do_GetService("@mozilla.org/messenger/account-manager;1", &rv); + nsCOMPtr<nsIMsgAccount> account; + NS_ENSURE_SUCCESS(rv, rv); + acctMgr->FindAccountForServer(server, getter_AddRefs(account)); + if (account) account->GetKey(m_accountKey); + + bool isLocked; + nsCOMPtr<nsISupports> supports = + do_QueryInterface(static_cast<nsIPop3Sink*>(this)); + + NS_ENSURE_STATE(m_folder); + m_folder->GetLocked(&isLocked); + if (!isLocked) { + MOZ_LOG(POP3LOGMODULE, mozilla::LogLevel::Debug, + (POP3LOG("BeginMailDelivery acquiring semaphore"))); + m_folder->AcquireSemaphore(supports); + } else { + MOZ_LOG(POP3LOGMODULE, mozilla::LogLevel::Debug, + (POP3LOG("BeginMailDelivery folder locked"))); + return NS_MSG_FOLDER_BUSY; + } + m_uidlDownload = uidlDownload; + if (!uidlDownload) FindPartialMessages(); + + m_folder->GetNumNewMessages(false, &m_numNewMessagesInFolder); + +#ifdef DEBUG + printf("Begin mail message delivery.\n"); +#endif + nsCOMPtr<nsIPop3Service> pop3Service( + do_GetService("@mozilla.org/messenger/popservice;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + pop3Service->NotifyDownloadStarted(m_folder); + if (aBool) *aBool = true; + return NS_OK; +} + +nsresult nsPop3Sink::EndMailDelivery(nsIPop3Protocol* protocol) { + CheckPartialMessages(protocol); + + if (m_newMailParser) { + if (m_outFileStream) m_outFileStream->Flush(); // try this. + m_newMailParser->OnStopRequest(nullptr, NS_OK); + m_newMailParser->EndMsgDownload(); + } + if (m_outFileStream) { + m_outFileStream->Close(); + m_outFileStream = nullptr; + } + + // tell the parser to mark the db valid *after* closing the mailbox. + if (m_newMailParser) m_newMailParser->UpdateDBFolderInfo(); + + MOZ_LOG(POP3LOGMODULE, mozilla::LogLevel::Debug, + (POP3LOG("Calling ReleaseFolderLock from EndMailDelivery"))); + nsresult rv = ReleaseFolderLock(); + NS_ASSERTION(NS_SUCCEEDED(rv), "folder lock not released successfully"); + + bool filtersRun; + m_folder->CallFilterPlugins(nullptr, + &filtersRun); // ??? do we need msgWindow? + int32_t numNewMessagesInFolder; + // if filters have marked msgs read or deleted, the num new messages count + // will go negative by the number of messages marked read or deleted, + // so if we add that number to the number of msgs downloaded, that will give + // us the number of actual new messages. + m_folder->GetNumNewMessages(false, &numNewMessagesInFolder); + m_numNewMessages -= (m_numNewMessagesInFolder - numNewMessagesInFolder); + m_folder->SetNumNewMessages( + m_numNewMessages); // we'll adjust this for spam later + if (!filtersRun && m_numNewMessages > 0) { + nsCOMPtr<nsIMsgIncomingServer> server; + m_folder->GetServer(getter_AddRefs(server)); + if (server) { + server->SetPerformingBiff(true); + m_folder->SetBiffState(m_biffState); + server->SetPerformingBiff(false); + } + } + // note that size on disk has possibly changed. + nsCOMPtr<nsIMsgLocalMailFolder> localFolder = do_QueryInterface(m_folder); + if (localFolder) (void)localFolder->RefreshSizeOnDisk(); + nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(m_popServer); + if (server) { + nsCOMPtr<nsIMsgFilterList> filterList; + rv = server->GetFilterList(nullptr, getter_AddRefs(filterList)); + NS_ENSURE_SUCCESS(rv, rv); + + if (filterList) (void)filterList->FlushLogIfNecessary(); + } + + // fix for bug #161999 + // we should update the summary totals for the folder (inbox) + // in case it's not the open folder + m_folder->UpdateSummaryTotals(true); + + // check if the folder open in this window is not the current folder, and if + // it has new message, in which case we need to try to run the filter plugin. + if (m_newMailParser) { + nsCOMPtr<nsIMsgWindow> msgWindow; + m_newMailParser->GetMsgWindow(getter_AddRefs(msgWindow)); + // this breaks down if it's biff downloading new mail because + // there's no msgWindow... + if (msgWindow) { + nsCOMPtr<nsIMsgFolder> openFolder; + (void)msgWindow->GetOpenFolder(getter_AddRefs(openFolder)); + if (openFolder && openFolder != m_folder) { + // only call filter plugins if folder is a local folder, because only + // local folders get messages filtered into them synchronously by pop3. + nsCOMPtr<nsIMsgLocalMailFolder> localFolder = + do_QueryInterface(openFolder); + if (localFolder) { + bool hasNew, isLocked; + (void)openFolder->GetHasNewMessages(&hasNew); + if (hasNew) { + // if the open folder is locked, we shouldn't run the spam filters + // on it because someone is using the folder. see 218433. + // Ideally, the filter plugin code would try to grab the folder lock + // and hold onto it until done, but that's more difficult and I + // think this will actually fix the problem. + openFolder->GetLocked(&isLocked); + if (!isLocked) openFolder->CallFilterPlugins(nullptr, &filtersRun); + } + } + } + } + } +#ifdef DEBUG + printf("End mail message delivery.\n"); +#endif + nsCOMPtr<nsIPop3Service> pop3Service( + do_GetService("@mozilla.org/messenger/popservice;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + pop3Service->NotifyDownloadCompleted(m_folder, m_numNewMessages); + return NS_OK; +} + +nsresult nsPop3Sink::ReleaseFolderLock() { + nsresult result = NS_OK; + if (!m_folder) return result; + bool haveSemaphore; + nsCOMPtr<nsISupports> supports = + do_QueryInterface(static_cast<nsIPop3Sink*>(this)); + result = m_folder->TestSemaphore(supports, &haveSemaphore); + MOZ_LOG(POP3LOGMODULE, mozilla::LogLevel::Debug, + (POP3LOG("ReleaseFolderLock haveSemaphore = %s"), + haveSemaphore ? "TRUE" : "FALSE")); + + if (NS_SUCCEEDED(result) && haveSemaphore) + result = m_folder->ReleaseSemaphore(supports); + return result; +} + +nsresult nsPop3Sink::AbortMailDelivery(nsIPop3Protocol* protocol) { + CheckPartialMessages(protocol); + + // ### PS TODO - discard any new message? + + if (m_outFileStream) { + m_outFileStream->Close(); + m_outFileStream = nullptr; + } + + /* tell the parser to mark the db valid *after* closing the mailbox. + we have truncated the inbox, so berkeley mailbox and msf file are in sync*/ + if (m_newMailParser) m_newMailParser->UpdateDBFolderInfo(); + MOZ_LOG(POP3LOGMODULE, mozilla::LogLevel::Debug, + (POP3LOG("Calling ReleaseFolderLock from AbortMailDelivery"))); + + nsresult rv = ReleaseFolderLock(); + NS_ASSERTION(NS_SUCCEEDED(rv), "folder lock not released successfully"); + +#ifdef DEBUG + printf("Abort mail message delivery.\n"); +#endif + nsCOMPtr<nsIPop3Service> pop3Service( + do_GetService("@mozilla.org/messenger/popservice;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + pop3Service->NotifyDownloadCompleted(m_folder, 0); + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::IncorporateBegin(const char* uidlString, uint32_t flags) { +#ifdef DEBUG + printf("Incorporate message begin:\n"); + if (uidlString) printf("uidl string: %s\n", uidlString); +#endif + + nsresult rv; + nsCOMPtr<nsIMsgDBHdr> newHdr; + + nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(m_popServer); + if (!server) return NS_ERROR_UNEXPECTED; + + rv = server->GetMsgStore(getter_AddRefs(m_msgStore)); + NS_ENSURE_SUCCESS(rv, rv); + rv = m_msgStore->GetNewMsgOutputStream(m_folder, getter_AddRefs(newHdr), + getter_AddRefs(m_outFileStream)); + NS_ENSURE_SUCCESS(rv, rv); + + // create a new mail parser + if (!m_newMailParser) m_newMailParser = new nsParseNewMailState; + NS_ENSURE_TRUE(m_newMailParser, NS_ERROR_OUT_OF_MEMORY); + if (m_uidlDownload) m_newMailParser->DisableFilters(); + + nsCOMPtr<nsIMsgFolder> serverFolder; + rv = GetServerFolder(getter_AddRefs(serverFolder)); + if (NS_FAILED(rv)) return rv; + + rv = m_newMailParser->Init(serverFolder, m_folder, m_window, newHdr, + m_outFileStream); + // If we failed to initialize the parser, then just don't use it!!! + // We can still continue without one. + + if (NS_FAILED(rv)) { + m_newMailParser = nullptr; + rv = NS_OK; + } + + nsCString outputString(GetDummyEnvelope()); + rv = WriteLineToMailbox(outputString); + NS_ENSURE_SUCCESS(rv, rv); + // Write out account-key before UIDL so the code that looks for + // UIDL will find the account first and know it can stop looking + // once it finds the UIDL line. + if (!m_accountKey.IsEmpty()) { + outputString.AssignLiteral(HEADER_X_MOZILLA_ACCOUNT_KEY ": "); + outputString.Append(m_accountKey); + outputString.AppendLiteral(MSG_LINEBREAK); + rv = WriteLineToMailbox(outputString); + NS_ENSURE_SUCCESS(rv, rv); + } + if (uidlString) { + outputString.AssignLiteral("X-UIDL: "); + outputString.Append(uidlString); + outputString.AppendLiteral(MSG_LINEBREAK); + rv = WriteLineToMailbox(outputString); + NS_ENSURE_SUCCESS(rv, rv); + } + + // WriteLineToMailbox("X-Mozilla-Status: 8000" MSG_LINEBREAK); + char* statusLine = PR_smprintf(X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, flags); + outputString.Assign(statusLine); + rv = WriteLineToMailbox(outputString); + PR_smprintf_free(statusLine); + NS_ENSURE_SUCCESS(rv, rv); + + rv = WriteLineToMailbox("X-Mozilla-Status2: 00000000"_ns MSG_LINEBREAK); + NS_ENSURE_SUCCESS(rv, rv); + + // leave space for 60 bytes worth of keys/tags + rv = WriteLineToMailbox(nsLiteralCString(X_MOZILLA_KEYWORDS)); + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::SetPopServer(nsIPop3IncomingServer* server) { + m_popServer = server; + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::GetPopServer(nsIPop3IncomingServer** aServer) { + NS_ENSURE_ARG_POINTER(aServer); + NS_IF_ADDREF(*aServer = m_popServer); + return NS_OK; +} + +NS_IMETHODIMP nsPop3Sink::GetFolder(nsIMsgFolder** aFolder) { + NS_ENSURE_ARG_POINTER(aFolder); + NS_IF_ADDREF(*aFolder = m_folder); + return NS_OK; +} + +NS_IMETHODIMP nsPop3Sink::SetFolder(nsIMsgFolder* aFolder) { + m_folder = aFolder; + return NS_OK; +} + +nsresult nsPop3Sink::GetServerFolder(nsIMsgFolder** aFolder) { + NS_ENSURE_ARG_POINTER(aFolder); + + if (m_popServer) { + // not sure what this is used for - might be wrong if we have a deferred + // account. + nsCOMPtr<nsIMsgIncomingServer> incomingServer = + do_QueryInterface(m_popServer); + if (incomingServer) return incomingServer->GetRootFolder(aFolder); + } + *aFolder = nullptr; + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP nsPop3Sink::SetMsgsToDownload(uint32_t aNumMessages) { + m_numNewMessages = aNumMessages; + return NS_OK; +} + +char* nsPop3Sink::GetDummyEnvelope(void) { + static char result[75]; + char* ct; + time_t now = time((time_t*)0); +#if defined(XP_WIN) + if (now < 0 || now > 0x7FFFFFFF) now = 0x7FFFFFFF; +#endif + ct = ctime(&now); + PR_ASSERT(ct[24] == '\r' || ct[24] == '\n'); + ct[24] = 0; + /* This value must be in ctime() format, with English abbreviations. + strftime("... %c ...") is no good, because it is localized. */ + PL_strcpy(result, "From - "); + PL_strcpy(result + 7, ct); + PL_strcpy(result + 7 + 24, MSG_LINEBREAK); + return result; +} + +nsresult nsPop3Sink::IncorporateWrite(const char* block, int32_t length) { + m_outputBuffer.Truncate(); + if (!strncmp(block, "From ", 5)) m_outputBuffer.Assign('>'); + + m_outputBuffer.Append(block); + + return WriteLineToMailbox(m_outputBuffer); +} + +nsresult nsPop3Sink::WriteLineToMailbox(const nsACString& buffer) { + if (!buffer.IsEmpty()) { + uint32_t bufferLen = buffer.Length(); + if (m_newMailParser) + m_newMailParser->HandleLine(buffer.BeginReading(), bufferLen); + // The following (!m_outFileStream etc) was added to make sure that we don't + // write somewhere where for some reason or another we can't write to and + // lose the messages See bug 62480 + NS_ENSURE_TRUE(m_outFileStream, NS_ERROR_OUT_OF_MEMORY); + + // To remove seeking to the end for each line to be written, remove the + // following line. See bug 1116055 for details. +#define SEEK_TO_END +#ifdef SEEK_TO_END + // seek to the end in case someone else has sought elsewhere in our stream. + nsCOMPtr<nsISeekableStream> seekableOutStream = + do_QueryInterface(m_outFileStream); + + if (seekableOutStream) { + int64_t before_seek_pos; + nsresult rv2 = seekableOutStream->Tell(&before_seek_pos); + MOZ_ASSERT(NS_SUCCEEDED(rv2), + "seekableOutStream->Tell(&before_seek_pos) failed"); + + // XXX Handle error such as network error for remote file system. + seekableOutStream->Seek(nsISeekableStream::NS_SEEK_END, 0); + + int64_t after_seek_pos; + nsresult rv3 = seekableOutStream->Tell(&after_seek_pos); + MOZ_ASSERT(NS_SUCCEEDED(rv3), + "seekableOutStream->Tell(&after_seek_pos) failed"); + + if (NS_SUCCEEDED(rv2) && NS_SUCCEEDED(rv3)) { + if (before_seek_pos != after_seek_pos) { + nsString folderName; + if (m_folder) m_folder->GetPrettyName(folderName); + // This merits a console message, it's poor man's telemetry. + MsgLogToConsole4( + u"Unexpected file position change detected"_ns + + (folderName.IsEmpty() ? EmptyString() : u" in folder "_ns) + + (folderName.IsEmpty() ? EmptyString() : folderName) + + u". " + "If you can reliably reproduce this, please report the " + "steps you used to dev-apps-thunderbird@lists.mozilla.org " + "or to bug 1308335 at bugzilla.mozilla.org. " + "Resolving this problem will allow speeding up message " + "downloads."_ns, + NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, + nsIScriptError::errorFlag); +# ifdef DEBUG + // Debugging, see bug 1116055. + if (!folderName.IsEmpty()) { + fprintf(stderr, + "(seekdebug) WriteLineToMailbox() detected an unexpected " + "file position change in folder %s.\n", + NS_ConvertUTF16toUTF8(folderName).get()); + } else { + fprintf(stderr, + "(seekdebug) WriteLineToMailbox() detected an unexpected " + "file position change.\n"); + } + fprintf(stderr, + "(seekdebug) before_seek_pos=0x%016llx, " + "after_seek_pos=0x%016llx\n", + (long long unsigned int)before_seek_pos, + (long long unsigned int)after_seek_pos); +# endif + } + } + } +#endif + + uint32_t bytesWritten; + nsresult rv = + m_outFileStream->Write(buffer.BeginReading(), bufferLen, &bytesWritten); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(bytesWritten == bufferLen, NS_ERROR_FAILURE); + } + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::IncorporateComplete(nsIMsgWindow* aMsgWindow, int32_t aSize) { + if (m_buildMessageUri && !m_baseMessageUri.IsEmpty() && m_newMailParser && + m_newMailParser->m_newMsgHdr) { + nsMsgKey msgKey; + m_newMailParser->m_newMsgHdr->GetMessageKey(&msgKey); + m_messageUri.Truncate(); + nsBuildLocalMessageURI(m_baseMessageUri, msgKey, m_messageUri); + } + + nsresult rv = WriteLineToMailbox(nsLiteralCString(MSG_LINEBREAK)); + NS_ENSURE_SUCCESS(rv, rv); + bool leaveOnServer = false; + m_popServer->GetLeaveMessagesOnServer(&leaveOnServer); + // We need to flush the output stream, in case mail filters move + // the new message, which relies on all the data being flushed. + rv = + m_outFileStream->Flush(); // Make sure the message is written to the disk + NS_ENSURE_SUCCESS(rv, rv); + NS_ASSERTION(m_newMailParser, "could not get m_newMailParser"); + if (m_newMailParser) { + // PublishMsgHdr clears m_newMsgHdr, so we need a comptr to + // hold onto it. + nsCOMPtr<nsIMsgDBHdr> hdr = m_newMailParser->m_newMsgHdr; + NS_ASSERTION(hdr, "m_newMailParser->m_newMsgHdr wasn't set"); + if (!hdr) return NS_ERROR_FAILURE; + + nsCOMPtr<nsIMsgLocalMailFolder> localFolder = do_QueryInterface(m_folder); + + // If a header already exists for this message (for example, when + // getting a complete message when a partial exists), then update the new + // header from the old. + nsCOMPtr<nsIMsgDBHdr> oldMsgHdr; + if (!m_origMessageUri.IsEmpty() && localFolder) { + rv = GetMsgDBHdrFromURI(m_origMessageUri, getter_AddRefs(oldMsgHdr)); + if (NS_SUCCEEDED(rv) && oldMsgHdr) { + localFolder->UpdateNewMsgHdr(oldMsgHdr, hdr); + } + } + m_msgStore->FinishNewMessage(m_outFileStream, hdr); + m_newMailParser->PublishMsgHeader(aMsgWindow); + m_newMailParser->ApplyForwardAndReplyFilter(aMsgWindow); + if (aSize) hdr->SetUint32Property("onlineSize", aSize); + + if (oldMsgHdr) { + // We had the partial message, but got the full now. + nsCOMPtr<nsIMsgFolder> oldMsgFolder; + rv = oldMsgHdr->GetFolder(getter_AddRefs(oldMsgFolder)); + NS_ENSURE_SUCCESS(rv, rv); + nsCString oldURI; + rv = oldMsgFolder->GetUriForMsg(oldMsgHdr, oldURI); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMsgFolder> newMsgFolder; + rv = hdr->GetFolder(getter_AddRefs(newMsgFolder)); + NS_ENSURE_SUCCESS(rv, rv); + nsCString newURI; + rv = newMsgFolder->GetUriForMsg(hdr, newURI); + NS_ENSURE_SUCCESS(rv, rv); + + // Delete old header before notifying. + nsCOMPtr<nsIMsgDatabase> db; + rv = m_folder->GetMsgDatabase(getter_AddRefs(db)); + NS_ENSURE_SUCCESS(rv, rv); + rv = db->DeleteHeader(oldMsgHdr, nullptr, false, true); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIObserverService> obsServ = + mozilla::services::GetObserverService(); + nsCOMPtr<nsISupportsString> origUri = + do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + origUri->SetData(NS_ConvertUTF8toUTF16(oldURI)); + obsServ->NotifyObservers(origUri, "message-content-updated", + NS_ConvertUTF8toUTF16(newURI).get()); + } + } + } + +#ifdef DEBUG + printf("Incorporate message complete.\n"); +#endif + nsCOMPtr<nsIPop3Service> pop3Service( + do_GetService("@mozilla.org/messenger/popservice;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + pop3Service->NotifyDownloadProgress(m_folder, ++m_numMsgsDownloaded, + m_numNewMessages); + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::IncorporateAbort(bool uidlDownload) { + NS_ENSURE_STATE(m_outFileStream); + nsresult rv = m_outFileStream->Close(); + NS_ENSURE_SUCCESS(rv, rv); + if (m_msgStore && m_newMailParser && m_newMailParser->m_newMsgHdr) { + m_msgStore->DiscardNewMessage(m_outFileStream, + m_newMailParser->m_newMsgHdr); + } +#ifdef DEBUG + printf("Incorporate message abort.\n"); +#endif + return rv; +} + +nsresult nsPop3Sink::SetBiffStateAndUpdateFE(uint32_t aBiffState, + int32_t numNewMessages, + bool notify) { + m_biffState = aBiffState; + if (m_newMailParser) numNewMessages -= m_newMailParser->m_numNotNewMessages; + + if (notify && m_folder && numNewMessages > 0 && + numNewMessages != m_numNewMessages && + aBiffState == nsIMsgFolder::nsMsgBiffState_NewMail) { + m_folder->SetNumNewMessages(numNewMessages); + m_folder->SetBiffState(aBiffState); + } + m_numNewMessages = numNewMessages; + + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::GetBuildMessageUri(bool* bVal) { + NS_ENSURE_ARG_POINTER(bVal); + *bVal = m_buildMessageUri; + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::SetBuildMessageUri(bool bVal) { + m_buildMessageUri = bVal; + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::GetMessageUri(nsACString& messageUri) { + NS_ENSURE_TRUE(!m_messageUri.IsEmpty(), NS_ERROR_FAILURE); + messageUri = m_messageUri; + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::SetMessageUri(const nsACString& messageUri) { + m_messageUri = messageUri; + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::GetBaseMessageUri(nsACString& baseMessageUri) { + NS_ENSURE_TRUE(!m_baseMessageUri.IsEmpty(), NS_ERROR_FAILURE); + baseMessageUri = m_baseMessageUri; + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::SetBaseMessageUri(const nsACString& baseMessageUri) { + m_baseMessageUri = baseMessageUri; + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::GetOrigMessageUri(nsACString& aOrigMessageUri) { + aOrigMessageUri.Assign(m_origMessageUri); + return NS_OK; +} + +NS_IMETHODIMP +nsPop3Sink::SetOrigMessageUri(const nsACString& aOrigMessageUri) { + m_origMessageUri.Assign(aOrigMessageUri); + return NS_OK; +} |