From 302bf1b523012e11b60425d6eee1221ebc2724eb Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Sun, 3 Nov 2019 00:17:46 -0400 Subject: Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1 --- mailnews/imap/src/nsImapFlagAndUidState.cpp | 321 ++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 mailnews/imap/src/nsImapFlagAndUidState.cpp (limited to 'mailnews/imap/src/nsImapFlagAndUidState.cpp') diff --git a/mailnews/imap/src/nsImapFlagAndUidState.cpp b/mailnews/imap/src/nsImapFlagAndUidState.cpp new file mode 100644 index 000000000..deae831db --- /dev/null +++ b/mailnews/imap/src/nsImapFlagAndUidState.cpp @@ -0,0 +1,321 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "msgCore.h" // for pre-compiled headers + +#include "nsImapCore.h" +#include "nsImapFlagAndUidState.h" +#include "nsMsgUtils.h" +#include "prcmon.h" +#include "nspr.h" + +NS_IMPL_ISUPPORTS(nsImapFlagAndUidState, nsIImapFlagAndUidState) + +using namespace mozilla; + +NS_IMETHODIMP nsImapFlagAndUidState::GetNumberOfMessages(int32_t *result) +{ + if (!result) + return NS_ERROR_NULL_POINTER; + *result = fUids.Length(); + return NS_OK; +} + +NS_IMETHODIMP nsImapFlagAndUidState::GetUidOfMessage(int32_t zeroBasedIndex, uint32_t *aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + + PR_CEnterMonitor(this); + *aResult = fUids.SafeElementAt(zeroBasedIndex, nsMsgKey_None); + PR_CExitMonitor(this); + return NS_OK; +} + +NS_IMETHODIMP nsImapFlagAndUidState::GetMessageFlags(int32_t zeroBasedIndex, uint16_t *aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = fFlags.SafeElementAt(zeroBasedIndex, kNoImapMsgFlag); + return NS_OK; +} + +NS_IMETHODIMP nsImapFlagAndUidState::SetMessageFlags(int32_t zeroBasedIndex, unsigned short flags) +{ + if (zeroBasedIndex < (int32_t)fUids.Length()) + fFlags[zeroBasedIndex] = flags; + return NS_OK; +} + +NS_IMETHODIMP nsImapFlagAndUidState::GetNumberOfRecentMessages(int32_t *result) +{ + if (!result) + return NS_ERROR_NULL_POINTER; + + PR_CEnterMonitor(this); + uint32_t counter = 0; + int32_t numUnseenMessages = 0; + + for (counter = 0; counter < fUids.Length(); counter++) + { + if (fFlags[counter] & kImapMsgRecentFlag) + numUnseenMessages++; + } + PR_CExitMonitor(this); + + *result = numUnseenMessages; + + return NS_OK; +} + +NS_IMETHODIMP nsImapFlagAndUidState::GetPartialUIDFetch(bool *aPartialUIDFetch) +{ + NS_ENSURE_ARG_POINTER(aPartialUIDFetch); + *aPartialUIDFetch = fPartialUIDFetch; + return NS_OK; +} + +/* amount to expand for imap entry flags when we need more */ + +nsImapFlagAndUidState::nsImapFlagAndUidState(int32_t numberOfMessages) + : fUids(numberOfMessages), + fFlags(numberOfMessages), + m_customFlagsHash(10), + m_customAttributesHash(10), + mLock("nsImapFlagAndUidState.mLock") +{ + fSupportedUserFlags = 0; + fNumberDeleted = 0; + fPartialUIDFetch = true; +} + +nsImapFlagAndUidState::~nsImapFlagAndUidState() +{ +} + +NS_IMETHODIMP +nsImapFlagAndUidState::OrSupportedUserFlags(uint16_t flags) +{ + fSupportedUserFlags |= flags; + return NS_OK; +} + +NS_IMETHODIMP +nsImapFlagAndUidState::GetSupportedUserFlags(uint16_t *aFlags) +{ + NS_ENSURE_ARG_POINTER(aFlags); + *aFlags = fSupportedUserFlags; + return NS_OK; +} + +// we need to reset our flags, (re-read all) but chances are the memory allocation needed will be +// very close to what we were already using + +NS_IMETHODIMP nsImapFlagAndUidState::Reset() +{ + PR_CEnterMonitor(this); + fNumberDeleted = 0; + m_customFlagsHash.Clear(); + fUids.Clear(); + fFlags.Clear(); + fPartialUIDFetch = true; + PR_CExitMonitor(this); + return NS_OK; +} + + +// Remove (expunge) a message from our array, since now it is gone for good + +NS_IMETHODIMP nsImapFlagAndUidState::ExpungeByIndex(uint32_t msgIndex) +{ + // protect ourselves in case the server gave us an index key of -1 or 0 + if ((int32_t) msgIndex <= 0) + return NS_ERROR_INVALID_ARG; + + if ((uint32_t) fUids.Length() < msgIndex) + return NS_ERROR_INVALID_ARG; + + PR_CEnterMonitor(this); + msgIndex--; // msgIndex is 1-relative + if (fFlags[msgIndex] & kImapMsgDeletedFlag) // see if we already had counted this one as deleted + fNumberDeleted--; + fUids.RemoveElementAt(msgIndex); + fFlags.RemoveElementAt(msgIndex); + PR_CExitMonitor(this); + return NS_OK; +} + + +// adds to sorted list, protects against duplicates and going past array bounds. +NS_IMETHODIMP nsImapFlagAndUidState::AddUidFlagPair(uint32_t uid, imapMessageFlagsType flags, uint32_t zeroBasedIndex) +{ + if (uid == nsMsgKey_None) // ignore uid of -1 + return NS_OK; + // check for potential overflow in buffer size for uid array + if (zeroBasedIndex > 0x3FFFFFFF) + return NS_ERROR_INVALID_ARG; + PR_CEnterMonitor(this); + // make sure there is room for this pair + if (zeroBasedIndex >= fUids.Length()) + { + int32_t sizeToGrowBy = zeroBasedIndex - fUids.Length() + 1; + fUids.InsertElementsAt(fUids.Length(), sizeToGrowBy, 0); + fFlags.InsertElementsAt(fFlags.Length(), sizeToGrowBy, 0); + } + + fUids[zeroBasedIndex] = uid; + fFlags[zeroBasedIndex] = flags; + if (flags & kImapMsgDeletedFlag) + fNumberDeleted++; + PR_CExitMonitor(this); + return NS_OK; +} + + +NS_IMETHODIMP nsImapFlagAndUidState::GetNumberOfDeletedMessages(int32_t *numDeletedMessages) +{ + NS_ENSURE_ARG_POINTER(numDeletedMessages); + *numDeletedMessages = NumberOfDeletedMessages(); + return NS_OK; +} + +int32_t nsImapFlagAndUidState::NumberOfDeletedMessages() +{ + return fNumberDeleted; +} + +// since the uids are sorted, start from the back (rb) + +uint32_t nsImapFlagAndUidState::GetHighestNonDeletedUID() +{ + uint32_t msgIndex = fUids.Length(); + do + { + if (msgIndex <= 0) + return(0); + msgIndex--; + if (fUids[msgIndex] && !(fFlags[msgIndex] & kImapMsgDeletedFlag)) + return fUids[msgIndex]; + } + while (msgIndex > 0); + return 0; +} + + +// Has the user read the last message here ? Used when we first open the inbox to see if there +// really is new mail there. + +bool nsImapFlagAndUidState::IsLastMessageUnseen() +{ + uint32_t msgIndex = fUids.Length(); + + if (msgIndex <= 0) + return false; + msgIndex--; + // if last message is deleted, it was probably filtered the last time around + if (fUids[msgIndex] && (fFlags[msgIndex] & (kImapMsgSeenFlag | kImapMsgDeletedFlag))) + return false; + return true; +} + +// find a message flag given a key with non-recursive binary search, since some folders +// may have thousand of messages, once we find the key set its index, or the index of +// where the key should be inserted + +imapMessageFlagsType nsImapFlagAndUidState::GetMessageFlagsFromUID(uint32_t uid, bool *foundIt, int32_t *ndx) +{ + PR_CEnterMonitor(this); + *ndx = (int32_t) fUids.IndexOfFirstElementGt(uid) - 1; + *foundIt = *ndx >= 0 && fUids[*ndx] == uid; + imapMessageFlagsType retFlags = (*foundIt) ? fFlags[*ndx] : kNoImapMsgFlag; + PR_CExitMonitor(this); + return retFlags; +} + +NS_IMETHODIMP nsImapFlagAndUidState::AddUidCustomFlagPair(uint32_t uid, const char *customFlag) +{ + if (!customFlag) + return NS_OK; + + MutexAutoLock mon(mLock); + nsCString ourCustomFlags; + nsCString oldValue; + if (m_customFlagsHash.Get(uid, &oldValue)) + { + // We'll store multiple keys as space-delimited since space is not + // a valid character in a keyword. First, we need to look for the + // customFlag in the existing flags; + nsDependentCString customFlagString(customFlag); + int32_t existingCustomFlagPos = oldValue.Find(customFlagString); + uint32_t customFlagLen = customFlagString.Length(); + while (existingCustomFlagPos != kNotFound) + { + // if existing flags ends with this exact flag, or flag + ' ' + // and the flag is at the beginning of the string or there is ' ' + flag + // then we have this flag already; + if (((oldValue.Length() == existingCustomFlagPos + customFlagLen) || + (oldValue.CharAt(existingCustomFlagPos + customFlagLen) == ' ')) && + ((existingCustomFlagPos == 0) || + (oldValue.CharAt(existingCustomFlagPos - 1) == ' '))) + return NS_OK; + // else, advance to next flag + existingCustomFlagPos = MsgFind(oldValue, customFlagString, false, existingCustomFlagPos + customFlagLen); + } + ourCustomFlags.Assign(oldValue); + ourCustomFlags.AppendLiteral(" "); + ourCustomFlags.Append(customFlag); + m_customFlagsHash.Remove(uid); + } + else + { + ourCustomFlags.Assign(customFlag); + } + m_customFlagsHash.Put(uid, ourCustomFlags); + return NS_OK; +} + +NS_IMETHODIMP nsImapFlagAndUidState::GetCustomFlags(uint32_t uid, char **customFlags) +{ + MutexAutoLock mon(mLock); + nsCString value; + if (m_customFlagsHash.Get(uid, &value)) + { + *customFlags = NS_strdup(value.get()); + return (*customFlags) ? NS_OK : NS_ERROR_FAILURE; + } + *customFlags = nullptr; + return NS_OK; +} + +NS_IMETHODIMP nsImapFlagAndUidState::ClearCustomFlags(uint32_t uid) +{ + MutexAutoLock mon(mLock); + m_customFlagsHash.Remove(uid); + return NS_OK; +} + +NS_IMETHODIMP nsImapFlagAndUidState::SetCustomAttribute(uint32_t aUid, + const nsACString &aCustomAttributeName, + const nsACString &aCustomAttributeValue) +{ + nsCString key; + key.AppendInt((int64_t)aUid); + key.Append(aCustomAttributeName); + nsCString value; + value.Assign(aCustomAttributeValue); + m_customAttributesHash.Put(key, value); + return NS_OK; +} + +NS_IMETHODIMP nsImapFlagAndUidState::GetCustomAttribute(uint32_t aUid, + const nsACString &aCustomAttributeName, + nsACString &aCustomAttributeValue) +{ + nsCString key; + key.AppendInt((int64_t)aUid); + key.Append(aCustomAttributeName); + nsCString val; + m_customAttributesHash.Get(key, &val); + aCustomAttributeValue.Assign(val); + return NS_OK; +} -- cgit v1.2.3