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(NS_MSGACCOUNTMANAGER_CONTRACTID, &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));
  m_folder->GetLocked(&isLocked);
  if(!isLocked)
  {
    PR_LOG(POP3LOGMODULE, PR_LOG_MAX, ("BeginMailDelivery acquiring semaphore"));
    m_folder->AcquireSemaphore(supports);
  }
  else
  {
    PR_LOG(POP3LOGMODULE, PR_LOG_MAX, ("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(NS_POP3SERVICE_CONTRACTID1, &rv));
  NS_ENSURE_SUCCESS(rv, rv);
  pop3Service->NotifyDownloadStarted(m_folder);
  if (aBool)
    *aBool = true;
  return NS_OK;
}
nsresult
nsPop3Sink::AbortMailDelivery(nsIPop3Protocol *protocol)
{
  CheckPartialMessages(protocol);

  // ### PS TODO - discard any new message?

  if (m_outFileStream)
  {
    m_outFileStream->Close();
    m_outFileStream = 0;
  }
  if (m_inboxOutputStream)
  {
    m_inboxOutputStream->Close();
    m_inboxOutputStream = nullptr;
  }

  if (m_downloadingToTempFile && m_tmpDownloadFile)
    m_tmpDownloadFile->Remove(false);

  /* 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();
  PR_LOG(POP3LOGMODULE, PR_LOG_MAX, ("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(NS_POP3SERVICE_CONTRACTID1, &rv));
  NS_ENSURE_SUCCESS(rv, rv);
  pop3Service->NotifyDownloadCompleted(m_folder, 0);
  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.get(), msgKey, m_messageUri);
  }

  nsresult rv = WriteLineToMailbox(NS_LITERAL_CSTRING(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);
    bool doSelect = false;

    // aSize is only set for partial messages. For full messages,
    // check to see if we're replacing an old partial message.
    if (!aSize && localFolder)
      (void) localFolder->DeleteDownloadMsg(hdr, &doSelect);

    // 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.
    if (!m_origMessageUri.IsEmpty() && localFolder)
    {
      nsCOMPtr <nsIMsgDBHdr> oldMsgHdr;
      rv = GetMsgDBHdrFromURI(m_origMessageUri.get(), getter_AddRefs(oldMsgHdr));
      if (NS_SUCCEEDED(rv) && oldMsgHdr)
        localFolder->UpdateNewMsgHdr(oldMsgHdr, hdr);
    }

    if (m_downloadingToTempFile)
    {
      // close file to give virus checkers a chance to do their thing...
      m_outFileStream->Flush();
      m_outFileStream->Close();
      m_newMailParser->FinishHeader();
      // need to re-open the inbox file stream.
      bool exists;
      m_tmpDownloadFile->Exists(&exists);
      if (!exists)
        return HandleTempDownloadFailed(aMsgWindow);

      nsCOMPtr <nsIInputStream> inboxInputStream = do_QueryInterface(m_outFileStream);
      rv = MsgReopenFileStream(m_tmpDownloadFile, inboxInputStream);
      NS_ENSURE_SUCCESS(rv, HandleTempDownloadFailed(aMsgWindow));
      if (m_outFileStream)
      {
        int64_t tmpDownloadFileSize;
        uint32_t msgSize;
        hdr->GetMessageSize(&msgSize);
        // we need to clone because nsLocalFileUnix caches its stat result,
        // so it doesn't realize the file has changed size.
        nsCOMPtr <nsIFile> tmpClone;
        rv = m_tmpDownloadFile->Clone(getter_AddRefs(tmpClone));
        NS_ENSURE_SUCCESS(rv, rv);
        tmpClone->GetFileSize(&tmpDownloadFileSize);

        if (msgSize > tmpDownloadFileSize)
          rv = NS_MSG_ERROR_WRITING_MAIL_FOLDER;
        else
          rv = m_newMailParser->AppendMsgFromStream(inboxInputStream, hdr,
                                                    msgSize, m_folder);
        if (NS_FAILED(rv))
          return HandleTempDownloadFailed(aMsgWindow);

        m_outFileStream->Close(); // close so we can truncate.
        m_tmpDownloadFile->SetFileSize(0);
      }
      else
      {
          return HandleTempDownloadFailed(aMsgWindow);
        // need to give an error here.
      }
    }
    else
    {
      m_msgStore->FinishNewMessage(m_outFileStream, hdr);
    }
    m_newMailParser->PublishMsgHeader(aMsgWindow);
    // run any reply/forward filter after we've finished with the
    // temp quarantine file, and/or moved the message to another folder.
    m_newMailParser->ApplyForwardAndReplyFilter(aMsgWindow);
    if (aSize)
      hdr->SetUint32Property("onlineSize", aSize);

    // if DeleteDownloadMsg requested it, select the new message
    else if (doSelect)
      (void) localFolder->SelectDownloadMsg();
  }

#ifdef DEBUG
  printf("Incorporate message complete.\n");
#endif
  nsCOMPtr<nsIPop3Service> pop3Service(do_GetService(NS_POP3SERVICE_CONTRACTID1, &rv));
  NS_ENSURE_SUCCESS(rv, rv);
  pop3Service->NotifyDownloadProgress(m_folder, ++m_numMsgsDownloaded, m_numNewMessages);
  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, nullptr, NS_OK);
    m_newMailParser->EndMsgDownload();
  }
  if (m_outFileStream)
  {
    m_outFileStream->Close();
    m_outFileStream = 0;
  }

  if (m_downloadingToTempFile)
    m_tmpDownloadFile->Remove(false);

  // 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(NS_POP3SERVICE_CONTRACTID1, &rv));
  NS_ENSURE_SUCCESS(rv, rv);
  pop3Service->NotifyDownloadCompleted(m_folder, m_numNewMessages);
  return NS_OK;
}