NS_IMETHODIMP nsMsgMaildirStore::ChangeKeywords(nsIArray *aHdrArray,
                                             const nsACString &aKeywords,
                                             bool aAdd)
{
  NS_ENSURE_ARG_POINTER(aHdrArray);
  NS_ENSURE_ARG_POINTER(aHdrArray);
  nsCOMPtr<nsIOutputStream> outputStream;
  nsCOMPtr<nsISeekableStream> seekableStream;

  uint32_t messageCount;
  nsresult rv = aHdrArray->GetLength(&messageCount);
  NS_ENSURE_SUCCESS(rv, rv);
  if (!messageCount)
    return NS_ERROR_INVALID_ARG;

  nsAutoPtr<nsLineBuffer<char> > lineBuffer(new nsLineBuffer<char>);
  NS_ENSURE_TRUE(lineBuffer, NS_ERROR_OUT_OF_MEMORY);

  nsTArray<nsCString> keywordArray;
  ParseString(aKeywords, ' ', keywordArray);

  for (uint32_t i = 0; i < messageCount; ++i) // for each message
  {
    nsCOMPtr<nsIMsgDBHdr> message = do_QueryElementAt(aHdrArray, i, &rv);
    NS_ENSURE_SUCCESS(rv, rv);
    // get output stream for header
    nsCOMPtr<nsIOutputStream> outputStream;
    rv = GetOutputStream(message, outputStream);
    NS_ENSURE_SUCCESS(rv, rv);
    nsCOMPtr <nsIInputStream> inputStream = do_QueryInterface(outputStream, &rv);
    NS_ENSURE_SUCCESS(rv, rv);
    nsCOMPtr <nsISeekableStream> seekableStream(do_QueryInterface(inputStream, &rv));
    NS_ENSURE_SUCCESS(rv, rv);
    uint32_t statusOffset = 0;
    (void)message->GetStatusOffset(&statusOffset);
    uint64_t desiredOffset = statusOffset;

    ChangeKeywordsHelper(message, desiredOffset, lineBuffer, keywordArray,
                         aAdd, outputStream, seekableStream, inputStream);
    if (inputStream)
      inputStream->Close();
    // ### TODO - if growKeywords property is set on the message header,
    // we need to rewrite the message file with extra room for the keywords,
    // or schedule some sort of background task to do this.
  }
  lineBuffer = nullptr;
  return NS_OK;
}
nsresult nsMsgLocalStoreUtils::UpdateFolderFlag(nsIMsgDBHdr *mailHdr, bool bSet,
                                                nsMsgMessageFlagType flag,
                                                nsIOutputStream *fileStream) {
  uint32_t statusOffset;
  uint64_t msgOffset;
  nsresult rv = mailHdr->GetStatusOffset(&statusOffset);
  // This probably means there's no x-mozilla-status header, so
  // we just ignore this.
  if (NS_FAILED(rv) || (statusOffset == 0)) return NS_OK;
  rv = mailHdr->GetMessageOffset(&msgOffset);
  NS_ENSURE_SUCCESS(rv, rv);
  uint64_t statusPos = msgOffset + statusOffset;
  nsCOMPtr<nsISeekableStream> seekableStream(
      do_QueryInterface(fileStream, &rv));
  NS_ENSURE_SUCCESS(rv, rv);
  rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, statusPos);
  NS_ENSURE_SUCCESS(rv, rv);
  char buf[50];
  buf[0] = '\0';
  nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(fileStream, &rv);
  NS_ENSURE_SUCCESS(rv, rv);
  uint32_t bytesRead;
  if (NS_SUCCEEDED(
          inputStream->Read(buf, X_MOZILLA_STATUS_LEN + 6, &bytesRead))) {
    buf[bytesRead] = '\0';
    if (strncmp(buf, X_MOZILLA_STATUS, X_MOZILLA_STATUS_LEN) == 0 &&
        strncmp(buf + X_MOZILLA_STATUS_LEN, ": ", 2) == 0 &&
        strlen(buf) >= X_MOZILLA_STATUS_LEN + 6) {
      uint32_t flags;
      uint32_t bytesWritten;
      (void)mailHdr->GetFlags(&flags);
      if (!(flags & nsMsgMessageFlags::Expunged)) {
        char *p = buf + X_MOZILLA_STATUS_LEN + 2;

        nsresult errorCode = NS_OK;
        flags = nsDependentCString(p).ToInteger(&errorCode, 16);

        uint32_t curFlags;
        (void)mailHdr->GetFlags(&curFlags);
        flags = (flags & nsMsgMessageFlags::Queued) |
                (curFlags & ~nsMsgMessageFlags::RuntimeOnly);
        if (bSet)
          flags |= flag;
        else
          flags &= ~flag;
      } else {
        flags &= ~nsMsgMessageFlags::RuntimeOnly;
      }
      seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, statusPos);
      // We are filing out x-mozilla-status flags here
      PR_snprintf(buf, sizeof(buf), X_MOZILLA_STATUS_FORMAT,
                  flags & 0x0000FFFF);
      int32_t lineLen = PL_strlen(buf);
      uint64_t status2Pos = statusPos + lineLen;
      fileStream->Write(buf, lineLen, &bytesWritten);

      if (flag & 0xFFFF0000) {
        // Time to update x-mozilla-status2,
        // first find it by finding end of previous line, see bug 234935.
        seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, status2Pos);
        do {
          rv = inputStream->Read(buf, 1, &bytesRead);
          status2Pos++;
        } while (NS_SUCCEEDED(rv) && (*buf == '\n' || *buf == '\r'));
        status2Pos--;
        seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, status2Pos);
        if (NS_SUCCEEDED(inputStream->Read(buf, X_MOZILLA_STATUS2_LEN + 10,
                                           &bytesRead))) {
          if (strncmp(buf, X_MOZILLA_STATUS2, X_MOZILLA_STATUS2_LEN) == 0 &&
              strncmp(buf + X_MOZILLA_STATUS2_LEN, ": ", 2) == 0 &&
              strlen(buf) >= X_MOZILLA_STATUS2_LEN + 10) {
            uint32_t dbFlags;
            (void)mailHdr->GetFlags(&dbFlags);
            dbFlags &= 0xFFFF0000;
            seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, status2Pos);
            PR_snprintf(buf, sizeof(buf), X_MOZILLA_STATUS2_FORMAT, dbFlags);
            fileStream->Write(buf, PL_strlen(buf), &bytesWritten);
          }
        }
      }
    } else {
#ifdef DEBUG
      printf(
          "Didn't find %s where expected at position %ld\n"
          "instead, found %s.\n",
          X_MOZILLA_STATUS, (long)statusPos, buf);
#endif
      rv = NS_ERROR_FAILURE;
    }
  } else
    rv = NS_ERROR_FAILURE;
  return rv;
}
nsresult nsMailboxProtocol::Initialize(nsIURI * aURL)
{
  NS_PRECONDITION(aURL, "invalid URL passed into MAILBOX Protocol");
  nsresult rv = NS_OK;
  if (aURL)
  {
    rv = aURL->QueryInterface(NS_GET_IID(nsIMailboxUrl), (void **) getter_AddRefs(m_runningUrl));
    if (NS_SUCCEEDED(rv) && m_runningUrl)
    {
      nsCOMPtr <nsIMsgWindow> window;
      rv = m_runningUrl->GetMailboxAction(&m_mailboxAction); 
      // clear stopped flag on msg window, because we care.
      nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_runningUrl);
      if (mailnewsUrl)
      {
        mailnewsUrl->GetMsgWindow(getter_AddRefs(window));
        if (window)
          window->SetStopped(false);
      }

      if (m_mailboxAction == nsIMailboxUrl::ActionParseMailbox)
      {
        // Set the length of the file equal to the max progress
        nsCOMPtr<nsIFile> file;
        GetFileFromURL(aURL, getter_AddRefs(file));
        if (file)
        {
          int64_t fileSize = 0;
          file->GetFileSize(&fileSize);
          mailnewsUrl->SetMaxProgress(fileSize);
        }

        rv = OpenFileSocket(aURL, 0, -1 /* read in all the bytes in the file */);
      }
      else
      {
        // we need to specify a byte range to read in so we read in JUST the message we want.
        rv = SetupMessageExtraction();
        if (NS_FAILED(rv)) return rv;
        uint32_t aMsgSize = 0;
        rv = m_runningUrl->GetMessageSize(&aMsgSize);
        NS_ASSERTION(NS_SUCCEEDED(rv), "oops....i messed something up");
        SetContentLength(aMsgSize);
        mailnewsUrl->SetMaxProgress(aMsgSize);

        if (RunningMultipleMsgUrl())
        {
          rv = OpenFileSocketForReuse(aURL, m_msgOffset, aMsgSize);
          // if we're running multiple msg url, we clear the event sink because the multiple
          // msg urls will handle setting the progress.
          mProgressEventSink = nullptr;
        }
        else
        {
          nsCOMPtr<nsIMsgIncomingServer> server;
          nsCOMPtr<nsIMsgDBHdr> msgHdr;
          nsCOMPtr<nsIMsgFolder> folder;
          nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(m_runningUrl, &rv);
          NS_ENSURE_SUCCESS(rv,rv);
          rv = msgUrl->GetMessageHeader(getter_AddRefs(msgHdr));
          if (msgHdr)
          {
            msgHdr->GetFolder(getter_AddRefs(folder));
            if (folder)
              folder->GetServer(getter_AddRefs(server));
          }
          if (server)
          {
            nsCOMPtr<nsIMsgPluggableStore> msgStore;
            rv = server->GetMsgStore(getter_AddRefs(msgStore));
            NS_ENSURE_SUCCESS(rv, rv);

            if (NS_SUCCEEDED(rv) && msgHdr)
            {
              nsCOMPtr<nsIInputStream> stream;
              int64_t offset = 0;
              bool reusable = false;

              rv = folder->GetMsgInputStream(msgHdr, &reusable, getter_AddRefs(stream));
              NS_ENSURE_SUCCESS(rv, rv);
              nsCOMPtr<nsISeekableStream> seekableStream(do_QueryInterface(stream, &rv));
              NS_ENSURE_SUCCESS(rv, rv);
              seekableStream->Tell(&offset);
              // create input stream transport
              nsCOMPtr<nsIStreamTransportService> sts =
                  do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
              if (NS_FAILED(rv)) return rv;
              m_readCount = aMsgSize;
              rv = sts->CreateInputTransport(stream, offset,
                                             int64_t(aMsgSize), true,
                                             getter_AddRefs(m_transport));

              m_socketIsOpen = false;
             
            }
          }
          else // must be a .eml file
            rv = OpenFileSocket(aURL, 0, aMsgSize);
        }
        NS_ASSERTION(NS_SUCCEEDED(rv), "oops....i messed something up");
      }
    }
  }
  
  m_lineStreamBuffer = new nsMsgLineStreamBuffer(OUTPUT_BUFFER_SIZE, true);
  
  m_nextState = MAILBOX_READ_FOLDER;
  m_initialState = MAILBOX_READ_FOLDER;
  mCurrentProgress = 0;
  
  // do we really need both?
  m_tempMessageFile = m_tempMsgFile;
  return rv;
}