/* 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/. */ #ifndef COMM_MAILNEWS_PROTOCOLS_EXCHANGE_SRC_EXCHANGE_FOLDERCOPYHANDLER_H_ #define COMM_MAILNEWS_PROTOCOLS_EXCHANGE_SRC_EXCHANGE_FOLDERCOPYHANDLER_H_ #include "IExchangeClient.h" #include "ExchangeFolder.h" #include "nsHashKeys.h" #include "nscore.h" #include "nsIMsgCopyServiceListener.h" #include "nsIMsgFolder.h" #include "nsIMsgHdr.h" #include "nsIMsgWindow.h" #include "nsTArray.h" #include "nsTHashMap.h" class FolderCreateCopyCallbacks; /** * A handler for a single folder copy/move operation. * * An instance of `ExchangeFolderCopyHandler` is created for each copy/move * operation. A single operation always targets a single folder, but includes * its subfolders, meaning we might end up copying or moving multiple folders. * * The current process of copying or moving a folder is the following (assuming * no failure): * 1. A consumer requests a folder to be copied to an Exchange folder * (`ExchangeFolder::CopyFolder()`). * 2. The Exchange folder class instantiates a copy handler, and instructs it to * start the operation (`ExchangeFolderCopyHandler::CopyNextFolder()`). * 3. The copy handler instructs its Exchange client to begin creating a folder * with the current source folder's name on the server, underneath its logical * parent in the destination folder's hierarchy * (`IExchangeClient::CreateFolder()`). It is called with an instance of * `FolderCreateCopyCallbacks`. * 4. Once the folder has been created on the Exchange server, the Exchange * client instructs its callbacks instance to create the new folder locally * (`FolderCreateCopyCallbacks::OnSuccess()`). * 5. The callbacks instance notifies the copy handler of the operation's * success (`ExchangeFolderCopyHandler::OnFolderCreateFinished()`). * 6. The copy handler iterates over all the subfolders in the source folders, * and adds them to the end of the list of folders to copy. * 7. The copy handler builds a list of all the messages in the source folder * (non-recursively). If there are messages in this list, it instructs the * newly-created folder to start copying them from the source folder * (`ExchangeFolder::CopyMessages()`). It is called with an instance of * `MessageCopyListener`. If there are no messages to copy, it skips straight to * step 9. * 8. The new folder notifies the listener when all the messages have been * copied (`MessageCopyListener::OnStopCopy()`). * 9. `ExchangeFolderCopyHandler::CopyNextFolder()` is called. If there are more * folders to copy, the copy handler moves to the next folder in the list and * starts the process again from step 3. Otherwise the operation stops there. */ class ExchangeFolderCopyHandler { public: MOZ_DECLARE_REFCOUNTED_TYPENAME(ExchangeFolderCopyHandler) NS_INLINE_DECL_REFCOUNTING(ExchangeFolderCopyHandler) ExchangeFolderCopyHandler(nsIMsgFolder* srcFolder, ExchangeFolder* dstFolder, bool isMove, nsIMsgWindow* window, IExchangeClient* client, nsIMsgCopyServiceListener* copyServiceListener) : mDstFolder(dstFolder), mIsMove(isMove), mWindow(window), mFoldersToCopy({srcFolder}), mClient(client), mCopyServiceListener(copyServiceListener), mCurIndex(-1) { mDstParents.InsertOrUpdate(srcFolder, dstFolder); } /** * Start copying the next folder in line. * * Consumers should call his method with the source folder to initiate the * copy operation, after which the handler itself will call it for any * subfolder that needs to be copied as part of this operation. */ nsresult CopyNextFolder(); friend class FolderCreateCopyCallbacks; protected: virtual ~ExchangeFolderCopyHandler() = default; /** * The method below is expected to be called by a friend class, such as * `FolderCreateCopyCallbacks`. */ /** * Signals to the handler that the folder creation has finished, and provides * it with a reference to the newly-created folder. If `status` represents a * failure, `newFolder` may be null. */ nsresult OnFolderCreateFinished(nsresult status, nsIMsgFolder* newFolder); private: // Parameters of the copy/move operation. RefPtr mDstFolder; bool mIsMove; nsCOMPtr mWindow; // The folders to copy. This list starts with only the source folder, and may // grow as the operation progresses and subfolders are added to it. nsTArray> mFoldersToCopy; // A map tracking the destination folder in which to copy each folder in // `mFoldersToCopy` (or in other words, the final parent of each copy from // that list). // // This is necessary because we might not have references to the copy // destination of every folder in the list at the start of the whole // operation. For instance, if a folder A contains a subfolder B, at the start // of the operation we'll have a reference to A's copy destination // (`mDstFolder`), but not B's since A hasn't been copied over yet. nsTHashMap> mDstParents; // The Exchange client to use when creating the folder on the remote server. nsCOMPtr mClient; // The listener to inform of the status of the copy/move operation. RefPtr mCopyServiceListener; // The index into `mFoldersToCopy` of the folder currently being copied/moved. size_t mCurIndex{}; }; #endif // COMM_MAILNEWS_PROTOCOLS_EXCHANGE_SRC_EXCHANGE_FOLDERCOPYHANDLER_H_