nsresult nsEudoraCompose::ReadHeaders( ReadFileState *pState, SimpleBufferTonyRCopiedOnce& copy, SimpleBufferTonyRCopiedOnce& header)
{
  // This should be the headers...
  header.m_writeOffset = 0;

  nsresult rv;
  PRInt32 lineLen;
  PRInt32 endLen = -1;
  PRInt8 endBuffer = 0;

  while ((endLen = IsEndHeaders( copy)) == -1) {
    while ((lineLen = FindNextEndLine( copy)) == -1) {
      copy.m_writeOffset = copy.m_bytesInBuf;
      if (!header.Write( copy.m_pBuffer, copy.m_writeOffset)) {
        IMPORT_LOG0( "*** ERROR, writing headers\n");
        return( NS_ERROR_FAILURE);
      }
      if (NS_FAILED( rv = FillMailBuffer( pState, copy))) {
        IMPORT_LOG0( "*** Error reading message headers\n");
        return( rv);
      }
      if (!copy.m_bytesInBuf) {
        IMPORT_LOG0( "*** Error, end of file while reading headers\n");
        return( NS_ERROR_FAILURE);
      }
    }
    copy.m_writeOffset += lineLen;
    if ((copy.m_writeOffset + 4) >= copy.m_bytesInBuf) {
      if (!header.Write( copy.m_pBuffer, copy.m_writeOffset)) {
        IMPORT_LOG0( "*** ERROR, writing headers 2\n");
        return( NS_ERROR_FAILURE);
      }
      if (NS_FAILED( rv = FillMailBuffer( pState, copy))) {
        IMPORT_LOG0( "*** Error reading message headers 2\n");
        return( rv);
      }
    }
  }

  if (!header.Write( copy.m_pBuffer, copy.m_writeOffset)) {
    IMPORT_LOG0( "*** Error writing final headers\n");
    return( NS_ERROR_FAILURE);
  }
  if (!header.Write( (const char *)&endBuffer, 1)) {
    IMPORT_LOG0( "*** Error writing header trailing null\n");
    return( NS_ERROR_FAILURE);
  }

  copy.m_writeOffset += endLen;

  return( NS_OK);
}
PRBool nsEudoraWin32::ImportSettings( nsIFile *pIniFile, nsIMsgAccount **localMailAccount)
{
  PRBool    result = PR_FALSE;
  nsresult  rv;

  nsCOMPtr<nsIMsgAccountManager> accMgr =
           do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
  if (NS_FAILED(rv))
  {
    IMPORT_LOG0( "*** Failed to create a account manager!\n");
    return( PR_FALSE);
  }

  // Eudora info is arranged by key, 1 for the default, then persona's for additional
  // accounts.
  // Start with the first one, then do each persona
  nsCString iniPath;
  pIniFile->GetNativePath(iniPath);
  if (iniPath.IsEmpty())
    return( PR_FALSE);
  UINT       valInt;
  SimpleBufferTonyRCopiedOnce  section;
  DWORD      sSize;
  DWORD      sOffset = 0;
  DWORD      start;
  nsCString  sectionName("Settings");
  int        popCount = 0;
  int        accounts = 0;

  DWORD  allocSize = 0;
  do
  {
    allocSize += 2048;
    section.Allocate( allocSize);
    sSize = ::GetPrivateProfileSection( "Personalities", section.m_pBuffer, allocSize, iniPath.get());
  } while (sSize == (allocSize - 2));

  nsIMsgAccount *  pAccount;

  do
  {
    if (!sectionName.IsEmpty())
    {
      pAccount = nsnull;
      valInt = ::GetPrivateProfileInt( sectionName.get(), "UsesPOP", 1, iniPath.get());
      if (valInt)
      {
        // This is a POP account
        if (BuildPOPAccount( accMgr, sectionName.get(), iniPath.get(), &pAccount))
        {
          accounts++;
          popCount++;
          if (popCount > 1)
          {
            if (localMailAccount && *localMailAccount)
            {
              NS_RELEASE( *localMailAccount);
              *localMailAccount = nsnull;
            }
          }
          else
          {
            if (localMailAccount)
            {
              *localMailAccount = pAccount;
              NS_IF_ADDREF( pAccount);
            }
          }
        }
      }
      else
      {
        valInt = ::GetPrivateProfileInt( sectionName.get(), "UsesIMAP", 0, iniPath.get());
        if (valInt)
        {
          // This is an IMAP account
          if (BuildIMAPAccount( accMgr, sectionName.get(), iniPath.get(), &pAccount))
            accounts++;
        }
      }
      if (pAccount && (sOffset == 0))
        accMgr->SetDefaultAccount( pAccount);

      NS_IF_RELEASE( pAccount);
    }

    sectionName.Truncate();
    while ((sOffset < sSize) && (section.m_pBuffer[sOffset] != '='))
      sOffset++;
    sOffset++;
    start = sOffset;
    while ((sOffset < sSize) && (section.m_pBuffer[sOffset] != 0))
      sOffset++;
    if (sOffset > start)
    {
      sectionName.Append( section.m_pBuffer + start, sOffset - start);
      sectionName.Trim( kWhitespace);
    }

  } while (sOffset < sSize);

  // Now save the new acct info to pref file.
  rv = accMgr->SaveAccountInfo();
  NS_ASSERTION(NS_SUCCEEDED(rv), "Can't save account info to pref file");


  return( accounts != 0);
}
nsresult nsEudoraMailbox::ReadNextMessage(ReadFileState *pState, SimpleBufferTonyRCopiedOnce& copy,
                                          SimpleBufferTonyRCopiedOnce& header, SimpleBufferTonyRCopiedOnce& body,
                                          nsCString& defaultDate, nsCString& bodyType, EudoraTOCEntry *pTocEntry)
{
  header.m_writeOffset = 0;
  body.m_writeOffset = 0;

  nsresult    rv;
  int32_t      lineLen;
  char      endBuffer = 0;

  lineLen = -1;
  // Find the from separator - we should actually be positioned at the
  // from separator, but for now, we'll verify this.
  while (lineLen == -1) {
    if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
      IMPORT_LOG0("*** Error, FillMailBuffer FAILED in ReadNextMessage\n");
      return rv;
    }
    lineLen = IsEudoraFromSeparator(copy.m_pBuffer + copy.m_writeOffset, copy.m_bytesInBuf - copy.m_writeOffset, defaultDate);

    if (lineLen == -1) {
      while ((lineLen = FindStartLine(copy)) == -1) {
        copy.m_writeOffset = copy.m_bytesInBuf;
        if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
          IMPORT_LOG0("*** Error, FillMailBuffer FAILED in ReadNextMessage, looking for next start line\n");
          return rv;
        }
        if (!copy.m_bytesInBuf) {
          IMPORT_LOG0("*** Error, ReadNextMessage, looking for start of next line, got end of file.\n");
          return NS_ERROR_FAILURE;
        }
      }
      copy.m_writeOffset += lineLen;
      lineLen = -1;
    }
  }

  // Skip past the from line separator
  while ((lineLen = FindStartLine(copy)) == -1) {
    copy.m_writeOffset = copy.m_bytesInBuf;
    if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
      IMPORT_LOG0("*** Error, ReadNextMessage, FillMailBuffer failed looking for from sep\n");
      return rv;
    }
    if (!copy.m_bytesInBuf) {
      IMPORT_LOG0("*** Error, ReadNextMessage, end of file looking for from sep\n");
      return NS_ERROR_FAILURE;
    }
  }
  copy.m_writeOffset += lineLen;
  if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
    IMPORT_LOG0("*** Error, Unable to fill mail buffer after from sep.\n");
    return rv;
  }

  // This should be the headers...
  int32_t endLen = -1;
  while ((endLen = IsEndHeaders(copy)) == -1) {
    while ((lineLen = FindNextEndLine(copy)) == -1) {
      copy.m_writeOffset = copy.m_bytesInBuf;
      if (!header.Write(copy.m_pBuffer, copy.m_writeOffset)) {
        IMPORT_LOG0("*** ERROR, writing headers\n");
        return NS_ERROR_FAILURE;
      }
      if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
        IMPORT_LOG0("*** Error reading message headers\n");
        return rv;
      }
      if (!copy.m_bytesInBuf) {
        IMPORT_LOG0("*** Error, end of file while reading headers\n");
        return NS_ERROR_FAILURE;
      }
    }
    copy.m_writeOffset += lineLen;
    if ((copy.m_writeOffset + 4) >= copy.m_bytesInBuf) {
      if (!header.Write(copy.m_pBuffer, copy.m_writeOffset)) {
        IMPORT_LOG0("*** ERROR, writing headers 2\n");
        return NS_ERROR_FAILURE;
      }
      if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
        IMPORT_LOG0("*** Error reading message headers 2\n");
        return rv;
      }
    }
  }

  if (!header.Write(copy.m_pBuffer, copy.m_writeOffset)) {
    IMPORT_LOG0("*** Error writing final headers\n");
    return NS_ERROR_FAILURE;
  }

  if (pTocEntry) {
    // This is not the prettiest spot to stick this code, but it works and it was convenient.
    char    header_str[128];

    // Write X-Mozilla-Status header
    PR_snprintf(header_str, 128, MSG_LINEBREAK X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, pTocEntry->GetMozillaStatusFlags());
    header.Write(header_str, strlen(header_str));

    // Write X-Mozilla-Status2 header
    PR_snprintf(header_str, 128, X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, pTocEntry->GetMozillaStatus2Flags());
    header.Write(header_str, strlen(header_str));

    // Format and write X-Mozilla-Keys header
    nsCString  keywordHdr(X_MOZILLA_KEYWORDS);
    if (pTocEntry->HasEudoraLabel()) {
      PR_snprintf(header_str, 128, "eudoralabel%d", pTocEntry->GetLabelNumber());
      keywordHdr.Replace(sizeof(HEADER_X_MOZILLA_KEYWORDS) + 1, strlen(header_str), header_str);
    }
    header.Write(keywordHdr.get(), keywordHdr.Length());
  }

  if (!header.Write(&endBuffer, 1)) {
    IMPORT_LOG0("*** Error writing header trailing null\n");
    return NS_ERROR_FAILURE;
  }

  copy.m_writeOffset += endLen;
  if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
    IMPORT_LOG0("*** Error reading beginning of message body\n");
    return rv;
  }

  EmptyAttachments();

  // Get the body!
  // Read one line at a time here and look for the next separator
  nsCString tmp;
  bool insideEudoraTags = false;
  // by default we consider the body text to be plain text
  bodyType = "text/plain";

  while ((lineLen = IsEudoraFromSeparator(copy.m_pBuffer + copy.m_writeOffset, copy.m_bytesInBuf - copy.m_writeOffset, tmp)) == -1) {
    int32_t tagLength = 0;
    if (IsEudoraTag (copy.m_pBuffer + copy.m_writeOffset, copy.m_bytesInBuf - copy.m_writeOffset, insideEudoraTags, bodyType, tagLength)) {
      // We don't want to keep eudora tags so skip over them.

      // let's write the previous text
      if (!body.Write(copy.m_pBuffer, copy.m_writeOffset)) {
        IMPORT_LOG0("*** Error writing to message body\n");
        return NS_ERROR_FAILURE;
      }

      // we want to skip over the tag...for now we are assuming the tag is always at the start of line.
      copy.m_writeOffset += tagLength;
        if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
          IMPORT_LOG0("*** Error reading message body\n");
          return rv;
        }

      if (!copy.m_bytesInBuf)
        break;

      continue;
    }

    // Eudora Attachment lines are always outside Eudora Tags
    // so we shouldn't try to find one here
    if (!insideEudoraTags) {
    // Debatable is whether or not to exclude these lines from the
    // text of the message, I prefer not to in case the original
    // attachment is actually missing.
    rv = ExamineAttachment(copy);
    if (NS_FAILED(rv)) {
      IMPORT_LOG0("*** Error examining attachment line\n");
      return rv;
    }
    }

    while (((lineLen = FindStartLine(copy)) == -1) && copy.m_bytesInBuf) {
      copy.m_writeOffset = copy.m_bytesInBuf;
      if (!body.Write(copy.m_pBuffer, copy.m_writeOffset)) {
        IMPORT_LOG0("*** Error writing to message body\n");
        return NS_ERROR_FAILURE;
      }
      if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
        IMPORT_LOG0("*** Error reading message body\n");
        return rv;
      }
    }
    if (!copy.m_bytesInBuf)
      break;

    copy.m_writeOffset += lineLen;

    // found the start of the next line
    // make sure it's long enough to check for the from line
    if ((copy.m_writeOffset + 2048) >= copy.m_bytesInBuf) {
      if (!body.Write(copy.m_pBuffer, copy.m_writeOffset)) {
        IMPORT_LOG0("*** Error writing to message body 2\n");
        return NS_ERROR_FAILURE;
      }
      if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
        IMPORT_LOG0("*** Error reading message body 2\n");
        return rv;
      }
    }
  }

  // the start of the current line is a from, we-re done
  if (!body.Write(copy.m_pBuffer, copy.m_writeOffset)) {
    IMPORT_LOG0("*** Error writing final message body\n");
    return NS_ERROR_FAILURE;
  }
  if (!body.Write(&endBuffer, 1)) {
    IMPORT_LOG0("*** Error writing body trailing null\n");
    IMPORT_LOG2("\tbody.m_size: %ld, body.m_writeOffset: %ld\n", body.m_size, body.m_writeOffset);
    return NS_ERROR_FAILURE;
  }
  if (NS_FAILED(rv = FillMailBuffer(pState, copy))) {
    IMPORT_LOG0("*** Error filling mail buffer for next read message\n");
    return rv;
  }

  return NS_OK;
}
nsresult nsEudoraMailbox::ImportMessage(
  SimpleBufferTonyRCopiedOnce &headers,
  SimpleBufferTonyRCopiedOnce &body,
  nsCString& defaultDate,
  nsAutoCString& bodyType,
  nsIOutputStream *pDst,
  int32_t  *pMsgCount)
{
  nsresult rv = NS_OK;
  uint32_t written = 0;
  nsEudoraCompose compose;

  // Unfortunately Eudora stores HTML messages in the sent folder
  // without any content type header at all. If the first line of the message body is <html>
  // then mark the message as html internally...See Bug #258489
  if (body.m_pBuffer && (body.m_writeOffset > (int32_t)strlen(kHTMLTag)) && (strncmp(body.m_pBuffer, kHTMLTag, strlen(kHTMLTag)) == 0))
    bodyType = "text/html"; // ignore whatever body type we were given...force html

  compose.SetBody(body.m_pBuffer, body.m_writeOffset - 1, bodyType);
  compose.SetHeaders(headers.m_pBuffer, headers.m_writeOffset - 1);
  compose.SetAttachments(&m_attachments);
  compose.SetDefaultDate(defaultDate);

        nsCOMPtr <nsIFile> compositionFile;
  rv = compose.SendTheMessage(m_mailImportLocation, getter_AddRefs(compositionFile));
  if (NS_SUCCEEDED(rv)) {
    nsCString            fromLine(eudoraFromLine);
    SimpleBufferTonyRCopiedOnce    copy;

    copy.Allocate(kCopyBufferSize);

    /* IMPORT_LOG0("Composed message in file: "); DUMP_FILENAME(compositionFile, true); */
    // copy the resulting file into the destination file!
    rv = compose.CopyComposedMessage(fromLine, compositionFile, pDst, copy);
    DeleteFile(compositionFile);
    if (NS_FAILED(rv))
      IMPORT_LOG0("*** Error copying composed message to destination mailbox\n");
    if (pMsgCount)
      (*pMsgCount)++;
  }
  else {
    IMPORT_LOG0("*** Error composing message, writing raw message\n");
    rv = WriteFromSep(pDst);

    rv = pDst->Write(kComposeErrorStr, strlen(kComposeErrorStr), &written);

    if (NS_SUCCEEDED(rv))
      rv = pDst->Write(headers.m_pBuffer, headers.m_writeOffset - 1, &written);
    if (NS_SUCCEEDED(rv) && (written == (headers.m_writeOffset - 1)))
      rv = pDst->Write("\x0D\x0A" "\x0D\x0A", 4, &written);
    if (NS_SUCCEEDED(rv) && (written == 4))
      rv = pDst->Write(body.m_pBuffer, body.m_writeOffset - 1, &written);
    if (NS_SUCCEEDED(rv) && (written == (body.m_writeOffset - 1))) {
      rv = pDst->Write("\x0D\x0A", 2, &written);
      if (written != 2)
        rv = NS_ERROR_FAILURE;
    }

    if (NS_FAILED(rv))
      IMPORT_LOG0("*** Error writing to destination mailbox\n");
  }

  return rv;
}
nsresult nsEudoraMailbox::ImportMailboxUsingTOC(
  uint32_t *pBytes,
  bool *pAbort,
  nsIInputStream *pInputStream,
  nsIFile *tocFile,
  nsIMsgFolder *dstFolder,
  int32_t *pMsgCount)
{
  nsresult        rv = NS_OK;

  int64_t  mailSize = m_mailSize;
  int64_t  tocSize = 0;
  uint32_t  saveBytes = pBytes ? *pBytes : 0;
  nsCOMPtr <nsIInputStream> tocInputStream;

  rv = tocFile->GetFileSize(&tocSize);

  // if the index or the mail file is empty then just
  // use the original mail file.
  if (!mailSize || !tocSize)
    return NS_ERROR_FAILURE;
  rv = NS_NewLocalFileInputStream(getter_AddRefs(tocInputStream), tocFile);
  NS_ENSURE_SUCCESS(rv, rv);

  SimpleBufferTonyRCopiedOnce readBuffer;
  SimpleBufferTonyRCopiedOnce headers;
  SimpleBufferTonyRCopiedOnce body;
  SimpleBufferTonyRCopiedOnce copy;
  int32_t tocOffset = kMsgFirstOffset;
  EudoraTOCEntry tocEntry;

  copy.Allocate(kCopyBufferSize);
  readBuffer.Allocate(kMailReadBufferSize);

  IMPORT_LOG0("Importing mailbox using TOC: ");
  DUMP_FILENAME(tocFile, true);

  nsCOMPtr<nsISeekableStream> tocSeekableStream = do_QueryInterface(tocInputStream);
  nsCOMPtr<nsISeekableStream> mailboxSeekableStream = do_QueryInterface(pInputStream);
  nsCOMPtr<nsIOutputStream> outputStream;
  nsCOMPtr<nsIMsgPluggableStore> msgStore;

  rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore));
  NS_ENSURE_SUCCESS(rv, rv);

  while (!*pAbort && (tocOffset < (int32_t)tocSize)) {
    if (NS_FAILED(rv = tocSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocOffset)))
      break;

    if (NS_FAILED(rv = ReadTOCEntry(tocInputStream, tocEntry)))
      break;

    nsCOMPtr<nsIMsgDBHdr> msgHdr;
    bool reusable;

    rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable,
                                         getter_AddRefs(outputStream));
    if (NS_FAILED(rv))
      break;

    // Quick and dirty way to read in and parse the message the way the rest
    // of the code expects.
    nsCString              defaultDate;
    nsAutoCString            bodyType;
    ReadFileState            state;

    // Seek to the start of the email message.
    mailboxSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocEntry.m_Offset);

    // We're fudging the data to make ReadNextMessage happy. In particular
    // state.size is meant to be the size of the entire file, because it's
    // assumed that ReadNextMessage will actually have to parse. We know
    // exactly how big the message is, so we simply set the "size" to be
    // immediately where the message ends.
    state.offset = tocEntry.m_Offset;
    state.pInputStream = pInputStream;
    state.size = state.offset + tocEntry.m_Length;

    if (NS_SUCCEEDED(rv = ReadNextMessage(&state, readBuffer, headers, body, defaultDate, bodyType, &tocEntry)))
    {
      rv = ImportMessage(headers, body, defaultDate, bodyType, outputStream,
                         pMsgCount);

      if (pBytes)
        *pBytes += tocEntry.m_Length;
      if (NS_SUCCEEDED(rv))
        msgStore->FinishNewMessage(outputStream, msgHdr);
      else {
        msgStore->DiscardNewMessage(outputStream, msgHdr);
        IMPORT_LOG0( "*** Error importing message\n");
      }
    }

    // We currently don't consider an error from ReadNextMessage or ImportMessage to be fatal.
    // Reset the error back to no error in case this is the last time through the loop.
    rv = NS_OK;

    tocOffset += kMsgHeaderSize;

    if (!reusable)
      outputStream->Close();
  }
  if (outputStream)
    outputStream->Close();

  if (NS_SUCCEEDED(rv)) {
    IMPORT_LOG0(" finished\n");
  }
  else {
    // We failed somewhere important enough that we kept the error.
    // Bail on all that we imported since we'll be importing everything
    // again using just the mailbox.
    IMPORT_LOG0("*** Error importing mailbox using TOC: ");
//    DUMP_FILENAME(pMail, true);

    // Reset pBytes back to where it was before we imported this mailbox.
    // This will likely result in a funky progress bar which will move
    // backwards, but that's probably the best we can do to keep the
    // progress accurate since we'll be re-importing the same mailbox.
    if (pBytes)
      *pBytes = saveBytes;

    // Set the message count back to 0.
    if (pMsgCount)
      *pMsgCount = 0;
  }

  return rv;
}
nsresult nsEudoraMailbox::ImportMailbox(uint32_t *pBytes, bool *pAbort,
                                        const PRUnichar *pName, nsIFile *pSrc,
                                        nsIMsgFolder *dstFolder,
                                        int32_t *pMsgCount)
{
  nsCOMPtr<nsIFile>   tocFile;
  nsCOMPtr<nsIInputStream> srcInputStream;
  nsCOMPtr<nsIInputStream> tocInputStream;
  nsCOMPtr<nsIOutputStream> mailOutputStream;
  bool                importWithoutToc = true;
  bool                deleteToc = false;
  nsCOMPtr<nsIFile>   mailFile;

  if (pMsgCount)
    *pMsgCount = 0;

  nsresult rv = pSrc->GetFileSize(&m_mailSize);

  rv = NS_NewLocalFileInputStream(getter_AddRefs(srcInputStream), pSrc);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIFile> srcFile(pSrc);

  // First, get the index file for this mailbox
  rv = FindTOCFile(pSrc, getter_AddRefs(tocFile), &deleteToc);
  if (NS_SUCCEEDED(rv) && tocFile)
  {
    IMPORT_LOG0("Reading euroda toc file: ");
    DUMP_FILENAME(tocFile, true);

    // Read the toc and import the messages
    rv = ImportMailboxUsingTOC(pBytes, pAbort, srcInputStream, tocFile,
                               dstFolder, pMsgCount);

    // clean up
    if (deleteToc)
      DeleteFile(tocFile);

    // If we were able to import with the TOC, then we don't need to bother
    // importing without the TOC.
    if (NS_SUCCEEDED(rv)) {
      importWithoutToc = false;
      IMPORT_LOG0("Imported mailbox: "); DUMP_FILENAME(pSrc, false);
      IMPORT_LOG0("  Using TOC: "); DUMP_FILENAME(tocFile, true);
    }
    else {
      IMPORT_LOG0("*** Error importing with TOC - will import without TOC.\n");
    }
  }

  // pSrc must be Released before returning

  if (importWithoutToc) {
    // The source file contains partially constructed mail messages,
    // and attachments.  We should first investigate if we can use the mailnews msgCompose
    // stuff to do the work for us.  If not we have to scan the mailboxes and do TONS
    // of work to properly reconstruct the message - Eudora is so nice that it strips things
    // like MIME headers, character encoding, and attachments - beautiful!

    rv = pSrc->GetFileSize(&m_mailSize);

    SimpleBufferTonyRCopiedOnce    readBuffer;
    SimpleBufferTonyRCopiedOnce    headers;
    SimpleBufferTonyRCopiedOnce    body;
    SimpleBufferTonyRCopiedOnce    copy;

    headers.m_convertCRs = true;
    body.m_convertCRs = true;

    copy.Allocate(kCopyBufferSize);
    readBuffer.Allocate(kMailReadBufferSize);
    ReadFileState      state;
    state.offset = 0;
    state.size = m_mailSize;
    state.pFile = pSrc;

    IMPORT_LOG0("Reading mailbox\n");

    if (NS_SUCCEEDED(rv))
    {
      nsCString defaultDate;
      nsAutoCString bodyType;

      IMPORT_LOG0("Reading first message\n");

      nsCOMPtr<nsIOutputStream> outputStream;
      nsCOMPtr<nsIMsgPluggableStore> msgStore;
      rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore));
      NS_ENSURE_SUCCESS(rv, rv);

      while (!*pAbort && NS_SUCCEEDED(rv = ReadNextMessage( &state, readBuffer, headers, body, defaultDate, bodyType, NULL))) {

        if (pBytes)
          *pBytes += body.m_writeOffset - 1 + headers.m_writeOffset - 1;

        nsCOMPtr<nsIMsgDBHdr> msgHdr;
        bool reusable;

        rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable,
                                             getter_AddRefs(outputStream));
        if (NS_FAILED(rv))
          break;

        rv = ImportMessage(headers, body, defaultDate, bodyType, outputStream, pMsgCount);

        if (NS_SUCCEEDED(rv))
          msgStore->FinishNewMessage(outputStream, msgHdr);
        else {
          msgStore->DiscardNewMessage(outputStream, msgHdr);
          IMPORT_LOG0( "*** Error importing message\n");
        }

        if (!reusable)
          outputStream->Close();

        if (!readBuffer.m_bytesInBuf && (state.offset >= state.size))
          break;
      }
      if (outputStream)
        outputStream->Close();
    }
    else {
      IMPORT_LOG0("*** Error creating file spec for composition\n");
    }
  }
  return rv;
}
nsresult nsEudoraMailbox::ImportMailboxUsingTOC(
  PRUint32 *pBytes,
  PRBool *pAbort,
  nsIInputStream *pInputStream,
  nsIFile *tocFile,
  nsIOutputStream *pDst,
  PRInt32 *pMsgCount)
{
  nsresult        rv = NS_OK;

  PRInt64  mailSize = m_mailSize;
  PRInt64  tocSize = 0;
  PRUint32  saveBytes = pBytes ? *pBytes : 0;
  nsCOMPtr <nsIInputStream> tocInputStream;

  rv = tocFile->GetFileSize( &tocSize);

  // if the index or the mail file is empty then just
  // use the original mail file.
  if (!mailSize || !tocSize)
    return NS_ERROR_FAILURE;
  rv = NS_NewLocalFileInputStream(getter_AddRefs(tocInputStream), tocFile);
  NS_ENSURE_SUCCESS(rv, rv);

  SimpleBufferTonyRCopiedOnce readBuffer;
  SimpleBufferTonyRCopiedOnce headers;
  SimpleBufferTonyRCopiedOnce body;
  SimpleBufferTonyRCopiedOnce copy;
  PRInt32 tocOffset = kMsgFirstOffset;
  EudoraTOCEntry tocEntry;

  copy.Allocate( kCopyBufferSize);
  readBuffer.Allocate(kMailReadBufferSize);

  IMPORT_LOG0( "Importing mailbox using TOC: ");
  DUMP_FILENAME( tocFile, PR_TRUE);

  nsCOMPtr <nsISeekableStream> tocSeekableStream = do_QueryInterface(tocInputStream);
  nsCOMPtr <nsISeekableStream> mailboxSeekableStream = do_QueryInterface(pInputStream);
  while (!*pAbort && (tocOffset < (PRInt32)tocSize)) {
    if ( NS_FAILED(rv = tocSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocOffset)) )
      break;

    if ( NS_FAILED(rv = ReadTOCEntry(tocInputStream, tocEntry)) )
      break;

    // Quick and dirty way to read in and parse the message the way the rest
    // of the code expects.
    nsCString              defaultDate;
    nsCAutoString            bodyType;
    ReadFileState            state;

    // Seek to the start of the email message.
    mailboxSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocEntry.m_Offset);

    // We're fudging the data to make ReadNextMessage happy. In particular
    // state.size is meant to be the size of the entire file, because it's
    // assumed that ReadNextMessage will actually have to parse. We know
    // exactly how big the message is, so we simply set the "size" to be
    // immediately where the message ends.
    state.offset = tocEntry.m_Offset;
    state.pInputStream = pInputStream;
    state.size = state.offset + tocEntry.m_Length;

    if ( NS_SUCCEEDED(rv = ReadNextMessage(&state, readBuffer, headers, body, defaultDate, bodyType, &tocEntry) ) )
    {
      rv = ImportMessage(headers, body, defaultDate, bodyType, pDst, pMsgCount);

      if (pBytes)
        *pBytes += tocEntry.m_Length;
    }

    // We currently don't consider an error from ReadNextMessage or ImportMessage to be fatal.
    // Reset the error back to no error in case this is the last time through the loop.
    rv = NS_OK;

    tocOffset += kMsgHeaderSize;
  }

  if ( NS_SUCCEEDED(rv) ) {
    IMPORT_LOG0( " finished\n");
  }
  else {
    // We failed somewhere important enough that we kept the error.
    // Bail on all that we imported since we'll be importing everything
    // again using just the mailbox.
    IMPORT_LOG0( "*** Error importing mailbox using TOC: ");
//    DUMP_FILENAME(pMail, PR_TRUE);

    // Close the destination and truncate it. We don't need to bother
    // to reopen it because the nsIFileSpec implementation will open
    // before writing if necessary (and yes legacy importing code already
    // relies on this behavior).
//    pDst->CloseStream();
//    pDst->Truncate(0);

    // Reset pBytes back to where it was before we imported this mailbox.
    // This will likely result in a funky progress bar which will move
    // backwards, but that's probably the best we can do to keep the
    // progress accurate since we'll be re-importing the same mailbox.
    if (pBytes)
      *pBytes = saveBytes;

    // Set the message count back to 0.
    if (pMsgCount)
      *pMsgCount = 0;
  }

  return rv;
}