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/nsImapUtils.cpp | 373 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 mailnews/imap/src/nsImapUtils.cpp (limited to 'mailnews/imap/src/nsImapUtils.cpp') diff --git a/mailnews/imap/src/nsImapUtils.cpp b/mailnews/imap/src/nsImapUtils.cpp new file mode 100644 index 000000000..b213d33f8 --- /dev/null +++ b/mailnews/imap/src/nsImapUtils.cpp @@ -0,0 +1,373 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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" +#include "nsImapUtils.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "prsystem.h" +#include "prprf.h" +#include "nsNetCID.h" + +// stuff for temporary root folder hack +#include "nsIMsgAccountManager.h" +#include "nsIMsgIncomingServer.h" +#include "nsIImapIncomingServer.h" +#include "nsMsgBaseCID.h" +#include "nsImapCore.h" +#include "nsMsgUtils.h" +#include "nsImapFlagAndUidState.h" +#include "nsIMAPNamespace.h" +#include "nsIImapFlagAndUidState.h" + +nsresult +nsImapURI2FullName(const char* rootURI, const char* hostName, const char* uriStr, + char **name) +{ + nsAutoCString uri(uriStr); + nsAutoCString fullName; + if (uri.Find(rootURI) != 0) + return NS_ERROR_FAILURE; + fullName = Substring(uri, strlen(rootURI)); + uri = fullName; + int32_t hostStart = uri.Find(hostName); + if (hostStart <= 0) + return NS_ERROR_FAILURE; + fullName = Substring(uri, hostStart); + uri = fullName; + int32_t hostEnd = uri.FindChar('/'); + if (hostEnd <= 0) + return NS_ERROR_FAILURE; + fullName = Substring(uri, hostEnd + 1); + if (fullName.IsEmpty()) + return NS_ERROR_FAILURE; + *name = ToNewCString(fullName); + return NS_OK; +} + +/* parses ImapMessageURI */ +nsresult nsParseImapMessageURI(const char* uri, nsCString& folderURI, uint32_t *key, char **part) +{ + if(!key) + return NS_ERROR_NULL_POINTER; + + nsAutoCString uriStr(uri); + int32_t folderEnd = -1; + // imap-message uri's can have imap:// url strings tacked on the end, + // e.g., when opening/saving attachments. We don't want to look for '#' + // in that part of the uri, if the attachment name contains '#', + // so check for that here. + if (StringBeginsWith(uriStr, NS_LITERAL_CSTRING("imap-message"))) + folderEnd = uriStr.Find("imap://"); + + int32_t keySeparator = MsgRFindChar(uriStr, '#', folderEnd); + if(keySeparator != -1) + { + int32_t keyEndSeparator = MsgFindCharInSet(uriStr, "/?&", keySeparator); + nsAutoString folderPath; + folderURI = StringHead(uriStr, keySeparator); + folderURI.Cut(4, 8); // cut out the _message part of imap-message: + // folder uri's don't have fully escaped usernames. + int32_t atPos = folderURI.FindChar('@'); + if (atPos != -1) + { + nsCString unescapedName, escapedName; + int32_t userNamePos = folderURI.Find("//") + 2; + uint32_t origUserNameLen = atPos - userNamePos; + if (NS_SUCCEEDED(MsgUnescapeString(Substring(folderURI, userNamePos, + origUserNameLen), + 0, unescapedName))) + { + // Re-escape the username, matching the way we do it in uris, not the + // way necko escapes urls. See nsMsgIncomingServer::GetServerURI. + MsgEscapeString(unescapedName, nsINetUtil::ESCAPE_XALPHAS, escapedName); + folderURI.Replace(userNamePos, origUserNameLen, escapedName); + } + } + nsAutoCString keyStr; + if (keyEndSeparator != -1) + keyStr = Substring(uriStr, keySeparator + 1, keyEndSeparator - (keySeparator + 1)); + else + keyStr = Substring(uriStr, keySeparator + 1); + + *key = strtoul(keyStr.get(), nullptr, 10); + + if (part && keyEndSeparator != -1) + { + int32_t partPos = MsgFind(uriStr, "part=", false, keyEndSeparator); + if (partPos != -1) + { + *part = ToNewCString(Substring(uriStr, keyEndSeparator)); + } + } + } + return NS_OK; +} + +nsresult nsBuildImapMessageURI(const char *baseURI, uint32_t key, nsCString& uri) +{ + uri.Append(baseURI); + uri.Append('#'); + uri.AppendInt(key); + return NS_OK; +} + +nsresult nsCreateImapBaseMessageURI(const nsACString& baseURI, nsCString &baseMessageURI) +{ + nsAutoCString tailURI(baseURI); + // chop off imap:/ + if (tailURI.Find(kImapRootURI) == 0) + tailURI.Cut(0, PL_strlen(kImapRootURI)); + baseMessageURI = kImapMessageRootURI; + baseMessageURI += tailURI; + return NS_OK; +} + +// nsImapMailboxSpec definition +NS_IMPL_ISUPPORTS(nsImapMailboxSpec, nsIMailboxSpec) + +nsImapMailboxSpec::nsImapMailboxSpec() +{ + mFolder_UIDVALIDITY = 0; + mHighestModSeq = 0; + mNumOfMessages = 0; + mNumOfUnseenMessages = 0; + mNumOfRecentMessages = 0; + mNextUID = 0; + + mBoxFlags = 0; + mSupportedUserFlags = 0; + + mHierarchySeparator = '\0'; + + mFolderSelected = false; + mDiscoveredFromLsub = false; + + mOnlineVerified = false; + mNamespaceForFolder = nullptr; +} + +nsImapMailboxSpec::~nsImapMailboxSpec() +{ +} + +NS_IMPL_GETSET(nsImapMailboxSpec, Folder_UIDVALIDITY, int32_t, mFolder_UIDVALIDITY) +NS_IMPL_GETSET(nsImapMailboxSpec, HighestModSeq, uint64_t, mHighestModSeq) +NS_IMPL_GETSET(nsImapMailboxSpec, NumMessages, int32_t, mNumOfMessages) +NS_IMPL_GETSET(nsImapMailboxSpec, NumUnseenMessages, int32_t, mNumOfUnseenMessages) +NS_IMPL_GETSET(nsImapMailboxSpec, NumRecentMessages, int32_t, mNumOfRecentMessages) +NS_IMPL_GETSET(nsImapMailboxSpec, NextUID, int32_t, mNextUID) +NS_IMPL_GETSET(nsImapMailboxSpec, HierarchyDelimiter, char, mHierarchySeparator) +NS_IMPL_GETSET(nsImapMailboxSpec, FolderSelected, bool, mFolderSelected) +NS_IMPL_GETSET(nsImapMailboxSpec, DiscoveredFromLsub, bool, mDiscoveredFromLsub) +NS_IMPL_GETSET(nsImapMailboxSpec, OnlineVerified, bool, mOnlineVerified) +NS_IMPL_GETSET(nsImapMailboxSpec, SupportedUserFlags, uint32_t, mSupportedUserFlags) +NS_IMPL_GETSET(nsImapMailboxSpec, Box_flags, uint32_t, mBoxFlags) +NS_IMPL_GETSET(nsImapMailboxSpec, NamespaceForFolder, nsIMAPNamespace *, mNamespaceForFolder) + +NS_IMETHODIMP nsImapMailboxSpec::GetAllocatedPathName(nsACString &aAllocatedPathName) +{ + aAllocatedPathName = mAllocatedPathName; + return NS_OK; +} + +NS_IMETHODIMP nsImapMailboxSpec::SetAllocatedPathName(const nsACString &aAllocatedPathName) +{ + mAllocatedPathName = aAllocatedPathName; + return NS_OK; +} + +NS_IMETHODIMP nsImapMailboxSpec::GetUnicharPathName(nsAString &aUnicharPathName) +{ + aUnicharPathName = aUnicharPathName; + return NS_OK; +} + +NS_IMETHODIMP nsImapMailboxSpec::SetUnicharPathName(const nsAString &aUnicharPathName) +{ + mUnicharPathName = aUnicharPathName; + return NS_OK; +} + +NS_IMETHODIMP nsImapMailboxSpec::GetHostName(nsACString &aHostName) +{ + aHostName = mHostName; + return NS_OK; +} + +NS_IMETHODIMP nsImapMailboxSpec::SetHostName(const nsACString &aHostName) +{ + mHostName = aHostName; + return NS_OK; +} + +NS_IMETHODIMP nsImapMailboxSpec::GetFlagState(nsIImapFlagAndUidState ** aFlagState) +{ + NS_ENSURE_ARG_POINTER(aFlagState); + NS_IF_ADDREF(*aFlagState = mFlagState); + return NS_OK; +} + +NS_IMETHODIMP nsImapMailboxSpec::SetFlagState(nsIImapFlagAndUidState * aFlagState) +{ + NS_ENSURE_ARG_POINTER(aFlagState); + mFlagState = aFlagState; + return NS_OK; +} + +nsImapMailboxSpec& nsImapMailboxSpec::operator= (const nsImapMailboxSpec& aCopy) +{ + mFolder_UIDVALIDITY = aCopy.mFolder_UIDVALIDITY; + mHighestModSeq = aCopy.mHighestModSeq; + mNumOfMessages = aCopy.mNumOfMessages; + mNumOfUnseenMessages = aCopy.mNumOfUnseenMessages; + mNumOfRecentMessages = aCopy.mNumOfRecentMessages; + + mBoxFlags = aCopy.mBoxFlags; + mSupportedUserFlags = aCopy.mSupportedUserFlags; + + mAllocatedPathName.Assign(aCopy.mAllocatedPathName); + mUnicharPathName.Assign(aCopy.mUnicharPathName); + mHostName.Assign(aCopy.mHostName); + + mFlagState = aCopy.mFlagState; + mNamespaceForFolder = aCopy.mNamespaceForFolder; + + mFolderSelected = aCopy.mFolderSelected; + mDiscoveredFromLsub = aCopy.mDiscoveredFromLsub; + + mOnlineVerified = aCopy.mOnlineVerified; + + return *this; +} + +// use the flagState to determine if the gaps in the msgUids correspond to gaps in the mailbox, +// in which case we can still use ranges. If flagState is null, we won't do this. +void AllocateImapUidString(uint32_t *msgUids, uint32_t &msgCount, + nsImapFlagAndUidState *flagState, nsCString &returnString) +{ + uint32_t startSequence = (msgCount > 0) ? msgUids[0] : 0xFFFFFFFF; + uint32_t curSequenceEnd = startSequence; + uint32_t total = msgCount; + int32_t curFlagStateIndex = -1; + + // a partial fetch flag state doesn't help us, so don't use it. + if (flagState && flagState->GetPartialUIDFetch()) + flagState = nullptr; + + + for (uint32_t keyIndex = 0; keyIndex < total; keyIndex++) + { + uint32_t curKey = msgUids[keyIndex]; + uint32_t nextKey = (keyIndex + 1 < total) ? msgUids[keyIndex + 1] : 0xFFFFFFFF; + bool lastKey = (nextKey == 0xFFFFFFFF); + + if (lastKey) + curSequenceEnd = curKey; + + if (!lastKey) + { + if (nextKey == curSequenceEnd + 1) + { + curSequenceEnd = nextKey; + curFlagStateIndex++; + continue; + } + if (flagState) + { + if (curFlagStateIndex == -1) + { + bool foundIt; + flagState->GetMessageFlagsFromUID(curSequenceEnd, &foundIt, &curFlagStateIndex); + if (!foundIt) + { + NS_WARNING("flag state missing key"); + // The start of this sequence is missing from flag state, so move + // on to the next key. + curFlagStateIndex = -1; + curSequenceEnd = startSequence = nextKey; + continue; + } + } + curFlagStateIndex++; + uint32_t nextUidInFlagState; + nsresult rv = flagState->GetUidOfMessage(curFlagStateIndex, &nextUidInFlagState); + if (NS_SUCCEEDED(rv) && nextUidInFlagState == nextKey) + { + curSequenceEnd = nextKey; + continue; + } + } + } + if (curSequenceEnd > startSequence) + { + returnString.AppendInt((int64_t) startSequence); + returnString += ':'; + returnString.AppendInt((int64_t) curSequenceEnd); + startSequence = nextKey; + curSequenceEnd = startSequence; + curFlagStateIndex = -1; + } + else + { + startSequence = nextKey; + curSequenceEnd = startSequence; + returnString.AppendInt((int64_t) msgUids[keyIndex]); + curFlagStateIndex = -1; + } + // check if we've generated too long a string - if there's no flag state, + // it means we just need to go ahead and generate a too long string + // because the calling code won't handle breaking up the strings. + if (flagState && returnString.Length() > 950) + { + msgCount = keyIndex; + break; + } + // If we are not the last item then we need to add the comma + // but it's important we do it here, after the length check + if (!lastKey) + returnString += ','; + } +} + +void ParseUidString(const char *uidString, nsTArray &keys) +{ + // This is in the form ,, or : + if (!uidString) + return; + + char curChar = *uidString; + bool isRange = false; + uint32_t curToken; + uint32_t saveStartToken = 0; + + for (const char *curCharPtr = uidString; curChar && *curCharPtr;) + { + const char *currentKeyToken = curCharPtr; + curChar = *curCharPtr; + while (curChar != ':' && curChar != ',' && curChar != '\0') + curChar = *curCharPtr++; + + // we don't need to null terminate currentKeyToken because strtoul + // stops at non-numeric chars. + curToken = strtoul(currentKeyToken, nullptr, 10); + if (isRange) + { + while (saveStartToken < curToken) + keys.AppendElement(saveStartToken++); + } + keys.AppendElement(curToken); + isRange = (curChar == ':'); + if (isRange) + saveStartToken = curToken + 1; + } +} + +void AppendUid(nsCString &msgIds, uint32_t uid) +{ + char buf[20]; + PR_snprintf(buf, sizeof(buf), "%u", uid); + msgIds.Append(buf); +} -- cgit v1.2.3