Bug 1594877 - Remove xpidl [array] use in nsIMessenger. r=jorgk
authorBen Campbell <benc@thunderbird.net>
Wed, 20 Nov 2019 00:05:08 +0100
changeset 37569 11e9e7a7d60dc8d1d90db490851bc5f012150623
parent 37568 e0b1df31a3f83d0665a2670a2b4b713b13e27eab
child 37570 afee24ca2f118226ecb57602882f9fa5469ba7b1
push id396
push userclokep@gmail.com
push dateMon, 06 Jan 2020 23:11:57 +0000
reviewersjorgk
bugs1594877
Bug 1594877 - Remove xpidl [array] use in nsIMessenger. r=jorgk
mail/base/content/mailCommands.js
mail/base/content/msgHdrView.js
mailnews/base/public/nsIMessenger.idl
mailnews/base/src/nsMessenger.cpp
mailnews/base/src/nsMessenger.h
mailnews/base/test/unit/test_detachToFile.js
mailnews/base/test/unit/test_mimemaltdetach.js
mailnews/imap/test/unit/test_imapAttachmentSaves.js
suite/mailnews/content/mailCommands.js
suite/mailnews/content/msgHdrViewOverlay.js
--- a/mail/base/content/mailCommands.js
+++ b/mail/base/content/mailCommands.js
@@ -376,17 +376,17 @@ function SaveAsFile(uris) {
       let number = 2;
       while (filenames.includes(name)) {
         // should be unlikely
         name = GenerateValidFilename(nameBase + "-" + number, ".eml");
         number++;
       }
       filenames.push(name);
     }
