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);
}
nsresult nsEudoraCompose::CopyComposedMessage( nsCString& fromLine, nsIFile *pSrc, nsIOutputStream *pDst, SimpleBufferTonyRCopiedOnce& copy)
{
  copy.m_bytesInBuf = 0;
  copy.m_writeOffset = 0;
  ReadFileState  state;
  state.pFile = pSrc;
  state.offset = 0;
  state.size = 0;

  pSrc->GetFileSize( &state.size);
  if (!state.size) {
    IMPORT_LOG0( "*** Error, unexpected zero file size for composed message\n");
    return( NS_ERROR_FAILURE);
  }

        nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(state.pInputStream), pSrc);

  if (NS_FAILED( rv)) {
    IMPORT_LOG0( "*** Error, unable to open composed message file\n");
    return( NS_ERROR_FAILURE);
  }

  PRUint32 written;
  rv = pDst->Write( fromLine.get(), fromLine.Length(), &written);

  // well, isn't this a hoot!
  // Read the headers from the new message, get the ones we like
  // and write out only the headers we want from the new message,
  // along with all of the other headers from the "old" message!
  if (NS_SUCCEEDED( rv))
    rv = FillMailBuffer( &state, copy);
  if (NS_SUCCEEDED( rv))
    rv = ReadHeaders( &state, copy, m_readHeaders);

  if (NS_SUCCEEDED( rv)) {
    rv = WriteHeaders( pDst, m_readHeaders);
  }

  // We need to go ahead and write out the rest of the copy buffer
  // so that the following will properly copy the rest of the body
  char lastChar = 0;

  rv = EscapeFromSpaceLine(pDst, copy.m_pBuffer + copy.m_writeOffset, copy.m_pBuffer+copy.m_bytesInBuf);
  if (copy.m_bytesInBuf)
    lastChar = copy.m_pBuffer[copy.m_bytesInBuf - 1];
  if (NS_SUCCEEDED(rv))
    copy.m_writeOffset = copy.m_bytesInBuf;

  while ((state.offset < state.size) && NS_SUCCEEDED( rv)) {
    rv = FillMailBuffer( &state, copy);
    if (NS_SUCCEEDED( rv)) {
      rv = EscapeFromSpaceLine(pDst, copy.m_pBuffer + copy.m_writeOffset, copy.m_pBuffer+copy.m_bytesInBuf);
      lastChar = copy.m_pBuffer[copy.m_bytesInBuf - 1];
      if (NS_SUCCEEDED( rv))
        copy.m_writeOffset = copy.m_bytesInBuf;
      else
        IMPORT_LOG0( "*** Error writing to destination mailbox\n");
    }
  }

  state.pInputStream->Close();

  if ((lastChar != 0x0A) && NS_SUCCEEDED( rv)) {
    rv = pDst->Write( "\x0D\x0A", 2, &written);
    if (written != 2)
      rv = NS_ERROR_FAILURE;
  }

  return( rv);
}
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;
}