NS_IMETHODIMP
nsFolderCompactState::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
                                    nsresult status)
{
  nsCOMPtr<nsIMsgDBHdr> msgHdr;
  nsCOMPtr<nsIMsgDBHdr> newMsgHdr;
  if (NS_FAILED(status))
  {
    m_status = status; // set the m_status to status so the destructor can remove the
                       // temp folder and database
    m_folder->NotifyCompactCompleted();
    ReleaseFolderLock();
  }
  else
  {
    EndCopy(nsnull, status);
    if (m_curIndex >= m_size)
    {
      msgHdr = nsnull;
      newMsgHdr = nsnull;
      // no more to copy finish it up
      FinishCompact();
    }
    else
    {
      // in case we're not getting an error, we still need to pretend we did get an error,
      // because the compact did not successfully complete.
      m_folder->NotifyCompactCompleted();
      CleanupTempFilesAfterError();
      ReleaseFolderLock();
    }
  }
  Release(); // kill self
  return status;
}
nsresult nsOfflineStoreCompactState::StartCompacting()
{
  nsresult rv = NS_OK;
  if (m_size > 0 && m_curIndex == 0)
  {
    AddRef(); // we own ourselves, until we're done, anyway.
    ShowCompactingStatusMsg();
    bool done = false;
    rv = CopyNextMessage(done);
    if (!done)
      return rv;
  }
  ReleaseFolderLock();
  FinishCompact();
  return rv;
}
nsresult nsFolderCompactState::StartCompacting()
{
  nsCOMPtr<nsIMsgPluggableStore> msgStore;
  nsCOMPtr<nsIMsgIncomingServer> server;
  
  nsresult rv = m_folder->GetServer(getter_AddRefs(server));
  NS_ENSURE_SUCCESS(rv, rv);
  rv = server->GetMsgStore(getter_AddRefs(msgStore));
  NS_ENSURE_SUCCESS(rv, rv);
  
  // Notify that compaction is beginning.  We do this even if there are no
  // messages to be copied because the summary database still gets blown away
  // which is still pretty interesting.  (And we like consistency.)
  nsCOMPtr<nsIMsgFolderNotificationService>
    notifier(do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID));
  if (notifier)
    notifier->NotifyItemEvent(m_folder,
                              NS_LITERAL_CSTRING("FolderCompactStart"),
                              nullptr);

  // TODO: test whether sorting the messages (m_keyArray) by messageOffset
  // would improve performance on large files (less seeks).
  // The m_keyArray is in the order as stored in DB and on IMAP or News
  // the messages stored on the mbox file are not necessarily in the same order.
  if (m_size > 0)
  {
    nsCOMPtr<nsIURI> notUsed;
    ShowCompactingStatusMsg();
    AddRef();
    rv = m_messageService->CopyMessages(m_size, m_keyArray->m_keys.Elements(),
                                        m_folder, this,
                                        false, nullptr, m_window,
                                        getter_AddRefs(notUsed));
  }
  else
  { // no messages to copy with
    FinishCompact();
//    Release(); // we don't "own" ourselves yet.
  }
  return rv;
}
nsresult nsFolderCompactState::StartCompacting()
{
  nsCOMPtr<nsIMsgPluggableStore> msgStore;
  nsCOMPtr<nsIMsgIncomingServer> server;
  
  nsresult rv = m_folder->GetServer(getter_AddRefs(server));
  NS_ENSURE_SUCCESS(rv, rv);
  rv = server->GetMsgStore(getter_AddRefs(msgStore));
  NS_ENSURE_SUCCESS(rv, rv);
  
  // Notify that compaction is beginning.  We do this even if there are no
  // messages to be copied because the summary database still gets blown away
  // which is still pretty interesting.  (And we like consistency.)
  nsCOMPtr<nsIMsgFolderNotificationService>
    notifier(do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID));
  if (notifier)
    notifier->NotifyItemEvent(m_folder,
                              NS_LITERAL_CSTRING("FolderCompactStart"),
                              nsnull);
  if (m_size > 0)
  {
    nsCOMPtr<nsIURI> notUsed;
    ShowCompactingStatusMsg();
    AddRef();
    rv = m_messageService->CopyMessages(m_size, m_keyArray->m_keys.Elements(),
                                        m_folder, this,
                                        false, nsnull, m_window,
                                        getter_AddRefs(notUsed));
  }
  else
  { // no messages to copy with
    FinishCompact();
//    Release(); // we don't "own" ourselves yet.
  }
  return rv;
}
NS_IMETHODIMP
nsOfflineStoreCompactState::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
                                          nsresult status)
{
  nsresult rv = status;
  nsCOMPtr<nsIURI> uri;
  nsCOMPtr<nsIMsgDBHdr> msgHdr;
  nsCOMPtr<nsIMsgDBHdr> newMsgHdr;
  nsCOMPtr <nsIMsgStatusFeedback> statusFeedback;
  bool done = false;

  // The NS_MSG_ERROR_MSG_NOT_OFFLINE error should allow us to continue, so we
  // check for it specifically and don't terminate the compaction.
  if (NS_FAILED(rv) && rv != NS_MSG_ERROR_MSG_NOT_OFFLINE)
    goto done;
  uri = do_QueryInterface(ctxt, &rv);
  if (NS_FAILED(rv)) goto done;
  rv = GetMessage(getter_AddRefs(msgHdr));
  if (NS_FAILED(rv)) goto done;

  if (msgHdr)
  {
    if (NS_SUCCEEDED(status))
    {
      msgHdr->SetMessageOffset(m_startOfNewMsg);
      char storeToken[100];
      PR_snprintf(storeToken, sizeof(storeToken), "%lld", m_startOfNewMsg);
      msgHdr->SetStringProperty("storeToken", storeToken);
      msgHdr->SetOfflineMessageSize(m_offlineMsgSize);
    }
    else
    {
      PRUint32 resultFlags;
      msgHdr->AndFlags(~nsMsgMessageFlags::Offline, &resultFlags);
    }
  }

  if (m_window)
  {
    m_window->GetStatusFeedback(getter_AddRefs(statusFeedback));
    if (statusFeedback)
      statusFeedback->ShowProgress (100 * m_curIndex / m_size);
  }
    // advance to next message 
  m_curIndex++;
  rv = CopyNextMessage(done);
  if (done)
  {
    m_db->Commit(nsMsgDBCommitType::kCompressCommit);
    msgHdr = nsnull;
    newMsgHdr = nsnull;
    // no more to copy finish it up
    ReleaseFolderLock();
    FinishCompact();
    Release(); // kill self
  }

done:
  if (NS_FAILED(rv)) {
    m_status = rv; // set the status to rv so the destructor can remove the
                   // temp folder and database
    ReleaseFolderLock();
    Release(); // kill self
    return rv;
  }
  return rv;
}