summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/base/src/nsMsgCopyService.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mailnews/base/src/nsMsgCopyService.cpp
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/mailnews/base/src/nsMsgCopyService.cpp')
-rw-r--r--comm/mailnews/base/src/nsMsgCopyService.cpp587
1 files changed, 587 insertions, 0 deletions
diff --git a/comm/mailnews/base/src/nsMsgCopyService.cpp b/comm/mailnews/base/src/nsMsgCopyService.cpp
new file mode 100644
index 0000000000..22df6bb6e9
--- /dev/null
+++ b/comm/mailnews/base/src/nsMsgCopyService.cpp
@@ -0,0 +1,587 @@
+/* -*- 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 "nsMsgCopyService.h"
+#include "nsCOMArray.h"
+#include "nspr.h"
+#include "nsIFile.h"
+#include "nsIMsgFolderNotificationService.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsMsgUtils.h"
+#include "mozilla/Logging.h"
+
+static mozilla::LazyLogModule gCopyServiceLog("MsgCopyService");
+
+// ******************** nsCopySource ******************
+
+nsCopySource::nsCopySource() : m_processed(false) {
+ MOZ_COUNT_CTOR(nsCopySource);
+}
+
+nsCopySource::nsCopySource(nsIMsgFolder* srcFolder) : m_processed(false) {
+ MOZ_COUNT_CTOR(nsCopySource);
+ m_msgFolder = srcFolder;
+}
+
+nsCopySource::~nsCopySource() { MOZ_COUNT_DTOR(nsCopySource); }
+
+void nsCopySource::AddMessage(nsIMsgDBHdr* aMsg) {
+ m_messageArray.AppendElement(aMsg);
+}
+
+// ************ nsCopyRequest *****************
+//
+
+nsCopyRequest::nsCopyRequest()
+ : m_requestType(nsCopyMessagesType),
+ m_isMoveOrDraftOrTemplate(false),
+ m_processed(false),
+ m_newMsgFlags(0) {
+ MOZ_COUNT_CTOR(nsCopyRequest);
+}
+
+nsCopyRequest::~nsCopyRequest() {
+ MOZ_COUNT_DTOR(nsCopyRequest);
+
+ int32_t j = m_copySourceArray.Length();
+ while (j-- > 0) delete m_copySourceArray.ElementAt(j);
+}
+
+nsresult nsCopyRequest::Init(nsCopyRequestType type, nsISupports* aSupport,
+ nsIMsgFolder* dstFolder, bool bVal,
+ uint32_t newMsgFlags,
+ const nsACString& newMsgKeywords,
+ nsIMsgCopyServiceListener* listener,
+ nsIMsgWindow* msgWindow, bool allowUndo) {
+ nsresult rv = NS_OK;
+ m_requestType = type;
+ m_srcSupport = aSupport;
+ m_dstFolder = dstFolder;
+ m_isMoveOrDraftOrTemplate = bVal;
+ m_allowUndo = allowUndo;
+ m_newMsgFlags = newMsgFlags;
+ m_newMsgKeywords = newMsgKeywords;
+
+ if (listener) m_listener = listener;
+ if (msgWindow) {
+ m_msgWindow = msgWindow;
+ if (m_allowUndo) msgWindow->GetTransactionManager(getter_AddRefs(m_txnMgr));
+ }
+ if (type == nsCopyFoldersType) {
+ // To support multiple copy folder operations to the same destination, we
+ // need to save the leaf name of the src file spec so that FindRequest() is
+ // able to find the right request when copy finishes.
+ nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryInterface(aSupport, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsString folderName;
+ rv = srcFolder->GetName(folderName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ m_dstFolderName = folderName;
+ }
+
+ return rv;
+}
+
+nsCopySource* nsCopyRequest::AddNewCopySource(nsIMsgFolder* srcFolder) {
+ nsCopySource* newSrc = new nsCopySource(srcFolder);
+ if (newSrc) {
+ m_copySourceArray.AppendElement(newSrc);
+ if (srcFolder == m_dstFolder) newSrc->m_processed = true;
+ }
+ return newSrc;
+}
+
+// ************* nsMsgCopyService ****************
+//
+
+nsMsgCopyService::nsMsgCopyService() {}
+
+nsMsgCopyService::~nsMsgCopyService() {
+ int32_t i = m_copyRequests.Length();
+
+ while (i-- > 0) ClearRequest(m_copyRequests.ElementAt(i), NS_ERROR_FAILURE);
+}
+
+void nsMsgCopyService::LogCopyCompletion(nsISupports* aSrc,
+ nsIMsgFolder* aDest) {
+ nsCString srcFolderUri, destFolderUri;
+ nsCOMPtr<nsIMsgFolder> srcFolder(do_QueryInterface(aSrc));
+ if (srcFolder) srcFolder->GetURI(srcFolderUri);
+ aDest->GetURI(destFolderUri);
+ MOZ_LOG(gCopyServiceLog, mozilla::LogLevel::Info,
+ ("NotifyCompletion - src %s dest %s\n", srcFolderUri.get(),
+ destFolderUri.get()));
+}
+
+void nsMsgCopyService::LogCopyRequest(const char* logMsg,
+ nsCopyRequest* aRequest) {
+ nsCString srcFolderUri, destFolderUri;
+ nsCOMPtr<nsIMsgFolder> srcFolder(do_QueryInterface(aRequest->m_srcSupport));
+ if (srcFolder) srcFolder->GetURI(srcFolderUri);
+ aRequest->m_dstFolder->GetURI(destFolderUri);
+ uint32_t numMsgs = 0;
+ if (aRequest->m_requestType == nsCopyMessagesType &&
+ aRequest->m_copySourceArray.Length() > 0) {
+ numMsgs = aRequest->m_copySourceArray[0]->m_messageArray.Length();
+ }
+ MOZ_LOG(gCopyServiceLog, mozilla::LogLevel::Info,
+ ("request %p %s - src %s dest %s numItems %d type=%d", aRequest,
+ logMsg, srcFolderUri.get(), destFolderUri.get(), numMsgs,
+ aRequest->m_requestType));
+}
+
+nsresult nsMsgCopyService::ClearRequest(nsCopyRequest* aRequest, nsresult rv) {
+ if (aRequest) {
+ if (MOZ_LOG_TEST(gCopyServiceLog, mozilla::LogLevel::Info))
+ LogCopyRequest(
+ NS_SUCCEEDED(rv) ? "Clearing OK request" : "Clearing failed request",
+ aRequest);
+
+ if (NS_SUCCEEDED(rv) && aRequest->m_requestType == nsCopyFoldersType) {
+ // Send folder copy/move notifications to nsIMsgFolderListeners.
+ // BAD SMELL ALERT: Seems odd that this is the only place the folder
+ // notification is invoked from the copyService.
+ // For message copy/move operations, the folder code handles the
+ // notification (to take one example).
+ // This suggests lack of clarity of responsibility.
+ nsCOMPtr<nsIMsgFolderNotificationService> notifier(
+ do_GetService("@mozilla.org/messenger/msgnotificationservice;1"));
+ if (notifier) {
+ for (nsCopySource* copySource : aRequest->m_copySourceArray) {
+ notifier->NotifyFolderMoveCopyCompleted(
+ aRequest->m_isMoveOrDraftOrTemplate, copySource->m_msgFolder,
+ aRequest->m_dstFolder);
+ }
+ }
+ }
+
+ // undo stuff
+ if (aRequest->m_allowUndo && aRequest->m_copySourceArray.Length() > 1 &&
+ aRequest->m_txnMgr)
+ aRequest->m_txnMgr->EndBatch(false);
+
+ m_copyRequests.RemoveElement(aRequest);
+ if (aRequest->m_listener) aRequest->m_listener->OnStopCopy(rv);
+ delete aRequest;
+ }
+
+ return rv;
+}
+
+nsresult nsMsgCopyService::QueueRequest(nsCopyRequest* aRequest,
+ bool* aCopyImmediately) {
+ NS_ENSURE_ARG_POINTER(aRequest);
+ NS_ENSURE_ARG_POINTER(aCopyImmediately);
+ *aCopyImmediately = true;
+ nsCopyRequest* copyRequest;
+
+ // Check through previous requests to see if the copy can start immediately.
+ uint32_t cnt = m_copyRequests.Length();
+
+ for (uint32_t i = 0; i < cnt; i++) {
+ copyRequest = m_copyRequests.ElementAt(i);
+ if (aRequest->m_requestType == nsCopyFoldersType) {
+ // For copy folder, see if both destination folder (root)
+ // (ie, Local Folder) and folder name (ie, abc) are the same.
+ if (copyRequest->m_dstFolderName == aRequest->m_dstFolderName &&
+ SameCOMIdentity(copyRequest->m_dstFolder, aRequest->m_dstFolder)) {
+ *aCopyImmediately = false;
+ break;
+ }
+ } else if (SameCOMIdentity(copyRequest->m_dstFolder,
+ aRequest->m_dstFolder)) {
+ // If dst are same and we already have a request, we cannot copy
+ // immediately.
+ *aCopyImmediately = false;
+ break;
+ }
+ }
+
+ // Queue it.
+ m_copyRequests.AppendElement(aRequest);
+ return NS_OK;
+}
+
+nsresult nsMsgCopyService::DoCopy(nsCopyRequest* aRequest) {
+ NS_ENSURE_ARG(aRequest);
+ bool copyImmediately;
+ QueueRequest(aRequest, &copyImmediately);
+ if (MOZ_LOG_TEST(gCopyServiceLog, mozilla::LogLevel::Info))
+ LogCopyRequest(copyImmediately ? "DoCopy" : "QueueRequest", aRequest);
+
+ // if no active request for this dest folder then we can copy immediately
+ if (copyImmediately) return DoNextCopy();
+
+ return NS_OK;
+}
+
+nsresult nsMsgCopyService::DoNextCopy() {
+ nsresult rv = NS_OK;
+ nsCopyRequest* copyRequest = nullptr;
+ nsCopySource* copySource = nullptr;
+ uint32_t i, j, scnt;
+
+ uint32_t cnt = m_copyRequests.Length();
+ if (cnt > 0) {
+ nsCOMArray<nsIMsgFolder> activeTargets;
+
+ // ** jt -- always FIFO
+ for (i = 0; i < cnt; i++) {
+ copyRequest = m_copyRequests.ElementAt(i);
+ copySource = nullptr;
+ scnt = copyRequest->m_copySourceArray.Length();
+ if (!copyRequest->m_processed) {
+ // if the target folder of this request already has an active
+ // copy request, skip this request for now.
+ if (activeTargets.ContainsObject(copyRequest->m_dstFolder)) {
+ copyRequest = nullptr;
+ continue;
+ }
+ if (scnt <= 0) goto found; // must be CopyFileMessage
+ for (j = 0; j < scnt; j++) {
+ copySource = copyRequest->m_copySourceArray.ElementAt(j);
+ if (!copySource->m_processed) goto found;
+ }
+ if (j >= scnt) // all processed set the value
+ copyRequest->m_processed = true;
+ }
+ if (copyRequest->m_processed) {
+ // Keep track of folders actively getting copied to.
+ activeTargets.AppendObject(copyRequest->m_dstFolder);
+ }
+ }
+ found:
+ if (copyRequest && !copyRequest->m_processed) {
+ if (copyRequest->m_listener) copyRequest->m_listener->OnStartCopy();
+ if (copyRequest->m_requestType == nsCopyMessagesType && copySource) {
+ copySource->m_processed = true;
+ rv = copyRequest->m_dstFolder->CopyMessages(
+ copySource->m_msgFolder, copySource->m_messageArray,
+ copyRequest->m_isMoveOrDraftOrTemplate, copyRequest->m_msgWindow,
+ copyRequest->m_listener, false,
+ copyRequest->m_allowUndo); // isFolder operation false
+
+ } else if (copyRequest->m_requestType == nsCopyFoldersType) {
+ NS_ENSURE_STATE(copySource);
+ copySource->m_processed = true;
+
+ nsCOMPtr<nsIMsgFolder> dstFolder = copyRequest->m_dstFolder;
+ nsCOMPtr<nsIMsgFolder> srcFolder = copySource->m_msgFolder;
+
+ // If folder transfer is not within the same server and if a folder
+ // move was requested, set the request move flag false to avoid
+ // removing the list of marked deleted messages in the source folder.
+ bool isMove = copyRequest->m_isMoveOrDraftOrTemplate;
+ if (copyRequest->m_isMoveOrDraftOrTemplate) {
+ bool sameServer;
+ IsOnSameServer(dstFolder, srcFolder, &sameServer);
+ if (!sameServer) copyRequest->m_isMoveOrDraftOrTemplate = false;
+ }
+
+ // NOTE: The folder invokes NotifyCompletion() when the operation is
+ // complete. Some folders (localfolder!) invoke it before CopyFolder()
+ // even returns. This will likely delete the request object, so
+ // you have to assume that copyRequest is invalid when CopyFolder()
+ // returns.
+ rv = dstFolder->CopyFolder(srcFolder, isMove, copyRequest->m_msgWindow,
+ copyRequest->m_listener);
+ // If CopyFolder() fails (e.g. destination folder already exists),
+ // it won't send a completion notification (NotifyCompletion()).
+ // So copyRequest will still exist, and we need to ditch it.
+ if (NS_FAILED(rv)) {
+ ClearRequest(copyRequest, rv);
+ }
+ } else if (copyRequest->m_requestType == nsCopyFileMessageType) {
+ nsCOMPtr<nsIFile> aFile(
+ do_QueryInterface(copyRequest->m_srcSupport, &rv));
+ if (NS_SUCCEEDED(rv)) {
+ // ** in case of saving draft/template; the very first
+ // time we may not have the original message to replace
+ // with; if we do we shall have an instance of copySource
+ nsCOMPtr<nsIMsgDBHdr> aMessage;
+ if (copySource) {
+ aMessage = copySource->m_messageArray[0];
+ copySource->m_processed = true;
+ }
+ copyRequest->m_processed = true;
+ rv = copyRequest->m_dstFolder->CopyFileMessage(
+ aFile, aMessage, copyRequest->m_isMoveOrDraftOrTemplate,
+ copyRequest->m_newMsgFlags, copyRequest->m_newMsgKeywords,
+ copyRequest->m_msgWindow, copyRequest->m_listener);
+ }
+ }
+ }
+ }
+ return rv;
+}
+
+/**
+ * Find a request in m_copyRequests which matches the passed in source
+ * and destination folders.
+ *
+ * @param aSupport the iSupports of the source folder.
+ * @param dstFolder the destination folder of the copy request.
+ */
+nsCopyRequest* nsMsgCopyService::FindRequest(nsISupports* aSupport,
+ nsIMsgFolder* dstFolder) {
+ nsCopyRequest* copyRequest = nullptr;
+ uint32_t cnt = m_copyRequests.Length();
+ for (uint32_t i = 0; i < cnt; i++) {
+ copyRequest = m_copyRequests.ElementAt(i);
+ if (SameCOMIdentity(copyRequest->m_srcSupport, aSupport) &&
+ SameCOMIdentity(copyRequest->m_dstFolder.get(), dstFolder))
+ break;
+
+ // When copying folders the notification of the message copy serves as a
+ // proxy for the folder copy. Check for that here.
+ if (copyRequest->m_requestType == nsCopyFoldersType) {
+ // If the src is different then check next request.
+ if (!SameCOMIdentity(copyRequest->m_srcSupport, aSupport)) {
+ copyRequest = nullptr;
+ continue;
+ }
+
+ // See if the parent of the copied folder is the same as the one when the
+ // request was made. Note if the destination folder is already a server
+ // folder then no need to get parent.
+ nsCOMPtr<nsIMsgFolder> parentMsgFolder;
+ nsresult rv = NS_OK;
+ bool isServer = false;
+ dstFolder->GetIsServer(&isServer);
+ if (!isServer) rv = dstFolder->GetParent(getter_AddRefs(parentMsgFolder));
+ if ((NS_FAILED(rv)) || (!parentMsgFolder && !isServer) ||
+ (copyRequest->m_dstFolder.get() != parentMsgFolder)) {
+ copyRequest = nullptr;
+ continue;
+ }
+
+ // Now checks if the folder name is the same.
+ nsString folderName;
+ rv = dstFolder->GetName(folderName);
+ if (NS_FAILED(rv)) {
+ copyRequest = nullptr;
+ continue;
+ }
+
+ if (copyRequest->m_dstFolderName == folderName) break;
+ } else
+ copyRequest = nullptr;
+ }
+
+ return copyRequest;
+}
+
+NS_IMPL_ISUPPORTS(nsMsgCopyService, nsIMsgCopyService)
+
+MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP nsMsgCopyService::CopyMessages(
+ nsIMsgFolder* srcFolder, /* UI src folder */
+ nsTArray<RefPtr<nsIMsgDBHdr>> const& messages, nsIMsgFolder* dstFolder,
+ bool isMove, nsIMsgCopyServiceListener* listener, nsIMsgWindow* window,
+ bool allowUndo) {
+ NS_ENSURE_ARG_POINTER(srcFolder);
+ NS_ENSURE_ARG_POINTER(dstFolder);
+
+ MOZ_LOG(gCopyServiceLog, mozilla::LogLevel::Debug, ("CopyMessages"));
+
+ if (srcFolder == dstFolder) {
+ NS_ERROR("src and dest folders for msg copy can't be the same");
+ return NS_ERROR_FAILURE;
+ }
+ nsCopyRequest* copyRequest;
+ nsCopySource* copySource = nullptr;
+ nsIMsgDBHdr* msg;
+ nsCOMPtr<nsIMsgFolder> curFolder;
+ nsCOMPtr<nsISupports> aSupport;
+ int cnt;
+ nsresult rv;
+
+ // XXX TODO
+ // JUNK MAIL RELATED
+ // make sure dest folder exists
+ // and has proper flags, before we start copying?
+
+ // bail early if nothing to do
+ if (messages.IsEmpty()) {
+ if (listener) {
+ listener->OnStartCopy();
+ listener->OnStopCopy(NS_OK);
+ }
+ return NS_OK;
+ }
+
+ copyRequest = new nsCopyRequest();
+ if (!copyRequest) return NS_ERROR_OUT_OF_MEMORY;
+
+ nsTArray<RefPtr<nsIMsgDBHdr>> unprocessed = messages.Clone();
+ aSupport = srcFolder;
+
+ rv = copyRequest->Init(nsCopyMessagesType, aSupport, dstFolder, isMove,
+ 0 /* new msg flags, not used */, EmptyCString(),
+ listener, window, allowUndo);
+ if (NS_FAILED(rv)) goto done;
+
+ if (MOZ_LOG_TEST(gCopyServiceLog, mozilla::LogLevel::Info))
+ LogCopyRequest("CopyMessages request", copyRequest);
+
+ // Build up multiple nsCopySource objects. Each holds a single source folder
+ // and all the messages in the folder that are to be copied.
+ cnt = unprocessed.Length();
+ while (cnt-- > 0) {
+ msg = unprocessed[cnt];
+ rv = msg->GetFolder(getter_AddRefs(curFolder));
+
+ if (NS_FAILED(rv)) goto done;
+ if (!copySource) {
+ // Begin a folder grouping.
+ copySource = copyRequest->AddNewCopySource(curFolder);
+ if (!copySource) {
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ goto done;
+ }
+ }
+
+ // Stash message if in the current folder grouping.
+ if (curFolder == copySource->m_msgFolder) {
+ copySource->AddMessage(msg);
+ unprocessed.RemoveElementAt((size_t)cnt);
+ }
+
+ if (cnt == 0) {
+ // Finished a folder. Start a new pass to handle any remaining messages
+ // in other folders.
+ cnt = unprocessed.Length();
+ if (cnt > 0) {
+ // Force to create a new one and continue grouping the messages.
+ copySource = nullptr;
+ }
+ }
+ }
+
+ // undo stuff
+ if (NS_SUCCEEDED(rv) && copyRequest->m_allowUndo &&
+ copyRequest->m_copySourceArray.Length() > 1 && copyRequest->m_txnMgr) {
+ nsCOMPtr<nsITransactionManager> txnMgr = copyRequest->m_txnMgr;
+ txnMgr->BeginBatch(nullptr);
+ }
+
+done:
+
+ if (NS_FAILED(rv))
+ delete copyRequest;
+ else
+ rv = DoCopy(copyRequest);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsMsgCopyService::CopyFolder(nsIMsgFolder* srcFolder, nsIMsgFolder* dstFolder,
+ bool isMove, nsIMsgCopyServiceListener* listener,
+ nsIMsgWindow* window) {
+ NS_ENSURE_ARG_POINTER(srcFolder);
+ NS_ENSURE_ARG_POINTER(dstFolder);
+ nsCopyRequest* copyRequest;
+ nsresult rv;
+ nsCOMPtr<nsIMsgFolder> curFolder;
+
+ copyRequest = new nsCopyRequest();
+ rv = copyRequest->Init(nsCopyFoldersType, srcFolder, dstFolder, isMove,
+ 0 /* new msg flags, not used */, EmptyCString(),
+ listener, window, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ copyRequest->AddNewCopySource(srcFolder);
+ return DoCopy(copyRequest);
+}
+
+NS_IMETHODIMP
+nsMsgCopyService::CopyFileMessage(nsIFile* file, nsIMsgFolder* dstFolder,
+ nsIMsgDBHdr* msgToReplace, bool isDraft,
+ uint32_t aMsgFlags,
+ const nsACString& aNewMsgKeywords,
+ nsIMsgCopyServiceListener* listener,
+ nsIMsgWindow* window) {
+ nsresult rv = NS_ERROR_NULL_POINTER;
+ nsCopyRequest* copyRequest;
+ nsCopySource* copySource = nullptr;
+
+ NS_ENSURE_ARG_POINTER(file);
+ NS_ENSURE_ARG_POINTER(dstFolder);
+
+ copyRequest = new nsCopyRequest();
+ if (!copyRequest) return rv;
+
+ rv = copyRequest->Init(nsCopyFileMessageType, file, dstFolder, isDraft,
+ aMsgFlags, aNewMsgKeywords, listener, window, false);
+ if (NS_FAILED(rv)) goto done;
+
+ if (msgToReplace) {
+ // The actual source of the message is a file not a folder, but
+ // we still need an nsCopySource to reference the old message header
+ // which will be used to recover message metadata.
+ copySource = copyRequest->AddNewCopySource(nullptr);
+ if (!copySource) {
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ goto done;
+ }
+ copySource->AddMessage(msgToReplace);
+ }
+
+done:
+ if (NS_FAILED(rv)) {
+ delete copyRequest;
+ } else {
+ rv = DoCopy(copyRequest);
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsMsgCopyService::NotifyCompletion(nsISupports* aSupport,
+ nsIMsgFolder* dstFolder, nsresult result) {
+ if (MOZ_LOG_TEST(gCopyServiceLog, mozilla::LogLevel::Info))
+ LogCopyCompletion(aSupport, dstFolder);
+ nsCopyRequest* copyRequest = nullptr;
+ uint32_t numOrigRequests = m_copyRequests.Length();
+ do {
+ // loop for copy requests, because if we do a cross server folder copy,
+ // we'll have a copy request for the folder copy, which will in turn
+ // generate a copy request for the messages in the folder, which
+ // will have the same src support.
+ copyRequest = FindRequest(aSupport, dstFolder);
+
+ if (copyRequest) {
+ // ClearRequest can cause a new request to get added to m_copyRequests
+ // with matching source and dest folders if the copy listener starts
+ // a new copy. We want to ignore any such request here, because it wasn't
+ // the one that was completed. So we keep track of how many original
+ // requests there were.
+ if (m_copyRequests.IndexOf(copyRequest) >= numOrigRequests) break;
+ // check if this copy request is done by making sure all the
+ // sources have been processed.
+ int32_t sourceIndex, sourceCount;
+ sourceCount = copyRequest->m_copySourceArray.Length();
+ for (sourceIndex = 0; sourceIndex < sourceCount;) {
+ if (!(copyRequest->m_copySourceArray.ElementAt(sourceIndex))
+ ->m_processed)
+ break;
+ sourceIndex++;
+ }
+ // if all sources processed, mark the request as processed
+ if (sourceIndex >= sourceCount) copyRequest->m_processed = true;
+ // if this request is done, or failed, clear it.
+ if (copyRequest->m_processed || NS_FAILED(result)) {
+ ClearRequest(copyRequest, result);
+ numOrigRequests--;
+ } else
+ break;
+ } else
+ break;
+ } while (copyRequest);
+
+ return DoNextCopy();
+}