public FolderProcessResult copyAll(final Folder source, final Folder target, final boolean move, final AtomicBoolean cancelFlag, final Consumer<FolderProcessStatus> statusListener) {

        try (ContextLogger cLog = new ContextLogger("FolderUtils.copyAll: %s -> %s (move=%s)", source, target, move)) {

            //the following two-pass-copy/move is a bit complicated, but it ensures that copying/moving also works when target is a subdir of source or vice versa
            //For every change done here, please make sure that tests in ContentStorageTest are still passing!

            if (!pls.ensureFolder(source, false)) {
                return createFolderProcessResult(ProcessResult.SOURCE_NOT_READABLE, null, 0, 0, null);
            }
            if (!pls.ensureFolder(target, true)) {
                return createFolderProcessResult(ProcessResult.TARGET_NOT_WRITEABLE, null, 0, 0, null);
            }

            //initial status call
            sendCopyStatus(statusListener, null, 0, 0, null);

            // -- first Pass:createCopyResult collect Information
            final ImmutablePair<List<ImmutableTriple<ContentStorage.FileInformation, Folder, Integer>>, ImmutablePair<Integer, Integer>> copyAllFirstPhaseResult = copyAllFirstPassCollectInfo(source, target, cancelFlag);
            final ImmutablePair<Integer, Integer> sourceCopyCount = copyAllFirstPhaseResult.right;
            if (isCancelled(cancelFlag)) {
                return createFolderProcessResult(ProcessResult.ABORTED, null, 0, 0, sourceCopyCount);
            }
            final List<ImmutableTriple<ContentStorage.FileInformation, Folder, Integer>> fileList = copyAllFirstPhaseResult.left;
            if (fileList == null) {
                return createFolderProcessResult(ProcessResult.TARGET_NOT_WRITEABLE, null, 0, 0, sourceCopyCount);
            } else if (fileList.isEmpty()) {
                return createFolderProcessResult(ProcessResult.OK, null, 0, 0, sourceCopyCount);
            }
            cLog.add("p1:#s", fileList.size());

            // -- second Pass: do Copy/move
            final ImmutableTriple<ContentStorage.FileInformation, Integer, Integer> copyResult = copyAllSecondPassCopyMove(fileList, move, statusListener, cancelFlag, sourceCopyCount);

            //final status call
            sendCopyStatus(statusListener, null, copyResult.middle, copyResult.right, sourceCopyCount);

            cLog.add("p2:#%s#%s", copyResult.middle, copyResult.right);

            return createFolderProcessResult(
                    isCancelled(cancelFlag) ? ProcessResult.ABORTED : (copyResult.left == null ? ProcessResult.OK : ProcessResult.FAILURE), copyResult.left, copyResult.middle, copyResult.right, sourceCopyCount);
        }

    }
Copies the content of one folder into another. Source and target folder itself remain untouched.
<br />
Implementation supports handling of case when source and target point to same folder (maybe via different APIs e.g. File vs Document)
as well as when source folder is inside target or vice versa

@param source         source folder with content to copy
@param target         target folder to copy content to
@param move           if true, content is MOVED (e.g. sdeleted in source)
@param cancelFlag     optional. If not null and flag is set to true during copy, then running copy/move process is aborted. Will result in a Copy Result ABORTED to be returned.
@param statusListener optional callback. This is called many times during copying to inform about copy status. May be used e.g. to implement a progress bar.
                      status listener is called once initially (with files/dirsToCopy set to -1), then each time when a new file/dir is about to be copied, then one time when copying process is finished
                      so when a dir is copied with e.g. 3 dirs and 7 files inside, then the statuslistener is called 2 + 3 + 7 times.
@return result of copyAll call.
main/src/main/java/cgeo/geocaching/storage/FolderUtils.java