NS_IMETHODIMP nsMsgBrkMBoxStore::CopyFolder(nsIMsgFolder *aSrcFolder, nsIMsgFolder *aDstFolder, bool aIsMoveFolder, nsIMsgWindow *aMsgWindow, nsIMsgCopyServiceListener *aListener, const nsAString &aNewName) { NS_ENSURE_ARG_POINTER(aSrcFolder); NS_ENSURE_ARG_POINTER(aDstFolder); nsAutoString folderName; if (aNewName.IsEmpty()) aSrcFolder->GetName(folderName); else folderName.Assign(aNewName); nsAutoString safeFolderName(folderName); NS_MsgHashIfNecessary(safeFolderName); nsCOMPtr<nsIMsgLocalMailFolder> localSrcFolder(do_QueryInterface(aSrcFolder)); nsCOMPtr<nsIMsgDatabase> srcDB; if (localSrcFolder) localSrcFolder->GetDatabaseWOReparse(getter_AddRefs(srcDB)); bool summaryValid = !!srcDB; srcDB = nullptr; aSrcFolder->ForceDBClosed(); nsCOMPtr<nsIFile> oldPath; nsresult rv = aSrcFolder->GetFilePath(getter_AddRefs(oldPath)); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr<nsIFile> summaryFile; GetSummaryFileLocation(oldPath, getter_AddRefs(summaryFile)); nsCOMPtr<nsIFile> newPath; rv = aDstFolder->GetFilePath(getter_AddRefs(newPath)); NS_ENSURE_SUCCESS(rv,rv); bool newPathIsDirectory = false; newPath->IsDirectory(&newPathIsDirectory); if (!newPathIsDirectory) { AddDirectorySeparator(newPath); newPath->Create(nsIFile::DIRECTORY_TYPE, 0700); } nsCOMPtr<nsIFile> origPath; oldPath->Clone(getter_AddRefs(origPath)); //copying necessary for aborting.... if failure return rv = oldPath->CopyTo(newPath, safeFolderName); NS_ENSURE_SUCCESS(rv, rv); // Will fail if a file by that name exists // Copy to dir can fail if filespec does not exist. If copy fails, we test // if the filespec exist or not, if it does not that's ok, we continue // without copying it. If it fails and filespec exist and is not zero sized // there is real problem // Copy the file to the new dir nsAutoString dbName(safeFolderName); dbName += NS_LITERAL_STRING(SUMMARY_SUFFIX); rv = summaryFile->CopyTo(newPath, dbName); if (NS_FAILED(rv)) // Test if the copy is successful { // Test if the filespec has data bool exists; int64_t fileSize; summaryFile->Exists(&exists); summaryFile->GetFileSize(&fileSize); if (exists && fileSize > 0) NS_ENSURE_SUCCESS(rv, rv); // Yes, it should have worked ! // else case is filespec is zero sized, no need to copy it, // not an error } nsCOMPtr<nsIMsgFolder> newMsgFolder; rv = aDstFolder->AddSubfolder(safeFolderName, getter_AddRefs(newMsgFolder)); NS_ENSURE_SUCCESS(rv, rv); // linux and mac are not good about maintaining the file stamp when copying // folders around. So if the source folder db is good, set the dest db as // good too. nsCOMPtr<nsIMsgDatabase> destDB; if (summaryValid) { nsAutoString folderLeafName; origPath->GetLeafName(folderLeafName); newPath->Append(folderLeafName); nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = msgDBService->OpenMailDBFromFile(newPath, newMsgFolder, false, true, getter_AddRefs(destDB)); if (rv == NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE && destDB) destDB->SetSummaryValid(true); } newMsgFolder->SetPrettyName(folderName); uint32_t flags; aSrcFolder->GetFlags(&flags); newMsgFolder->SetFlags(flags); bool changed = false; rv = aSrcFolder->MatchOrChangeFilterDestination(newMsgFolder, true, &changed); if (changed) aSrcFolder->AlertFilterChanged(aMsgWindow); nsCOMPtr<nsISimpleEnumerator> enumerator; rv = aSrcFolder->GetSubFolders(getter_AddRefs(enumerator)); NS_ENSURE_SUCCESS(rv, rv); // Copy subfolders to the new location nsresult copyStatus = NS_OK; nsCOMPtr<nsIMsgLocalMailFolder> localNewFolder(do_QueryInterface(newMsgFolder, &rv)); if (NS_SUCCEEDED(rv)) { bool hasMore; while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore && NS_SUCCEEDED(copyStatus)) { nsCOMPtr<nsISupports> item; enumerator->GetNext(getter_AddRefs(item)); nsCOMPtr<nsIMsgFolder> folder(do_QueryInterface(item)); if (!folder) continue; copyStatus = localNewFolder->CopyFolderLocal(folder, false, aMsgWindow, aListener); // Test if the call succeeded, if not we have to stop recursive call if (NS_FAILED(copyStatus)) { // Copy failed we have to notify caller to handle the error and stop // moving the folders. In case this happens to the topmost level of // recursive call, then we just need to break from the while loop and // go to error handling code. if (!aIsMoveFolder) return copyStatus; break; } } } if (aIsMoveFolder && NS_SUCCEEDED(copyStatus)) { if (localNewFolder) { nsCOMPtr<nsISupports> srcSupport(do_QueryInterface(aSrcFolder)); localNewFolder->OnCopyCompleted(srcSupport, true); } // Notify the "folder" that was dragged and dropped has been created. No // need to do this for its subfolders. isMoveFolder will be true for folder. aDstFolder->NotifyItemAdded(newMsgFolder); nsCOMPtr<nsIMsgFolder> msgParent; aSrcFolder->GetParent(getter_AddRefs(msgParent)); aSrcFolder->SetParent(nullptr); if (msgParent) { // The files have already been moved, so delete storage false msgParent->PropagateDelete(aSrcFolder, false, aMsgWindow); oldPath->Remove(false); //berkeley mailbox // We need to force closed the source db nsCOMPtr<nsIMsgDatabase> srcDB; aSrcFolder->Delete(); nsCOMPtr<nsIFile> parentPath; rv = msgParent->GetFilePath(getter_AddRefs(parentPath)); NS_ENSURE_SUCCESS(rv,rv); AddDirectorySeparator(parentPath); nsCOMPtr<nsISimpleEnumerator> children; parentPath->GetDirectoryEntries(getter_AddRefs(children)); bool more; // checks if the directory is empty or not if (children && NS_SUCCEEDED(children->HasMoreElements(&more)) && !more) parentPath->Remove(true); } } else { // This is the case where the copy of a subfolder failed. // We have to delete the newDirectory tree to make a "rollback". // Someone should add a popup to warn the user that the move was not // possible. if (aIsMoveFolder && NS_FAILED(copyStatus)) { nsCOMPtr<nsIMsgFolder> msgParent; newMsgFolder->ForceDBClosed(); newMsgFolder->GetParent(getter_AddRefs(msgParent)); newMsgFolder->SetParent(nullptr); if (msgParent) { msgParent->PropagateDelete(newMsgFolder, false, aMsgWindow); newMsgFolder->Delete(); newMsgFolder->ForceDBClosed(); AddDirectorySeparator(newPath); newPath->Remove(true); //berkeley mailbox } return NS_ERROR_FAILURE; } } return NS_OK; }
NS_IMETHODIMP nsMsgMaildirStore::CopyFolder(nsIMsgFolder *aSrcFolder, nsIMsgFolder *aDstFolder, bool aIsMoveFolder, nsIMsgWindow *aMsgWindow, nsIMsgCopyServiceListener *aListener) { NS_ENSURE_ARG_POINTER(aSrcFolder); NS_ENSURE_ARG_POINTER(aDstFolder); nsString folderName; aSrcFolder->GetName(folderName); nsAutoString safeFolderName(folderName); NS_MsgHashIfNecessary(safeFolderName); nsCOMPtr<nsIMsgLocalMailFolder> localSrcFolder(do_QueryInterface(aSrcFolder)); aSrcFolder->ForceDBClosed(); nsCOMPtr<nsIFile> oldPath; nsresult rv = aSrcFolder->GetFilePath(getter_AddRefs(oldPath)); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr<nsIFile> summaryFile; GetSummaryFileLocation(oldPath, getter_AddRefs(summaryFile)); nsCOMPtr<nsIFile> newPath; rv = aDstFolder->GetFilePath(getter_AddRefs(newPath)); NS_ENSURE_SUCCESS(rv, rv); // create target directory based on our current path bool isServer; aDstFolder->GetIsServer(&isServer); rv = CreateDirectoryForFolder(newPath, isServer); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIFile> origPath; oldPath->Clone(getter_AddRefs(origPath)); rv = oldPath->CopyTo(newPath, EmptyString()); NS_ENSURE_SUCCESS(rv, rv); //will fail if a file by that name exists // Copy to dir can fail if file does not exist. If copy fails, we test // if the file exists or not, if it does not that's ok, we continue // without copying it. If it fails and file exist and is not zero sized // there is real problem. rv = summaryFile->CopyTo(newPath, EmptyString()); if (!NS_SUCCEEDED(rv)) { // Test if the file is not empty bool exists; int64_t fileSize; summaryFile->Exists(&exists); summaryFile->GetFileSize(&fileSize); if (exists && fileSize > 0) NS_ENSURE_SUCCESS(rv, rv); // Yes, it should have worked! // else case is file is zero sized, no need to copy it, // not an error // else case is file does not exist - not an error } nsCOMPtr<nsIMsgFolder> newMsgFolder; rv = aDstFolder->AddSubfolder(safeFolderName, getter_AddRefs(newMsgFolder)); NS_ENSURE_SUCCESS(rv, rv); newMsgFolder->SetPrettyName(folderName); uint32_t flags; aSrcFolder->GetFlags(&flags); newMsgFolder->SetFlags(flags); bool changed = false; rv = aSrcFolder->MatchOrChangeFilterDestination(newMsgFolder, true, &changed); if (changed) aSrcFolder->AlertFilterChanged(aMsgWindow); nsCOMPtr<nsISimpleEnumerator> enumerator; rv = aSrcFolder->GetSubFolders(getter_AddRefs(enumerator)); NS_ENSURE_SUCCESS(rv, rv); // Copy subfolders to the new location nsresult copyStatus = NS_OK; nsCOMPtr<nsIMsgLocalMailFolder> localNewFolder(do_QueryInterface(newMsgFolder, &rv)); if (NS_SUCCEEDED(rv)) { bool hasMore; while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore && NS_SUCCEEDED(copyStatus)) { nsCOMPtr<nsISupports> item; enumerator->GetNext(getter_AddRefs(item)); nsCOMPtr<nsIMsgFolder> folder(do_QueryInterface(item)); if (!folder) continue; copyStatus = localNewFolder->CopyFolderLocal(folder, false, aMsgWindow, aListener); // Test if the call succeeded, if not we have to stop recursive call if (NS_FAILED(copyStatus)) { // Copy failed we have to notify caller to handle the error and stop // moving the folders. In case this happens to the topmost level of // recursive call, then we just need to break from the while loop and // go to error handling code. if (!aIsMoveFolder) return copyStatus; break; } } } if (aIsMoveFolder && NS_SUCCEEDED(copyStatus)) { if (localNewFolder) { nsCOMPtr<nsISupports> srcSupport(do_QueryInterface(aSrcFolder)); localNewFolder->OnCopyCompleted(srcSupport, true); } // Notify that the folder that was dragged and dropped has been created. // No need to do this for its subfolders - isMoveFolder will be true for folder. aDstFolder->NotifyItemAdded(newMsgFolder); nsCOMPtr<nsIMsgFolder> msgParent; aSrcFolder->GetParent(getter_AddRefs(msgParent)); aSrcFolder->SetParent(nullptr); if (msgParent) { // The files have already been moved, so delete storage false msgParent->PropagateDelete(aSrcFolder, false, aMsgWindow); oldPath->Remove(true); nsCOMPtr<nsIMsgDatabase> srcDB; // we need to force closed the source db aSrcFolder->Delete(); nsCOMPtr<nsIFile> parentPath; rv = msgParent->GetFilePath(getter_AddRefs(parentPath)); NS_ENSURE_SUCCESS(rv,rv); AddDirectorySeparator(parentPath); nsCOMPtr<nsISimpleEnumerator> children; parentPath->GetDirectoryEntries(getter_AddRefs(children)); bool more; // checks if the directory is empty or not if (children && NS_SUCCEEDED(children->HasMoreElements(&more)) && !more) parentPath->Remove(true); } } else { // This is the case where the copy of a subfolder failed. // We have to delete the newDirectory tree to make a "rollback". // Someone should add a popup to warn the user that the move was not // possible. if (aIsMoveFolder && NS_FAILED(copyStatus)) { nsCOMPtr<nsIMsgFolder> msgParent; newMsgFolder->ForceDBClosed(); newMsgFolder->GetParent(getter_AddRefs(msgParent)); newMsgFolder->SetParent(nullptr); if (msgParent) { msgParent->PropagateDelete(newMsgFolder, false, aMsgWindow); newMsgFolder->Delete(); newMsgFolder->ForceDBClosed(); AddDirectorySeparator(newPath); newPath->Remove(true); //berkeley mailbox } return NS_ERROR_FAILURE; } } return NS_OK; }