-    messenger.saveMessages(uris.length, filenames, uris);
+    messenger.saveMessages(filenames, uris);
   }
 }
 
 function GenerateFilenameFromMsgHdr(msgHdr) {
   function MakeIS8601ODateString(date) {
     function pad(n) {
       return n < 10 ? "0" + n : n;
     }
--- a/mail/base/content/msgHdrView.js
+++ b/mail/base/content/msgHdrView.js
@@ -3214,43 +3214,40 @@ function HandleMultipleAttachments(attac
     attachmentMessageUriArray[actionIndex] = attachment.uri;
     ++actionIndex;
   }
 
   // The list has been built. Now call our action code...
   switch (action) {
     case "save":
       messenger.saveAllAttachments(
-        attachmentContentTypeArray.length,
         attachmentContentTypeArray,
         attachmentUrlArray,
         attachmentDisplayNameArray,
         attachmentMessageUriArray
       );
       return;
     case "detach":
       // "detach" on a multiple selection of attachments is so far not really
       // supported. As a workaround, resort to normal detach-"all". See also
       // the comment on 'detaching a multiple selection of attachments' below.
       if (attachments.length == 1) {
         attachments[0].detach(true);
       } else {
         messenger.detachAllAttachments(
-          attachmentContentTypeArray.length,
           attachmentContentTypeArray,
           attachmentUrlArray,
           attachmentDisplayNameArray,
           attachmentMessageUriArray,
           true // save
         );
       }
       return;
     case "delete":
       messenger.detachAllAttachments(
-        attachmentContentTypeArray.length,
         attachmentContentTypeArray,
         attachmentUrlArray,
         attachmentDisplayNameArray,
         attachmentMessageUriArray,
         false // don't save
       );
       return;
     case "open":
--- a/mailnews/base/public/nsIMessenger.idl
+++ b/mailnews/base/public/nsIMessenger.idl
@@ -67,25 +67,25 @@ interface nsIMessenger : nsISupports {
 
     /**
      * Save the given messages as files in a folder - the user will be prompted
      * for which folder to use.
      * @param count message count
      * @param filenameArray the filenames to use
      * @param messageUriArray uris of the messages to save
      */
-    void saveMessages(in unsigned long count,
-                      [array, size_is(count)] in wstring filenameArray,
-                      [array, size_is(count)] in string messageUriArray);
+    void saveMessages(in Array<AString> filenameArray,
+                      in Array<ACString> messageUriArray);
 
     void openAttachment(in ACString contentTpe, in ACString url, in ACString displayName, in ACString messageUri, in boolean isExternalAttachment);
     void saveAttachment(in ACString contentTpe, in ACString url, in ACString displayName, in ACString messageUri, in boolean isExternalAttachment);
-    void saveAllAttachments(in unsigned long count, [array, size_is(count)] in string contentTypeArray,
-                            [array, size_is(count)] in string urlArray, [array, size_is(count)] in string displayNameArray,
-                            [array, size_is(count)] in string messageUriArray);
+    void saveAllAttachments(in Array<ACString> contentTypeArray,
+                            in Array<ACString> urlArray,
+                            in Array<ACString> displayNameArray,
+                            in Array<ACString> messageUriArray);
 
     void saveAttachmentToFile(in nsIFile aFile, in ACString aUrl, in ACString aMessageUri,
                               in ACString aContentType, in nsIUrlListener aListener);
 
     /**
      * For a single message and attachments, save these attachments to a file, and
      *  remove from the message. No warning windows will appear, so this is
      *  suitable for use in test and filtering.
@@ -95,27 +95,29 @@ interface nsIMessenger : nsISupports {
      * @param aContentTypeArray Content types of the attachments
      * @param aUrlArray         Urls for the attachments
      * @param aDisplayNameArray Files names to save attachments to. Unique
      *                           names will be created if needed.
      * @param aMessageUriArray  Uri for the source message
      * @param aListener         Listener to inform of start and stop of detach
      */
     void detachAttachmentsWOPrompts(in nsIFile aDestFolder,
-                                    in unsigned long aCount,
-                                    [array, size_is(aCount)] in string aContentTypeArray,
-                                    [array, size_is(aCount)] in string aUrlArray,
-                                    [array, size_is(aCount)] in string aDisplayNameArray,
-                                    [array, size_is(aCount)] in string aMessageUriArray,
+                                    in Array<ACString> aContentTypeArray,
+                                    in Array<ACString> aUrlArray,
+                                    in Array<ACString> aDisplayNameArray,
+                                    in Array<ACString> aMessageUriArray,
                                     in nsIUrlListener aListener);
 
-    void detachAttachment(in string contentTpe, in string url, in string displayName, in string messageUri, in boolean saveFirst, [optional] in boolean withoutWarning);
-    void detachAllAttachments(in unsigned long count, [array, size_is(count)] in string contentTypeArray,
-                             [array, size_is(count)] in string urlArray, [array, size_is(count)] in string displayNameArray,
-                             [array, size_is(count)] in string messageUriArray, in boolean saveFirst, [optional] in boolean withoutWarning);
+    void detachAttachment(in ACString contentTpe, in ACString url, in ACString displayName, in ACString messageUri, in boolean saveFirst, [optional] in boolean withoutWarning);
+    void detachAllAttachments(in Array<ACString> contentTypeArray,
+                              in Array<ACString> urlArray,
+                              in Array<ACString> displayNameArray,
+                              in Array<ACString> messageUriArray,
+                              in boolean saveFirst,
+                              [optional] in boolean withoutWarning);
     // saveAttachmentToFolder is used by the drag and drop code to drop an attachment to a destination folder
     // We need to return the actual file path (including the filename).
     nsIFile saveAttachmentToFolder(in ACString contentType, in ACString url, in ACString displayName, in ACString messageUri, in nsIFile aDestFolder);
 
     readonly attribute ACString lastDisplayedMessageUri;
 
     nsIMsgMessageService messageServiceFromURI(in ACString aUri);
     nsIMsgDBHdr msgHdrFromURI(in ACString aUri);
--- a/mailnews/base/src/nsMessenger.cpp
+++ b/mailnews/base/src/nsMessenger.cpp
@@ -96,24 +96,24 @@
 // Convert an nsString buffer to plain text...
 //
 #include "nsMsgUtils.h"
 #include "nsCharsetSource.h"
 #include "nsIChannel.h"
 #include "nsIOutputStream.h"
 #include "nsIPrincipal.h"
 
-static void ConvertAndSanitizeFileName(const char *displayName,
+static void ConvertAndSanitizeFileName(const nsACString &displayName,
                                        nsString &aResult) {
   nsCString unescapedName;
 
   /* we need to convert the UTF-8 fileName to platform specific character set.
      The display name is in UTF-8 because it has been escaped from JS
   */
-  MsgUnescapeString(nsDependentCString(displayName), 0, unescapedName);
+  MsgUnescapeString(displayName, 0, unescapedName);
   CopyUTF8toUTF16(unescapedName, aResult);
 
   // replace platform specific path separator and illegale characters to avoid
   // any confusion
   MsgReplaceChar(aResult, FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
 }
 
 // ***************************************************
@@ -170,31 +170,31 @@ class nsSaveMsgListener : public nsIUrlL
  private:
   virtual ~nsSaveMsgListener();
 };
 
 class nsSaveAllAttachmentsState {
   using PathChar = mozilla::filesystem::Path::value_type;
 
  public:
-  nsSaveAllAttachmentsState(uint32_t count, const char **contentTypeArray,
-                            const char **urlArray,
-                            const char **displayNameArray,
-                            const char **messageUriArray,
+  nsSaveAllAttachmentsState(const nsTArray<nsCString> &contentTypeArray,
+                            const nsTArray<nsCString> &urlArray,
+                            const nsTArray<nsCString> &displayNameArray,
+                            const nsTArray<nsCString> &messageUriArray,
                             const PathChar *directoryName,
                             bool detachingAttachments);
   virtual ~nsSaveAllAttachmentsState();
 
   uint32_t m_count;
   uint32_t m_curIndex;
   PathChar *m_directoryName;
-  char **m_contentTypeArray;
-  char **m_urlArray;
-  char **m_displayNameArray;
-  char **m_messageUriArray;
+  nsTArray<nsCString> m_contentTypeArray;
+  nsTArray<nsCString> m_urlArray;
+  nsTArray<nsCString> m_displayNameArray;
+  nsTArray<nsCString> m_messageUriArray;
   bool m_detachingAttachments;
 
   // if detaching, do without warning? Will create unique files instead of
   // prompting if duplicate files exist.
   bool m_withoutWarning;
   // if detaching first, remember where we saved to.
   nsTArray<nsCString> m_savedFiles;
 };
@@ -560,53 +560,49 @@ NS_IMETHODIMP nsMessenger::SaveAttachmen
                                                 const nsACString &aMessageUri,
                                                 const nsACString &aContentType,
                                                 nsIUrlListener *aListener) {
   return SaveAttachment(aFile, aURL, aMessageUri, aContentType, nullptr,
                         aListener);
 }
 
 NS_IMETHODIMP
-nsMessenger::DetachAttachmentsWOPrompts(nsIFile *aDestFolder, uint32_t aCount,
-                                        const char **aContentTypeArray,
-                                        const char **aUrlArray,
-                                        const char **aDisplayNameArray,
-                                        const char **aMessageUriArray,
-                                        nsIUrlListener *aListener) {
+nsMessenger::DetachAttachmentsWOPrompts(
+    nsIFile *aDestFolder, const nsTArray<nsCString> &aContentTypeArray,
+    const nsTArray<nsCString> &aUrlArray,
+    const nsTArray<nsCString> &aDisplayNameArray,
+    const nsTArray<nsCString> &aMessageUriArray, nsIUrlListener *aListener) {
   NS_ENSURE_ARG_POINTER(aDestFolder);
-  NS_ENSURE_ARG_POINTER(aContentTypeArray);
-  NS_ENSURE_ARG_POINTER(aUrlArray);
-  NS_ENSURE_ARG_POINTER(aMessageUriArray);
-  NS_ENSURE_ARG_POINTER(aDisplayNameArray);
-  if (!aCount) return NS_OK;
+  MOZ_ASSERT(aContentTypeArray.Length() == aUrlArray.Length() ==
+             aDisplayNameArray.Length() == aMessageUriArray.Length());
+
+  if (!aContentTypeArray.Length()) return NS_OK;
   nsSaveAllAttachmentsState *saveState;
   nsCOMPtr<nsIFile> attachmentDestination;
   nsresult rv = aDestFolder->Clone(getter_AddRefs(attachmentDestination));
   NS_ENSURE_SUCCESS(rv, rv);
 
   PathString path = attachmentDestination->NativePath();
 
   nsAutoString unescapedFileName;
   ConvertAndSanitizeFileName(aDisplayNameArray[0], unescapedFileName);
   rv = attachmentDestination->Append(unescapedFileName);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = attachmentDestination->CreateUnique(nsIFile::NORMAL_FILE_TYPE,
                                            ATTACHMENT_PERMISSION);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  saveState = new nsSaveAllAttachmentsState(aCount, aContentTypeArray,
-                                            aUrlArray, aDisplayNameArray,
-                                            aMessageUriArray, path.get(), true);
+  saveState = new nsSaveAllAttachmentsState(aContentTypeArray, aUrlArray,
+                                            aDisplayNameArray, aMessageUriArray,
+                                            path.get(), true);
 
   // This method is used in filters, where we don't want to warn
   saveState->m_withoutWarning = true;
-  rv = SaveAttachment(attachmentDestination, nsDependentCString(aUrlArray[0]),
-                      nsDependentCString(aMessageUriArray[0]),
-                      nsDependentCString(aContentTypeArray[0]),
-                      (void *)saveState, aListener);
+  rv = SaveAttachment(attachmentDestination, aUrlArray[0], aMessageUriArray[0],
+                      aContentTypeArray[0], (void *)saveState, aListener);
   return rv;
 }
 
 nsresult nsMessenger::SaveAttachment(nsIFile *aFile, const nsACString &aURL,
                                      const nsACString &aMessageUri,
                                      const nsACString &aContentType,
                                      void *closure, nsIUrlListener *aListener) {
   nsCOMPtr<nsIMsgMessageService> messageService;
@@ -717,18 +713,17 @@ nsMessenger::SaveAttachmentToFolder(cons
   NS_ENSURE_ARG_POINTER(aDestFolder);
   nsresult rv;
 
   nsCOMPtr<nsIFile> attachmentDestination;
   rv = aDestFolder->Clone(getter_AddRefs(attachmentDestination));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsString unescapedFileName;
-  ConvertAndSanitizeFileName(PromiseFlatCString(displayName).get(),
-                             unescapedFileName);
+  ConvertAndSanitizeFileName(displayName, unescapedFileName);
   rv = attachmentDestination->Append(unescapedFileName);
   NS_ENSURE_SUCCESS(rv, rv);
 #ifdef XP_MACOSX
   rv = attachmentDestination->CreateUnique(nsIFile::NORMAL_FILE_TYPE,
                                            ATTACHMENT_PERMISSION);
   NS_ENSURE_SUCCESS(rv, rv);
 #endif
 
@@ -742,26 +737,24 @@ NS_IMETHODIMP
 nsMessenger::SaveAttachment(const nsACString &aContentType,
                             const nsACString &aURL,
                             const nsACString &aDisplayName,
                             const nsACString &aMessageUri,
                             bool aIsExternalAttachment) {
   // open external attachments inside our message pane which in turn should
   // trigger the helper app dialog...
   if (aIsExternalAttachment) return OpenURL(aURL);
-  return SaveOneAttachment(PromiseFlatCString(aContentType).get(),
-                           PromiseFlatCString(aURL).get(),
-                           PromiseFlatCString(aDisplayName).get(),
-                           PromiseFlatCString(aMessageUri).get(), false);
+  return SaveOneAttachment(aContentType, aURL, aDisplayName, aMessageUri,
+                           false);
 }
 
-nsresult nsMessenger::SaveOneAttachment(const char *aContentType,
-                                        const char *aURL,
-                                        const char *aDisplayName,
-                                        const char *aMessageUri,
+nsresult nsMessenger::SaveOneAttachment(const nsACString &aContentType,
+                                        const nsACString &aURL,
+                                        const nsACString &aDisplayName,
+                                        const nsACString &aMessageUri,
                                         bool detaching) {
   nsresult rv = NS_ERROR_OUT_OF_MEMORY;
   nsCOMPtr<nsIFilePicker> filePicker =
       do_CreateInstance("@mozilla.org/filepicker;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int16_t dialogResult;
   nsCOMPtr<nsIFile> localFile;
@@ -813,41 +806,44 @@ nsresult nsMessenger::SaveOneAttachment(
 
   rv = filePicker->GetFile(getter_AddRefs(localFile));
   NS_ENSURE_SUCCESS(rv, rv);
 
   SetLastSaveDirectory(localFile);
 
   PathString dirName = localFile->NativePath();
 
-  nsSaveAllAttachmentsState *saveState =
-      new nsSaveAllAttachmentsState(1, &aContentType, &aURL, &aDisplayName,
-                                    &aMessageUri, dirName.get(), detaching);
-
-  return SaveAttachment(
-      localFile, nsDependentCString(aURL), nsDependentCString(aMessageUri),
-      nsDependentCString(aContentType), (void *)saveState, nullptr);
+  AutoTArray<nsCString, 1> contentTypeArray = {
+      PromiseFlatCString(aContentType)};
+  AutoTArray<nsCString, 1> urlArray = {PromiseFlatCString(aURL)};
+  AutoTArray<nsCString, 1> displayNameArray = {
+      PromiseFlatCString(aDisplayName)};
+  AutoTArray<nsCString, 1> messageUriArray = {PromiseFlatCString(aMessageUri)};
+  nsSaveAllAttachmentsState *saveState = new nsSaveAllAttachmentsState(
+      contentTypeArray, urlArray, displayNameArray, messageUriArray,
+      dirName.get(), detaching);
+
+  return SaveAttachment(localFile, aURL, aMessageUri, aContentType,
+                        (void *)saveState, nullptr);
 }
 
 NS_IMETHODIMP
-nsMessenger::SaveAllAttachments(uint32_t count, const char **contentTypeArray,
-                                const char **urlArray,
-                                const char **displayNameArray,
-                                const char **messageUriArray) {
-  if (!count) return NS_ERROR_INVALID_ARG;
-  return SaveAllAttachments(count, contentTypeArray, urlArray, displayNameArray,
+nsMessenger::SaveAllAttachments(const nsTArray<nsCString> &contentTypeArray,
+                                const nsTArray<nsCString> &urlArray,
+                                const nsTArray<nsCString> &displayNameArray,
+                                const nsTArray<nsCString> &messageUriArray) {
+  return SaveAllAttachments(contentTypeArray, urlArray, displayNameArray,
                             messageUriArray, false);
 }
 
-nsresult nsMessenger::SaveAllAttachments(uint32_t count,
-                                         const char **contentTypeArray,
-                                         const char **urlArray,
-                                         const char **displayNameArray,
-                                         const char **messageUriArray,
-                                         bool detaching) {
+nsresult nsMessenger::SaveAllAttachments(
+    const nsTArray<nsCString> &contentTypeArray,
+    const nsTArray<nsCString> &urlArray,
+    const nsTArray<nsCString> &displayNameArray,
+    const nsTArray<nsCString> &messageUriArray, bool detaching) {
   nsresult rv = NS_ERROR_OUT_OF_MEMORY;
   nsCOMPtr<nsIFilePicker> filePicker =
       do_CreateInstance("@mozilla.org/filepicker;1", &rv);
   nsCOMPtr<nsIFile> localFile;
   nsCOMPtr<nsIFile> lastSaveDir;
   int16_t dialogResult;
   nsString saveAttachmentStr;
 
@@ -870,31 +866,29 @@ nsresult nsMessenger::SaveAllAttachments
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = SetLastSaveDirectory(localFile);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsSaveAllAttachmentsState *saveState = nullptr;
   PathString dirName = localFile->NativePath();
 
-  saveState = new nsSaveAllAttachmentsState(count, contentTypeArray, urlArray,
+  saveState = new nsSaveAllAttachmentsState(contentTypeArray, urlArray,
                                             displayNameArray, messageUriArray,
                                             dirName.get(), detaching);
   nsString unescapedName;
   ConvertAndSanitizeFileName(displayNameArray[0], unescapedName);
   rv = localFile->Append(unescapedName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = PromptIfFileExists(localFile);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = SaveAttachment(localFile, nsDependentCString(urlArray[0]),
-                      nsDependentCString(messageUriArray[0]),
-                      nsDependentCString(contentTypeArray[0]),
-                      (void *)saveState, nullptr);
+  rv = SaveAttachment(localFile, urlArray[0], messageUriArray[0],
+                      contentTypeArray[0], (void *)saveState, nullptr);
   return rv;
 }
 
 enum MESSENGER_SAVEAS_FILE_TYPE {
   EML_FILE_TYPE = 0,
   HTML_FILE_TYPE = 1,
   TEXT_FILE_TYPE = 2,
   ANY_FILE_TYPE = 3
@@ -1239,53 +1233,48 @@ nsresult nsMessenger::GetSaveToDir(nsIFi
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aSaveDir = nullptr;
   dir.forget(aSaveDir);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsMessenger::SaveMessages(uint32_t aCount, const char16_t **aFilenameArray,
-                          const char **aMessageUriArray) {
-  NS_ENSURE_ARG_MIN(aCount, 1);
-  NS_ENSURE_ARG_POINTER(aFilenameArray);
-  NS_ENSURE_ARG_POINTER(aMessageUriArray);
+nsMessenger::SaveMessages(const nsTArray<nsString> &aFilenameArray,
+                          const nsTArray<nsCString> &aMessageUriArray) {
+  MOZ_ASSERT(aFilenameArray.Length() == aMessageUriArray.Length());
 
   nsresult rv;
 
   nsCOMPtr<nsIFile> saveDir;
   rv = GetSaveToDir(getter_AddRefs(saveDir));
   NS_ENSURE_SUCCESS(rv, rv);
   if (!saveDir)  // A null saveDir means that the user canceled the save.
     return NS_OK;
 
-  for (uint32_t i = 0; i < aCount; i++) {
-    if (!aFilenameArray[i])  // just to be sure
-      return NS_ERROR_FAILURE;
-
+  for (uint32_t i = 0; i < aFilenameArray.Length(); i++) {
     nsCOMPtr<nsIFile> saveToFile =
         do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = saveToFile->InitWithFile(saveDir);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = saveToFile->Append(nsDependentString(aFilenameArray[i]));
+    rv = saveToFile->Append(aFilenameArray[i]);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = AdjustFileIfNameTooLong(saveToFile);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = PromptIfFileExists(saveToFile);
     if (NS_FAILED(rv)) continue;
 
     nsCOMPtr<nsIMsgMessageService> messageService;
     nsCOMPtr<nsIUrlListener> urlListener;
 
-    rv = GetMessageServiceFromURI(nsDependentCString(aMessageUriArray[i]),
+    rv = GetMessageServiceFromURI(aMessageUriArray[i],
                                   getter_AddRefs(messageService));
     if (NS_FAILED(rv)) {
       Alert("saveMessageFailed");
       return rv;
     }
 
     RefPtr<nsSaveMsgListener> saveListener =
         new nsSaveMsgListener(saveToFile, this, nullptr);
@@ -1295,17 +1284,17 @@ nsMessenger::SaveMessages(uint32_t aCoun
     if (NS_FAILED(rv)) {
       Alert("saveMessageFailed");
       return rv;
     }
 
     // Ok, now save the message.
     nsCOMPtr<nsIURI> dummyNull;
     rv = messageService->SaveMessageToDisk(
-        aMessageUriArray[i], saveToFile, false, urlListener,
+        aMessageUriArray[i].get(), saveToFile, false, urlListener,
         getter_AddRefs(dummyNull), true, mMsgWindow);
     if (NS_FAILED(rv)) {
       Alert("saveMessageFailed");
       return rv;
     }
   }
   return rv;
 }
@@ -1716,35 +1705,31 @@ nsSaveMsgListener::OnStopRequest(nsIRequ
         rv = m_messenger->PromptIfFileExists(localFile);
         if (NS_FAILED(rv)) goto done;
       } else {
         rv = localFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE,
                                      ATTACHMENT_PERMISSION);
         if (NS_FAILED(rv)) goto done;
       }
       rv = m_messenger->SaveAttachment(
-          localFile, nsDependentCString(state->m_urlArray[i]),
-          nsDependentCString(state->m_messageUriArray[i]),
-          nsDependentCString(state->m_contentTypeArray[i]), (void *)state,
-          nullptr);
+          localFile, state->m_urlArray[i], state->m_messageUriArray[i],
+          state->m_contentTypeArray[i], (void *)state, nullptr);
     done:
       if (NS_FAILED(rv)) {
         delete state;
         m_saveAllAttachmentsState = nullptr;
       }
     } else {
       // check if we're saving attachments prior to detaching them.
       if (m_saveAllAttachmentsState->m_detachingAttachments && !mCanceled) {
         nsSaveAllAttachmentsState *state = m_saveAllAttachmentsState;
         m_messenger->DetachAttachments(
-            state->m_count, (const char **)state->m_contentTypeArray,
-            (const char **)state->m_urlArray,
-            (const char **)state->m_displayNameArray,
-            (const char **)state->m_messageUriArray, &state->m_savedFiles,
-            state->m_withoutWarning);
+            state->m_contentTypeArray, state->m_urlArray,
+            state->m_displayNameArray, state->m_messageUriArray,
+            &state->m_savedFiles, state->m_withoutWarning);
       }
 
       delete m_saveAllAttachmentsState;
       m_saveAllAttachmentsState = nullptr;
     }
   }
 
   if (mTransfer) {
@@ -1834,52 +1819,36 @@ void nsMessenger::GetString(const nsStri
   else
     rv = NS_ERROR_FAILURE;
 
   if (NS_FAILED(rv) || aValue.IsEmpty()) aValue = aStringName;
   return;
 }
 
 nsSaveAllAttachmentsState::nsSaveAllAttachmentsState(
-    uint32_t count, const char **contentTypeArray, const char **urlArray,
-    const char **nameArray, const char **uriArray, const PathChar *dirName,
+    const nsTArray<nsCString> &contentTypeArray,
+    const nsTArray<nsCString> &urlArray,
+    const nsTArray<nsCString> &displayNameArray,
+    const nsTArray<nsCString> &messageUriArray, const PathChar *dirName,
     bool detachingAttachments)
-    : m_withoutWarning(false) {
-  uint32_t i;
-  NS_ASSERTION(count && urlArray && nameArray && uriArray && dirName,
-               "fatal - invalid parameters\n");
-
-  m_count = count;
+    : m_contentTypeArray(contentTypeArray),
+      m_urlArray(urlArray),
+      m_displayNameArray(displayNameArray),
+      m_messageUriArray(messageUriArray),
+      m_detachingAttachments(detachingAttachments),
+      m_withoutWarning(false) {
+  MOZ_ASSERT(contentTypeArray.Length() == urlArray.Length() ==
+             displayNameArray.Length() == messageUriArray.Length());
+
+  m_count = contentTypeArray.Length();
   m_curIndex = 0;
-  m_contentTypeArray = new char *[count];
-  m_urlArray = new char *[count];
-  m_displayNameArray = new char *[count];
-  m_messageUriArray = new char *[count];
-  for (i = 0; i < count; i++) {
-    m_contentTypeArray[i] = strdup(contentTypeArray[i]);
-    m_urlArray[i] = strdup(urlArray[i]);
-    m_displayNameArray[i] = strdup(nameArray[i]);
-    m_messageUriArray[i] = strdup(uriArray[i]);
-  }
   m_directoryName = NS_xstrdup(dirName);
-  m_detachingAttachments = detachingAttachments;
 }
 
 nsSaveAllAttachmentsState::~nsSaveAllAttachmentsState() {
-  uint32_t i;
-  for (i = 0; i < m_count; i++) {
-    free(m_contentTypeArray[i]);
-    free(m_urlArray[i]);
-    free(m_displayNameArray[i]);
-    free(m_messageUriArray[i]);
-  }
-  delete[] m_contentTypeArray;
-  delete[] m_urlArray;
-  delete[] m_displayNameArray;
-  delete[] m_messageUriArray;
   free(m_directoryName);
 }
 
 nsresult nsMessenger::GetLastSaveDirectory(nsIFile **aLastSaveDir) {
   nsresult rv;
   nsCOMPtr<nsIPrefBranch> prefBranch =
       do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2125,110 +2094,67 @@ static int CompareAttachmentPartId(const
     ++partIdRight;
   } while (true);
 }
 
 // ------------------------------------
 
 // struct on purpose -> show that we don't ever want a vtable
 struct msgAttachment {
-  msgAttachment()
-      : mContentType(nullptr),
-        mUrl(nullptr),
-        mDisplayName(nullptr),
-        mMessageUri(nullptr) {}
-
-  ~msgAttachment() { Clear(); }
-
-  void Clear() {
-    free(mContentType);
-    free(mUrl);
-    free(mDisplayName);
-    free(mMessageUri);
-  }
-
-  bool Init(const char *aContentType, const char *aUrl,
-            const char *aDisplayName, const char *aMessageUri) {
-    Clear();
-    mContentType = strdup(aContentType);
-    mUrl = strdup(aUrl);
-    mDisplayName = strdup(aDisplayName);
-    mMessageUri = strdup(aMessageUri);
-    return (mContentType && mUrl && mDisplayName && mMessageUri);
-  }
-
-  // take the pointers from aSource
-  void Adopt(msgAttachment &aSource) {
-    Clear();
-
-    mContentType = aSource.mContentType;
-    mUrl = aSource.mUrl;
-    mDisplayName = aSource.mDisplayName;
-    mMessageUri = aSource.mMessageUri;
-
-    aSource.mContentType = nullptr;
-    aSource.mUrl = nullptr;
-    aSource.mDisplayName = nullptr;
-    aSource.mMessageUri = nullptr;
-  }
-
-  char *mContentType;
-  char *mUrl;
-  char *mDisplayName;
-  char *mMessageUri;
-
- private:
-  // disable by not implementing
-  msgAttachment(const msgAttachment &rhs);
-  msgAttachment &operator=(const msgAttachment &rhs);
+  msgAttachment(const nsACString &aContentType, const nsACString &aUrl,
+                const nsACString &aDisplayName, const nsACString &aMessageUri)
+      : mContentType(aContentType),
+        mUrl(aUrl),
+        mDisplayName(aDisplayName),
+        mMessageUri(aMessageUri) {}
+
+  nsCString mContentType;
+  nsCString mUrl;
+  nsCString mDisplayName;
+  nsCString mMessageUri;
 };
 
 // ------------------------------------
 
 class nsAttachmentState {
  public:
   nsAttachmentState();
-  ~nsAttachmentState();
-  nsresult Init(uint32_t aCount, const char **aContentTypeArray,
-                const char **aUrlArray, const char **aDisplayNameArray,
-                const char **aMessageUriArray);
+  nsresult Init(const nsTArray<nsCString> &aContentTypeArray,
+                const nsTArray<nsCString> &aUrlArray,
+                const nsTArray<nsCString> &aDisplayNameArray,
+                const nsTArray<nsCString> &aMessageUriArray);
   nsresult PrepareForAttachmentDelete();
 
  private:
-  static int SortAttachmentsByPartId(const void *aLeft, const void *aRight);
+  static int CompareAttachmentsByPartId(const void *aLeft, const void *aRight);
 
  public:
-  uint32_t mCount;
   uint32_t mCurIndex;
-  msgAttachment *mAttachmentArray;
+  nsTArray<msgAttachment> mAttachmentArray;
 };
 
-nsAttachmentState::nsAttachmentState()
-    : mCount(0), mCurIndex(0), mAttachmentArray(nullptr) {}
-
-nsAttachmentState::~nsAttachmentState() { delete[] mAttachmentArray; }
-
-nsresult nsAttachmentState::Init(uint32_t aCount,
-                                 const char **aContentTypeArray,
-                                 const char **aUrlArray,
-                                 const char **aDisplayNameArray,
-                                 const char **aMessageUriArray) {
-  MOZ_ASSERT(aCount > 0, "count is invalid");
-
-  mCount = aCount;
+nsAttachmentState::nsAttachmentState() : mCurIndex(0) {}
+
+nsresult nsAttachmentState::Init(const nsTArray<nsCString> &aContentTypeArray,
+                                 const nsTArray<nsCString> &aUrlArray,
+                                 const nsTArray<nsCString> &aDisplayNameArray,
+                                 const nsTArray<nsCString> &aMessageUriArray) {
+  MOZ_ASSERT(aContentTypeArray.Length() > 0);
+  MOZ_ASSERT(aContentTypeArray.Length() == aUrlArray.Length() ==
+             aDisplayNameArray.Length() == aMessageUriArray.Length());
+
+  uint32_t count = aContentTypeArray.Length();
   mCurIndex = 0;
-  delete[] mAttachmentArray;
-
-  mAttachmentArray = new msgAttachment[aCount];
-  if (!mAttachmentArray) return NS_ERROR_OUT_OF_MEMORY;
-
-  for (uint32_t u = 0; u < aCount; ++u) {
-    if (!mAttachmentArray[u].Init(aContentTypeArray[u], aUrlArray[u],
-                                  aDisplayNameArray[u], aMessageUriArray[u]))
-      return NS_ERROR_OUT_OF_MEMORY;
+  mAttachmentArray.Clear();
+  mAttachmentArray.SetCapacity(count);
+
+  for (uint32_t u = 0; u < count; ++u) {
+    mAttachmentArray.AppendElement(
+        msgAttachment(aContentTypeArray[u], aUrlArray[u], aDisplayNameArray[u],
+                      aMessageUriArray[u]));
   }
 
   return NS_OK;
 }
 
 nsresult nsAttachmentState::PrepareForAttachmentDelete() {
   // this must be called before any processing
   if (mCurIndex != 0) return NS_ERROR_FAILURE;
@@ -2239,46 +2165,44 @@ nsresult nsAttachmentState::PrepareForAt
   // automatically by the removal of the parent.
   //
   // e.g. the attachment list processing (showing only part ids)
   // before: 1.11, 1.3, 1.2, 1.2.1.3, 1.4.1.2
   // sorted: 1.2, 1.2.1.3, 1.3, 1.4.1.2, 1.11
   // after:  1.2, 1.3, 1.4.1.2, 1.11
 
   // sort
-  qsort(mAttachmentArray, mCount, sizeof(msgAttachment),
-        SortAttachmentsByPartId);
+  qsort(mAttachmentArray.Elements(), mAttachmentArray.Length(),
+        sizeof(msgAttachment), CompareAttachmentsByPartId);
 
   // remove duplicates and sub-items
   int nCompare;
-  for (uint32_t u = 1; u < mCount;) {
-    nCompare = ::CompareAttachmentPartId(mAttachmentArray[u - 1].mUrl,
-                                         mAttachmentArray[u].mUrl);
+  for (uint32_t u = 1; u < mAttachmentArray.Length();) {
+    nCompare = ::CompareAttachmentPartId(mAttachmentArray[u - 1].mUrl.get(),
+                                         mAttachmentArray[u].mUrl.get());
     if (nCompare == 0 ||
         nCompare == -2)  // [u-1] is the same as or a parent of [u]
     {
       // shuffle the array down (and thus keeping the sorted order)
-      // this will get rid of the current unnecessary element
-      for (uint32_t i = u + 1; i < mCount; ++i) {
-        mAttachmentArray[i - 1].Adopt(mAttachmentArray[i]);
-      }
-      --mCount;
+      mAttachmentArray.RemoveElementAt(u);
     } else {
       ++u;
     }
   }
 
   return NS_OK;
 }
 
-int nsAttachmentState::SortAttachmentsByPartId(const void *aLeft,
-                                               const void *aRight) {
+// Static compare callback for sorting.
+int nsAttachmentState::CompareAttachmentsByPartId(const void *aLeft,
+                                                  const void *aRight) {
   msgAttachment &attachLeft = *((msgAttachment *)aLeft);
   msgAttachment &attachRight = *((msgAttachment *)aRight);
-  return ::CompareAttachmentPartId(attachLeft.mUrl, attachRight.mUrl);
+  return ::CompareAttachmentPartId(attachLeft.mUrl.get(),
+                                   attachRight.mUrl.get());
 }
 
 // ------------------------------------
 
 class nsDelAttachListener : public nsIStreamListener,
                             public nsIUrlListener,
                             public nsIMsgCopyServiceListener {
  public:
@@ -2427,34 +2351,35 @@ nsresult nsDelAttachListener::DeleteOrig
                                         false,                // isMove
                                         listenerCopyService,  // listener
                                         false);               // allowUndo
 }
 
 void nsDelAttachListener::SelectNewMessage() {
   nsCString displayUri;
   // all attachments refer to the same message
-  const char *messageUri = mAttach->mAttachmentArray[0].mMessageUri;
+  const nsCString &messageUri(mAttach->mAttachmentArray[0].mMessageUri);
   mMessenger->GetLastDisplayedMessageUri(displayUri);
   if (displayUri.Equals(messageUri)) {
     mMessageFolder->GenerateMessageURI(mNewMessageKey, displayUri);
     if (!displayUri.IsEmpty() && mMsgWindow) {
       nsCOMPtr<nsIMsgWindowCommands> windowCommands;
       mMsgWindow->GetWindowCommands(getter_AddRefs(windowCommands));
       if (windowCommands) windowCommands->SelectMessage(displayUri);
     }
   }
   mNewMessageKey = nsMsgKey_None;
 }
 
 NS_IMETHODIMP
 nsDelAttachListener::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode) {
   nsresult rv = NS_OK;
-  const char *messageUri = mAttach->mAttachmentArray[0].mMessageUri;
-  if (mOriginalMessage && !strncmp(messageUri, "imap-message:", 13)) {
+  const nsCString &messageUri(mAttach->mAttachmentArray[0].mMessageUri);
+  if (mOriginalMessage &&
+      Substring(messageUri, 0, 13).EqualsLiteral("imap-message:")) {
     if (m_state == eUpdatingFolder) rv = DeleteOriginalMessage();
   }
   // check if we've deleted the original message, and we know the new msg id.
   else if (m_state == eDeletingOldMessage && mMsgWindow)
     SelectNewMessage();
 
   return rv;
 }
@@ -2503,18 +2428,19 @@ nsDelAttachListener::OnStopCopy(nsresult
   // do this for non-imap messages - for imap, we'll do the delete in
   // OnStopRunningUrl. For local messages, we won't get an OnStopRunningUrl
   // notification. And for imap, it's too late to delete the message here,
   // because we'll be updating the folder naturally as a result of
   // running an append url. If we delete the header here, that folder
   // update will think we need to download the header...If we do it
   // in OnStopRunningUrl, we'll issue the delete before we do the
   // update....all nasty stuff.
-  const char *messageUri = mAttach->mAttachmentArray[0].mMessageUri;
-  if (mOriginalMessage && strncmp(messageUri, "imap-message:", 13))
+  const nsACString &messageUri = mAttach->mAttachmentArray[0].mMessageUri;
+  if (mOriginalMessage &&
+      !Substring(messageUri, 0, 13).EqualsLiteral("imap-message:"))
     return DeleteOriginalMessage();
   else
     m_state = eUpdatingFolder;
   return NS_OK;
 }
 
 //
 // local methods
@@ -2549,23 +2475,22 @@ nsresult nsDelAttachListener::StartProce
                              getter_AddRefs(mMessenger));
   mMsgWindow = aMsgWindow;
   mAttach = aAttach;
   mDetaching = detaching;
 
   nsresult rv;
 
   // all attachments refer to the same message
-  const char *messageUri = mAttach->mAttachmentArray[0].mMessageUri;
+  const nsCString &messageUri = mAttach->mAttachmentArray[0].mMessageUri;
 
   // get the message service, original message and folder for this message
-  rv = GetMessageServiceFromURI(nsDependentCString(messageUri),
-                                getter_AddRefs(mMessageService));
+  rv = GetMessageServiceFromURI(messageUri, getter_AddRefs(mMessageService));
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = mMessageService->MessageURIToMsgHdr(messageUri,
+  rv = mMessageService->MessageURIToMsgHdr(messageUri.get(),
                                            getter_AddRefs(mOriginalMessage));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mOriginalMessage->GetFolder(getter_AddRefs(mMessageFolder));
   NS_ENSURE_SUCCESS(rv, rv);
   mOriginalMessage->GetFlags(&mOrigMsgFlags);
 
   // ensure that we can store and delete messages in this folder, if we
   // can't then we can't do attachment deleting
@@ -2592,22 +2517,22 @@ nsresult nsDelAttachListener::StartProce
 
   // create the additional header for data conversion. This will tell the stream
   // converter which MIME emitter we want to use, and it will tell the MIME
   // emitter which attachments should be deleted.
   const char *partId;
   const char *nextField;
   nsAutoCString sHeader("attach&del=");
   nsAutoCString detachToHeader("&detachTo=");
-  for (uint32_t u = 0; u < mAttach->mCount; ++u) {
+  for (uint32_t u = 0; u < mAttach->mAttachmentArray.Length(); ++u) {
     if (u > 0) {
       sHeader.Append(',');
       if (detaching) detachToHeader.Append(',');
     }
-    partId = GetAttachmentPartId(mAttach->mAttachmentArray[u].mUrl);
+    partId = GetAttachmentPartId(mAttach->mAttachmentArray[u].mUrl.get());
     nextField = PL_strchr(partId, '&');
     sHeader.Append(partId, nextField ? nextField - partId : -1);
     if (detaching) detachToHeader.Append(mDetachedFileUris[u]);
   }
 
   if (detaching) sHeader.Append(detachToHeader);
   // stream this message to our listener converting it via the attachment mime
   // converter. The listener will just write the converted message straight to
@@ -2616,86 +2541,89 @@ nsresult nsDelAttachListener::StartProce
   rv = this->QueryInterface(NS_GET_IID(nsISupports),
                             getter_AddRefs(listenerSupports));
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIUrlListener> listenerUrlListener =
       do_QueryInterface(listenerSupports, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> dummyNull;
-  rv = mMessageService->StreamMessage(messageUri, listenerSupports, mMsgWindow,
-                                      listenerUrlListener, true, sHeader, false,
-                                      getter_AddRefs(dummyNull));
+  rv = mMessageService->StreamMessage(
+      messageUri.get(), listenerSupports, mMsgWindow, listenerUrlListener, true,
+      sHeader, false, getter_AddRefs(dummyNull));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 // ------------------------------------
 
 NS_IMETHODIMP
-nsMessenger::DetachAttachment(const char *aContentType, const char *aUrl,
-                              const char *aDisplayName, const char *aMessageUri,
-                              bool aSaveFirst, bool withoutWarning = false) {
-  NS_ENSURE_ARG_POINTER(aContentType);
-  NS_ENSURE_ARG_POINTER(aUrl);
-  NS_ENSURE_ARG_POINTER(aDisplayName);
-  NS_ENSURE_ARG_POINTER(aMessageUri);
-
+nsMessenger::DetachAttachment(const nsACString &aContentType,
+                              const nsACString &aURL,
+                              const nsACString &aDisplayName,
+                              const nsACString &aMessageUri, bool aSaveFirst,
+                              bool withoutWarning = false) {
   if (aSaveFirst)
-    return SaveOneAttachment(aContentType, aUrl, aDisplayName, aMessageUri,
+    return SaveOneAttachment(aContentType, aURL, aDisplayName, aMessageUri,
                              true);
-  return DetachAttachments(1, &aContentType, &aUrl, &aDisplayName, &aMessageUri,
-                           nullptr, withoutWarning);
+  AutoTArray<nsCString, 1> contentTypeArray = {
+      PromiseFlatCString(aContentType)};
+  AutoTArray<nsCString, 1> urlArray = {PromiseFlatCString(aURL)};
+  AutoTArray<nsCString, 1> displayNameArray = {
+      PromiseFlatCString(aDisplayName)};
+  AutoTArray<nsCString, 1> messageUriArray = {PromiseFlatCString(aMessageUri)};
+  return DetachAttachments(contentTypeArray, urlArray, displayNameArray,
+                           messageUriArray, nullptr, withoutWarning);
 }
 
 NS_IMETHODIMP
-nsMessenger::DetachAllAttachments(
-    uint32_t aCount, const char **aContentTypeArray, const char **aUrlArray,
-    const char **aDisplayNameArray, const char **aMessageUriArray,
-    bool aSaveFirst, bool withoutWarning = false) {
-  NS_ENSURE_ARG_MIN(aCount, 1);
-  NS_ENSURE_ARG_POINTER(aContentTypeArray);
-  NS_ENSURE_ARG_POINTER(aUrlArray);
-  NS_ENSURE_ARG_POINTER(aDisplayNameArray);
-  NS_ENSURE_ARG_POINTER(aMessageUriArray);
+nsMessenger::DetachAllAttachments(const nsTArray<nsCString> &aContentTypeArray,
+                                  const nsTArray<nsCString> &aUrlArray,
+                                  const nsTArray<nsCString> &aDisplayNameArray,
+                                  const nsTArray<nsCString> &aMessageUriArray,
+                                  bool aSaveFirst,
+                                  bool withoutWarning = false) {
+  NS_ENSURE_ARG_MIN(aContentTypeArray.Length(), 1);
+  MOZ_ASSERT(aContentTypeArray.Length() == aUrlArray.Length() ==
+             aDisplayNameArray.Length() == aMessageUriArray.Length());
 
   if (aSaveFirst)
-    return SaveAllAttachments(aCount, aContentTypeArray, aUrlArray,
-                              aDisplayNameArray, aMessageUriArray, true);
+    return SaveAllAttachments(aContentTypeArray, aUrlArray, aDisplayNameArray,
+                              aMessageUriArray, true);
   else
-    return DetachAttachments(aCount, aContentTypeArray, aUrlArray,
-                             aDisplayNameArray, aMessageUriArray, nullptr,
-                             withoutWarning);
+    return DetachAttachments(aContentTypeArray, aUrlArray, aDisplayNameArray,
+                             aMessageUriArray, nullptr, withoutWarning);
 }
 
 nsresult nsMessenger::DetachAttachments(
-    uint32_t aCount, const char **aContentTypeArray, const char **aUrlArray,
-    const char **aDisplayNameArray, const char **aMessageUriArray,
+    const nsTArray<nsCString> &aContentTypeArray,
+    const nsTArray<nsCString> &aUrlArray,
+    const nsTArray<nsCString> &aDisplayNameArray,
+    const nsTArray<nsCString> &aMessageUriArray,
     nsTArray<nsCString> *saveFileUris, bool withoutWarning) {
   // if withoutWarning no dialog for user
-  if (!withoutWarning &&
-      NS_FAILED(PromptIfDeleteAttachments(saveFileUris != nullptr, aCount,
-                                          aDisplayNameArray)))
+  if (!withoutWarning && NS_FAILED(PromptIfDeleteAttachments(
+                             saveFileUris != nullptr, aDisplayNameArray)))
     return NS_OK;
 
   nsresult rv = NS_OK;
 
   // ensure that our arguments are valid
   //  char * partId;
-  for (uint32_t u = 0; u < aCount; ++u) {
+  for (uint32_t u = 0; u < aContentTypeArray.Length(); ++u) {
     // ensure all of the message URI are the same, we cannot process
     // attachments from different messages
-    if (u > 0 && 0 != strcmp(aMessageUriArray[0], aMessageUriArray[u])) {
+    if (u > 0 && aMessageUriArray[0] != aMessageUriArray[u]) {
       rv = NS_ERROR_INVALID_ARG;
       break;
     }
 
     // ensure that we don't have deleted messages in this list
-    if (0 == strcmp(aContentTypeArray[u], MIMETYPE_DELETED)) {
+    if (aContentTypeArray[u].EqualsLiteral(MIMETYPE_DELETED)) {
       rv = NS_ERROR_INVALID_ARG;
       break;
     }
 
     // for the moment we prevent any attachments other than root level
     // attachments being deleted (i.e. you can't delete attachments from a
     // email forwarded as an attachment). We do this by ensuring that the
     // part id only has a single period in it (e.g. "1.2").
@@ -2725,48 +2653,47 @@ nsresult nsMessenger::DetachAttachments(
   nsCOMPtr<nsISupports>
       listenerSupports;  // auto-delete of the listener with error
   listener->QueryInterface(NS_GET_IID(nsISupports),
                            getter_AddRefs(listenerSupports));
 
   if (saveFileUris) listener->mDetachedFileUris = *saveFileUris;
   // create the attachments for use by the listener
   nsAttachmentState *attach = new nsAttachmentState;
-  if (!attach) return NS_ERROR_OUT_OF_MEMORY;
-  rv = attach->Init(aCount, aContentTypeArray, aUrlArray, aDisplayNameArray,
+  rv = attach->Init(aContentTypeArray, aUrlArray, aDisplayNameArray,
                     aMessageUriArray);
   if (NS_SUCCEEDED(rv)) rv = attach->PrepareForAttachmentDelete();
   if (NS_FAILED(rv)) {
     delete attach;
     return rv;
   }
 
   // initialize our listener with the attachments and details. The listener
   // takes ownership of 'attach' immediately irrespective of the return value
   // (error or not).
   return listener->StartProcessing(this, mMsgWindow, attach,
                                    saveFileUris != nullptr);
 }
 
 nsresult nsMessenger::PromptIfDeleteAttachments(
-    bool aSaveFirst, uint32_t aCount, const char **aDisplayNameArray) {
+    bool aSaveFirst, const nsTArray<nsCString> &aDisplayNameArray) {
   nsresult rv = NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIPrompt> dialog(do_GetInterface(mDocShell));
   if (!dialog) return rv;
 
   if (!mStringBundle) {
     rv = InitStringBundle();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // create the list of attachments we are removing
   nsString displayString;
   nsString attachmentList;
-  for (uint32_t u = 0; u < aCount; ++u) {
+  for (uint32_t u = 0; u < aDisplayNameArray.Length(); ++u) {
     ConvertAndSanitizeFileName(aDisplayNameArray[u], displayString);
     attachmentList.Append(displayString);
     attachmentList.Append(char16_t('\n'));
   }
   AutoTArray<nsString, 1> formatStrings = {attachmentList};
 
   // format the message and display
   nsString promptMessage;
--- a/mailnews/base/src/nsMessenger.h
+++ b/mailnews/base/src/nsMessenger.h
@@ -35,37 +35,39 @@ class nsMessenger : public nsIMessenger,
 
   nsresult Alert(const char *stringName);
 
   nsresult SaveAttachment(nsIFile *file, const nsACString &unescapedUrl,
                           const nsACString &messageUri,
                           const nsACString &contentType, void *closure,
                           nsIUrlListener *aListener);
   nsresult PromptIfFileExists(nsIFile *file);
-  nsresult DetachAttachments(uint32_t aCount, const char **aContentTypeArray,
-                             const char **aUrlArray,
-                             const char **aDisplayNameArray,
-                             const char **aMessageUriArray,
+  nsresult DetachAttachments(const nsTArray<nsCString> &aContentTypeArray,
+                             const nsTArray<nsCString> &aUrlArray,
+                             const nsTArray<nsCString> &aDisplayNameArray,
+                             const nsTArray<nsCString> &aMessageUriArray,
                              nsTArray<nsCString> *saveFileUris,
                              bool withoutWarning = false);
-  nsresult SaveAllAttachments(uint32_t count, const char **contentTypeArray,
-                              const char **urlArray,
-                              const char **displayNameArray,
-                              const char **messageUriArray, bool detaching);
-  nsresult SaveOneAttachment(const char *aContentType, const char *aURL,
-                             const char *aDisplayName, const char *aMessageUri,
-                             bool detaching);
+  nsresult SaveAllAttachments(const nsTArray<nsCString> &contentTypeArray,
+                              const nsTArray<nsCString> &urlArray,
+                              const nsTArray<nsCString> &displayNameArray,
+                              const nsTArray<nsCString> &messageUriArray,
+                              bool detaching);
+  nsresult SaveOneAttachment(const nsACString &aContentType,
+                             const nsACString &aURL,
+                             const nsACString &aDisplayName,
+                             const nsACString &aMessageUri, bool detaching);
 
  protected:
   virtual ~nsMessenger();
 
   void GetString(const nsString &aStringName, nsString &stringValue);
   nsresult InitStringBundle();
-  nsresult PromptIfDeleteAttachments(bool saveFirst, uint32_t count,
-                                     const char **displayNameArray);
+  nsresult PromptIfDeleteAttachments(
+      bool saveFirst, const nsTArray<nsCString> &displayNameArray);
 
  private:
   nsresult GetLastSaveDirectory(nsIFile **aLastSaveAsDir);
   // if aLocalFile is a dir, we use it.  otherwise, we use the parent of
   // aLocalFile.
   nsresult SetLastSaveDirectory(nsIFile *aLocalFile);
 
   nsresult AdjustFileIfNameTooLong(nsIFile *aFile);
--- a/mailnews/base/test/unit/test_detachToFile.js
+++ b/mailnews/base/test/unit/test_detachToFile.js
@@ -56,17 +56,16 @@ function* startDetach() {
 
   let messenger = Cc["@mozilla.org/messenger;1"].createInstance(
     Ci.nsIMessenger
   );
   let attachment = gCallbackObject.attachments[0];
 
   messenger.detachAttachmentsWOPrompts(
     do_get_profile(),
-    1,
     [attachment.contentType],
     [attachment.url],
     [attachment.name],
     [msgURI],
     asyncUrlListener
   );
   yield false;
 }
--- a/mailnews/base/test/unit/test_mimemaltdetach.js
+++ b/mailnews/base/test/unit/test_mimemaltdetach.js
@@ -57,17 +57,16 @@ function* startDetach() {
 
   let messenger = Cc["@mozilla.org/messenger;1"].createInstance(
     Ci.nsIMessenger
   );
   let attachment = gCallbackObject.attachments[0];
 
   messenger.detachAttachmentsWOPrompts(
     do_get_profile(),
-    1,
     [attachment.contentType],
     [attachment.url],
     [attachment.name],
     [msgURI],
     asyncUrlListener
   );
   yield false;
 }
--- a/mailnews/imap/test/unit/test_imapAttachmentSaves.js
+++ b/mailnews/imap/test/unit/test_imapAttachmentSaves.js
@@ -76,17 +76,16 @@ function* startDetach() {
 
   let messenger = Cc["@mozilla.org/messenger;1"].createInstance(
     Ci.nsIMessenger
   );
   let attachment = gCallbackObject.attachments[0];
 
   messenger.detachAttachmentsWOPrompts(
     do_get_profile(),
-    1,
     [attachment.contentType],
     [attachment.url],
     [attachment.name],
     [msgURI],
     null
   );
   // deletion of original message should kick async_driver.
   yield false;
--- a/suite/mailnews/content/mailCommands.js
+++ b/suite/mailnews/content/mailCommands.js
@@ -345,17 +345,17 @@ function SaveAsFile(aUris)
                            .messageURIToMsgHdr(aUris[i])
                            .mime2DecodedSubject;
     fileNames[i] = suggestUniqueFileName(subject.substr(0, 120), ".eml",
                                          fileNames);
   }
   if (num == 1)
     messenger.saveAs(aUris[0], true, null, fileNames[0]);
   else
-    messenger.saveMessages(num, fileNames, aUris);
+    messenger.saveMessages(fileNames, aUris);
 }
 
 function saveAsUrlListener(aUri, aIdentity)
 {
   this.uri = aUri;
   this.identity = aIdentity;
 }
 
--- a/suite/mailnews/content/msgHdrViewOverlay.js
+++ b/suite/mailnews/content/msgHdrViewOverlay.js
@@ -1792,33 +1792,30 @@ function HandleMultipleAttachments(comma
      attachmentDisplayNameArray[index] = encodeURI(attachment.displayName);
      attachmentMessageUriArray[index] = attachment.uri;
    }
 
    // okay the list has been built... now call our action code...
    switch (commandPrefix)
    {
      case "saveAttachment":
-       messenger.saveAllAttachments(attachmentContentTypeArray.length,
-                                    attachmentContentTypeArray,
+       messenger.saveAllAttachments(attachmentContentTypeArray,
                                     attachmentUrlArray,
                                     attachmentDisplayNameArray,
                                     attachmentMessageUriArray);
        break;
      case "detachAttachment":
-       messenger.detachAllAttachments(attachmentContentTypeArray.length,
-                                      attachmentContentTypeArray,
+       messenger.detachAllAttachments(attachmentContentTypeArray,
                                       attachmentUrlArray,
                                       attachmentDisplayNameArray,
                                       attachmentMessageUriArray,
                                       true /* save */);
        break;
      case "deleteAttachment":
-       messenger.detachAllAttachments(attachmentContentTypeArray.length,
-                                      attachmentContentTypeArray,
+       messenger.detachAllAttachments(attachmentContentTypeArray,
                                       attachmentUrlArray,
                                       attachmentDisplayNameArray,
                                       attachmentMessageUriArray,
                                       false /* don't save */);
        break;
      default:
        dump (commandPrefix + "** unknown handle all attachments action **\n");
    }