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; }
NS_IMETHODIMP nsMsgBrkMBoxStore::ChangeKeywords(nsIArray *aHdrArray, const nsACString &aKeywords, bool aAdd) { NS_ENSURE_ARG_POINTER(aHdrArray); nsCOMPtr<nsIOutputStream> outputStream; nsCOMPtr<nsISeekableStream> seekableStream; int64_t restoreStreamPos; uint32_t messageCount; nsresult rv = aHdrArray->GetLength(&messageCount); NS_ENSURE_SUCCESS(rv, rv); if (!messageCount) return NS_ERROR_INVALID_ARG; rv = GetOutputStream(aHdrArray, outputStream, seekableStream, restoreStreamPos); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(outputStream, &rv); NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr<nsLineBuffer<char> > lineBuffer(new nsLineBuffer<char>); NS_ENSURE_TRUE(lineBuffer, NS_ERROR_OUT_OF_MEMORY); // For each message, we seek to the beginning of the x-mozilla-status header, // and start reading lines, looking for x-mozilla-keys: headers; If we're // adding the keyword and we find // a header with the desired keyword already in it, we don't need to // do anything. Likewise, if removing keyword and we don't find it, // we don't need to do anything. Otherwise, if adding, we need to // see if there's an x-mozilla-keys // header with room for the new keyword. If so, we replace the // corresponding number of spaces with the keyword. If no room, // we can't do anything until the folder is compacted and another // x-mozilla-keys header is added. In that case, we set a property // on the header, which the compaction code will check. nsTArray<nsCString> keywordArray; ParseString(aKeywords, ' ', keywordArray); nsCOMPtr<nsIMsgDBHdr> msgHdr; for (uint32_t i = 0; i < messageCount; ++i) // for each message { msgHdr = do_QueryElementAt(aHdrArray, i, &rv); NS_ENSURE_SUCCESS(rv, rv); uint64_t messageOffset; msgHdr->GetMessageOffset(&messageOffset); uint32_t statusOffset = 0; (void)msgHdr->GetStatusOffset(&statusOffset); uint64_t desiredOffset = messageOffset + statusOffset; ChangeKeywordsHelper(msgHdr, desiredOffset, lineBuffer, keywordArray, aAdd, outputStream, seekableStream, inputStream); } lineBuffer = nullptr; if (restoreStreamPos != -1) seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, restoreStreamPos); else if (outputStream) outputStream->Close(); if (messageCount > 0) { msgHdr = do_QueryElementAt(aHdrArray, 0); SetDBValid(msgHdr); } return NS_OK; }