Bug 1317117 - call msgStore folder deletion during imap/news empty trash. r=jorgk
authorBen Campbell <benc@thunderbird.net>
Fri, 14 Sep 2018 12:03:52 +1200
changeset 33335 930dfab9478d6d09ba25ac32dd5831df204691d3
parent 33334 5aca0faf144579996c8d11dee4c37c7abf2443af
child 33336 95e9292660b75686d686c96f02bd334c8d0c24a0
push id387
push userclokep@gmail.com
push dateMon, 10 Dec 2018 21:30:47 +0000
reviewersjorgk
bugs1317117
Bug 1317117 - call msgStore folder deletion during imap/news empty trash. r=jorgk Also factors out some common code into nsMSgDBFolder::Delete(), and makes a couple of incidental changes to try and clarify the responsibilies of nsIMsgPluggableStore::DeleteFolder().
mailnews/base/public/nsIMsgPluggableStore.idl
mailnews/base/util/nsMsgDBFolder.cpp
mailnews/imap/src/nsImapMailFolder.cpp
mailnews/local/src/nsLocalMailFolder.cpp
mailnews/local/src/nsLocalMailFolder.h
mailnews/local/src/nsMsgBrkMBoxStore.cpp
mailnews/local/src/nsMsgMaildirStore.cpp
mailnews/news/src/nsNewsFolder.cpp
--- a/mailnews/base/public/nsIMsgPluggableStore.idl
+++ b/mailnews/base/public/nsIMsgPluggableStore.idl
@@ -46,18 +46,18 @@ interface nsIMsgPluggableStore : nsISupp
    * @param aFolderName leaf name of folder.
    * @return newly created folder.
    * @exception NS_MSG_FOLDER_EXISTS If the child exists.
    * @exception NS_MSG_CANT_CREATE_FOLDER for other errors.
    */
   nsIMsgFolder createFolder(in nsIMsgFolder aParent, in AString aFolderName);
 
   /**
-   * Delete the passed in folder. This is a real delete, not a move
-   * to the trash folder.
+   * Delete storage for a folder and its subfolders, if any.
+   * This is a real delete, not a move to the trash folder.
    *
    * @param aFolder folder to delete
    */
   void deleteFolder(in nsIMsgFolder aFolder);
 
   /**
    * Rename storage for an existing folder.
    *
--- a/mailnews/base/util/nsMsgDBFolder.cpp
+++ b/mailnews/base/util/nsMsgDBFolder.cpp
@@ -3609,17 +3609,41 @@ NS_IMETHODIMP nsMsgDBFolder::GetShowDele
 {
   NS_ENSURE_ARG_POINTER(showDeletedMessages);
   *showDeletedMessages = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsMsgDBFolder::Delete()
 {
-  return NS_OK;
+  ForceDBClosed();
+
+  // Delete the .msf file.
+  // NOTE: this doesn't remove .msf files in subfolders, but
+  // both nsMsgBrkMBoxStore::DeleteFolder() and
+  // nsMsgMaildirStore::DeleteFolder() will remove those .msf files
+  // as a side-effect of deleting the .sbd directory.
+  nsCOMPtr<nsIFile> summaryFile;
+  nsresult rv = GetSummaryFile(getter_AddRefs(summaryFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+  bool exists = false;
+  summaryFile->Exists(&exists);
+  if (exists) {
+    rv = summaryFile->Remove(false);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Ask the msgStore to delete the actual storage (mbox, maildir or whatever
+  // else may be supported in future).
+  nsCOMPtr<nsIMsgPluggableStore> msgStore;
+  rv = GetMsgStore(getter_AddRefs(msgStore));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = msgStore->DeleteFolder(this);
+
+  return rv;
 }
 
 NS_IMETHODIMP nsMsgDBFolder::DeleteSubFolders(nsIArray *folders,
                                               nsIMsgWindow *msgWindow)
 {
   uint32_t count;
   nsresult rv = folders->GetLength(&count);
   for(uint32_t i = 0; i < count; i++)
--- a/mailnews/imap/src/nsImapMailFolder.cpp
+++ b/mailnews/imap/src/nsImapMailFolder.cpp
@@ -1438,39 +1438,33 @@ NS_IMETHODIMP nsImapMailFolder::EmptyTra
       {
         bool isAOLServer = false;
         imapServer->GetIsAOLServer(&isAOLServer);
         if (isAOLServer)
           return NS_ERROR_FAILURE;  // we will not be performing an empty trash....
       } // if we fetched an imap server
     } // if emptying trash on exit which is done through the account manager.
 
-    nsCOMPtr<nsIMsgDatabase> trashDB;
     if (WeAreOffline())
     {
       nsCOMPtr <nsIMsgDatabase> trashDB;
       rv = trashFolder->GetMsgDatabase(getter_AddRefs(trashDB));
       if (trashDB)
       {
         nsMsgKey fakeKey;
         trashDB->GetNextFakeOfflineMsgKey(&fakeKey);
 
         nsCOMPtr <nsIMsgOfflineImapOperation> op;
         rv = trashDB->GetOfflineOpForKey(fakeKey, true, getter_AddRefs(op));
         trashFolder->SetFlag(nsMsgFolderFlags::OfflineEvents);
         op->SetOperation(nsIMsgOfflineImapOperation::kDeleteAllMsgs);
       }
       return rv;
     }
-    nsCOMPtr <nsIDBFolderInfo> transferInfo;
-    rv = trashFolder->GetDBTransferInfo(getter_AddRefs(transferInfo));
-    rv = trashFolder->Delete(); // delete summary spec
-    trashFolder->SetDBTransferInfo(transferInfo);
-
-    trashFolder->SetSizeOnDisk(0);
+
     nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aListener)
       rv = imapService->DeleteAllMessages(trashFolder, aListener, nullptr);
     else
     {
       nsCOMPtr<nsIUrlListener> urlListener = do_QueryInterface(trashFolder);
@@ -1506,63 +1500,41 @@ NS_IMETHODIMP nsImapMailFolder::EmptyTra
       for (int32_t i = array.Count() - 1; i >= 0; i--)
       {
         trashFolder->PropagateDelete(array[i], true, aMsgWindow);
         // Remove the object, presumably to free it up before we delete the next.
         array.RemoveObjectAt(i);
       }
     }
 
-    // The trash folder has effectively been deleted
+    nsCOMPtr <nsIDBFolderInfo> transferInfo;
+    rv = trashFolder->GetDBTransferInfo(getter_AddRefs(transferInfo));
+    NS_ENSURE_SUCCESS(rv, rv);
+    // Bulk-delete all the messages by deleting the msf file and storage.
+    // This is a little kludgy.
+    rv = trashFolder->Delete();
+    NS_ENSURE_SUCCESS(rv, rv);
+    trashFolder->SetDBTransferInfo(transferInfo);
+    trashFolder->SetSizeOnDisk(0);
+
+    // The trash folder has effectively been deleted.
     nsCOMPtr<nsIMsgFolderNotificationService> notifier(do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID));
     if (notifier)
       notifier->NotifyFolderDeleted(trashFolder);
 
     return NS_OK;
   }
   return rv;
 }
 
 NS_IMETHODIMP nsImapMailFolder::Delete()
 {
-  nsresult rv;
-  if (!mDatabase)
-  {
-    // Check if anyone has this db open. If so, do a force closed.
-    nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    msgDBService->CachedDBForFolder(this, getter_AddRefs(mDatabase));
-  }
-  if (mDatabase)
-  {
-    mDatabase->ForceClosed();
-    mDatabase = nullptr;
-  }
-
-  nsCOMPtr<nsIFile> path;
-  rv = GetFilePath(getter_AddRefs(path));
-  if (NS_SUCCEEDED(rv))
-  {
-    nsCOMPtr<nsIFile> summaryLocation;
-    rv = GetSummaryFileLocation(path, getter_AddRefs(summaryLocation));
-    if (NS_SUCCEEDED(rv))
-    {
-      bool exists = false;
-      rv = summaryLocation->Exists(&exists);
-      if (NS_SUCCEEDED(rv) && exists)
-      {
-        rv = summaryLocation->Remove(false);
-        if (NS_FAILED(rv))
-          NS_WARNING("failed to remove imap summary file");
-      }
-    }
-  }
-  if (mPath)
-    mPath->Remove(false);
-  // should notify nsIMsgFolderListeners about the folder getting deleted...
+  nsresult rv = nsMsgDBFolder::Delete();
+
+  // Should notify nsIMsgFolderListeners about the folder getting deleted?
   return rv;
 }
 
 NS_IMETHODIMP nsImapMailFolder::Rename (const nsAString& newName, nsIMsgWindow *msgWindow)
 {
   if (mFlags & nsMsgFolderFlags::Virtual)
     return nsMsgDBFolder::Rename(newName, msgWindow);
   nsresult rv;
--- a/mailnews/local/src/nsLocalMailFolder.cpp
+++ b/mailnews/local/src/nsLocalMailFolder.cpp
@@ -638,18 +638,16 @@ NS_IMETHODIMP nsMsgLocalMailFolder::Empt
                                                nsIUrlListener *aListener)
 {
   nsresult rv;
   nsCOMPtr<nsIMsgFolder> trashFolder;
   rv = GetTrashFolder(getter_AddRefs(trashFolder));
   if (NS_SUCCEEDED(rv))
   {
     uint32_t flags;
-    nsCString trashUri;
-    trashFolder->GetURI(trashUri);
     trashFolder->GetFlags(&flags);
     int32_t totalMessages = 0;
     rv = trashFolder->GetTotalMessages(true, &totalMessages);
     if (totalMessages <= 0)
     {
       nsCOMPtr<nsISimpleEnumerator> enumerator;
       rv = trashFolder->GetSubFolders(getter_AddRefs(enumerator));
       NS_ENSURE_SUCCESS(rv,rv);
@@ -735,53 +733,16 @@ nsresult nsMsgLocalMailFolder::IsChildOf
       return rv;
     }
 
     thisFolder = parentFolder;
   }
   return rv;
 }
 
-NS_IMETHODIMP nsMsgLocalMailFolder::Delete()
-{
-  nsresult rv;
-  nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  msgDBService->CachedDBForFolder(this, getter_AddRefs(mDatabase));
-  if (mDatabase)
-  {
-    mDatabase->ForceClosed();
-    mDatabase = nullptr;
-  }
-
-  nsCOMPtr<nsIMsgIncomingServer> server;
-  rv = GetServer(getter_AddRefs(server));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIMsgPluggableStore> msgStore;
-
-  rv = server->GetMsgStore(getter_AddRefs(msgStore));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr <nsIFile> summaryFile;
-  rv = GetSummaryFile(getter_AddRefs(summaryFile));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  //Clean up .sbd folder if it exists.
-  // Remove summary file.
-  rv = summaryFile->Remove(false);
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Could not delete msg summary file");
-
-  rv = msgStore->DeleteFolder(this);
-  if (rv == NS_ERROR_FILE_NOT_FOUND ||
-      rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
-    rv = NS_OK; // virtual folders do not have a msgStore file
-  return rv;
-}
-
 NS_IMETHODIMP nsMsgLocalMailFolder::DeleteSubFolders(nsIArray *folders, nsIMsgWindow *msgWindow)
 {
   nsresult rv;
   bool isChildOfTrash;
   IsChildOfTrash(&isChildOfTrash);
 
   // we don't allow multiple folder selection so this is ok.
   nsCOMPtr<nsIMsgFolder> folder = do_QueryElementAt(folders, 0);
--- a/mailnews/local/src/nsLocalMailFolder.h
+++ b/mailnews/local/src/nsLocalMailFolder.h
@@ -120,17 +120,16 @@ public:
   NS_IMETHOD GetMessages(nsISimpleEnumerator **result) override;
   NS_IMETHOD UpdateFolder(nsIMsgWindow *aWindow) override;
 
   NS_IMETHOD CreateSubfolder(const nsAString& folderName ,nsIMsgWindow *msgWindow) override;
 
   NS_IMETHOD Compact(nsIUrlListener *aListener, nsIMsgWindow *aMsgWindow) override;
   NS_IMETHOD CompactAll(nsIUrlListener *aListener, nsIMsgWindow *aMsgWindow, bool aCompactOfflineAlso) override;
   NS_IMETHOD EmptyTrash(nsIMsgWindow *msgWindow, nsIUrlListener *aListener) override;
-  NS_IMETHOD Delete () override;
   NS_IMETHOD DeleteSubFolders(nsIArray *folders, nsIMsgWindow *msgWindow) override;
   NS_IMETHOD CreateStorageIfMissing(nsIUrlListener* urlListener) override;
   NS_IMETHOD Rename (const nsAString& aNewName, nsIMsgWindow *msgWindow) override;
   NS_IMETHOD RenameSubFolders (nsIMsgWindow *msgWindow, nsIMsgFolder *oldFolder) override;
 
   NS_IMETHOD GetPrettyName(nsAString& prettyName) override; // Override of the base, for top-level mail folder
   NS_IMETHOD SetPrettyName(const nsAString& aName) override;
 
--- a/mailnews/local/src/nsMsgBrkMBoxStore.cpp
+++ b/mailnews/local/src/nsMsgBrkMBoxStore.cpp
@@ -295,36 +295,40 @@ NS_IMETHODIMP nsMsgBrkMBoxStore::SetSumm
   }
   aDB->Commit(nsMsgDBCommitType::kLargeCommit);
   return rv;
 }
 
 NS_IMETHODIMP nsMsgBrkMBoxStore::DeleteFolder(nsIMsgFolder *aFolder)
 {
   NS_ENSURE_ARG_POINTER(aFolder);
-  //Delete mailbox
+  bool exists;
+
+  // Delete mbox file.
   nsCOMPtr<nsIFile> pathFile;
   nsresult rv = aFolder->GetFilePath(getter_AddRefs(pathFile));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  pathFile->Remove(false);
+  exists = false;
+  pathFile->Exists(&exists);
+  if (exists) {
+    rv = pathFile->Remove(false);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
-  bool isDirectory = false;
-  pathFile->IsDirectory(&isDirectory);
-  if (!isDirectory)
-  {
-    nsAutoString leafName;
-    pathFile->GetLeafName(leafName);
-    leafName.AppendLiteral(FOLDER_SUFFIX);
-    pathFile->SetLeafName(leafName);
+  // Delete any subfolders (.sbd-suffixed directories).
+  AddDirectorySeparator(pathFile);
+  exists = false;
+  pathFile->Exists(&exists);
+  if (exists) {
+    rv = pathFile->Remove(true);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
-  isDirectory = false;
-  pathFile->IsDirectory(&isDirectory);
-  //If this is a directory, then remove it.
-  return isDirectory ? pathFile->Remove(true) : NS_OK;
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsMsgBrkMBoxStore::RenameFolder(nsIMsgFolder *aFolder,
                                               const nsAString & aNewName,
                                               nsIMsgFolder **aNewFolder)
 {
   NS_ENSURE_ARG_POINTER(aFolder);
   NS_ENSURE_ARG_POINTER(aNewFolder);
--- a/mailnews/local/src/nsMsgMaildirStore.cpp
+++ b/mailnews/local/src/nsMsgMaildirStore.cpp
@@ -316,29 +316,40 @@ NS_IMETHODIMP nsMsgMaildirStore::SetSumm
   aDB->GetDBFolderInfo(getter_AddRefs(dbFolderInfo));
   NS_ENSURE_STATE(dbFolderInfo);
   return dbFolderInfo->SetBooleanProperty("maildirValid", aValid);
 }
 
 NS_IMETHODIMP nsMsgMaildirStore::DeleteFolder(nsIMsgFolder *aFolder)
 {
   NS_ENSURE_ARG_POINTER(aFolder);
+  bool exists;
 
-  // Delete Maildir structure
+  // Delete the Maildir itself.
   nsCOMPtr<nsIFile> pathFile;
   nsresult rv = aFolder->GetFilePath(getter_AddRefs(pathFile));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = pathFile->Remove(true); // recursive
-  AddDirectorySeparator(pathFile);
-  bool exists;
+  exists = false;
   pathFile->Exists(&exists);
-  if (exists)
-    pathFile->Remove(true);
-  return rv;
+  if (exists) {
+    rv = pathFile->Remove(true);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Delete any subfolders (.sbd-suffixed directories).
+  AddDirectorySeparator(pathFile);
+  exists = false;
+  pathFile->Exists(&exists);
+  if (exists) {
+    rv = pathFile->Remove(true);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsMsgMaildirStore::RenameFolder(nsIMsgFolder *aFolder,
                                               const nsAString & aNewName,
                                               nsIMsgFolder **aNewFolder)
 {
   NS_ENSURE_ARG_POINTER(aFolder);
   NS_ENSURE_ARG_POINTER(aNewFolder);
--- a/mailnews/news/src/nsNewsFolder.cpp
+++ b/mailnews/news/src/nsNewsFolder.cpp
@@ -481,51 +481,18 @@ NS_IMETHODIMP nsMsgNewsFolder::CreateSub
     if (notifier)
       notifier->NotifyFolderAdded(child);
   }
   return rv;
 }
 
 NS_IMETHODIMP nsMsgNewsFolder::Delete()
 {
-  nsresult rv = GetDatabase();
-
-  if(NS_SUCCEEDED(rv))
-  {
-    mDatabase->ForceClosed();
-    mDatabase = nullptr;
-  }
-
-  nsCOMPtr<nsIFile> folderPath;
-  rv = GetFilePath(getter_AddRefs(folderPath));
-
-  if (NS_SUCCEEDED(rv))
-  {
-    nsCOMPtr<nsIFile> summaryPath;
-    rv = GetSummaryFileLocation(folderPath, getter_AddRefs(summaryPath));
-    if (NS_SUCCEEDED(rv))
-    {
-      bool exists = false;
-      rv = folderPath->Exists(&exists);
-
-      if (NS_SUCCEEDED(rv) && exists)
-        rv = folderPath->Remove(false);
-
-      if (NS_FAILED(rv))
-        NS_WARNING("Failed to remove News Folder");
-
-      rv = summaryPath->Exists(&exists);
-
-      if (NS_SUCCEEDED(rv) && exists)
-        rv = summaryPath->Remove(false);
-
-      if (NS_FAILED(rv))
-        NS_WARNING("Failed to remove News Folder Summary File");
-    }
-  }
+  nsresult rv = nsMsgDBFolder::Delete();
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr <nsINntpIncomingServer> nntpServer;
   rv = GetNntpServer(getter_AddRefs(nntpServer));
   if (NS_FAILED(rv)) return rv;
 
   nsAutoString name;
   rv = GetUnicodeName(name);
   NS_ENSURE_SUCCESS(rv,rv);