summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/local/src/nsPop3Sink.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/local/src/nsPop3Sink.cpp')
-rw-r--r--comm/mailnews/local/src/nsPop3Sink.cpp740
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;
+}