Bug 1585512 - Remove deprecated nsIMsgHeaderParser::parseHeadersWithArray. r=mkmelin
authorBen Campbell <benc@thunderbird.net>
Thu, 03 Oct 2019 23:02:57 +0200
changeset 36195 b22962d53db9ab1577a4f8df9dbf86f282797de4
parent 36194 ce3700fcd3c957309ce5c106f7a7616347285028
child 36196 6f766cbe59fdab4b0ad503386d9978b05c19ecef
push id2511
push userclokep@gmail.com
push dateMon, 21 Oct 2019 20:28:27 +0000
treeherdercomm-beta@67169a456144 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmkmelin
bugs1585512
Bug 1585512 - Remove deprecated nsIMsgHeaderParser::parseHeadersWithArray. r=mkmelin
mail/base/content/mailWindowOverlay.js
mail/components/compose/content/MsgComposeCommands.js
mail/test/mozmill/content-policy/test-general-content-policy.js
mail/test/mozmill/folder-display/test-summarization.js
mail/test/mozmill/message-header/test-message-header.js
mailnews/addrbook/content/abMailListDialog.js
mailnews/db/gloda/modules/utils.js
mailnews/mime/public/nsIMsgHeaderParser.idl
mailnews/mime/src/mimeJSComponents.js
mailnews/mime/test/unit/test_nsIMsgHeaderParser2.js
mailnews/mime/test/unit/test_nsIMsgHeaderParser5.js
mailnews/mime/test/unit/test_parseHeadersWithArray.js
mailnews/mime/test/unit/xpcshell.ini
--- a/mail/base/content/mailWindowOverlay.js
+++ b/mail/base/content/mailWindowOverlay.js
@@ -1628,23 +1628,19 @@ function IsReplyAllEnabled() {
   let imInAddresses =
     myEmail && addresses.toLowerCase().includes(myEmail.toLowerCase());
 
   // Now, let's get the number of unique addresses.
   let uniqueAddresses = MailServices.headerParser.removeDuplicateAddresses(
     addresses,
     ""
   );
-  let emailAddresses = {};
-  let numAddresses = MailServices.headerParser.parseHeadersWithArray(
-    uniqueAddresses,
-    emailAddresses,
-    {},
-    {}
-  );
+  let numAddresses = MailServices.headerParser.parseEncodedHeader(
+    uniqueAddresses
+  ).length;
 
   // I don't want to count my address in the number of addresses to reply
   // to, since I won't be emailing myself.
   if (imInAddresses) {
     numAddresses--;
   }
 
   // ReplyAll is enabled if there is more than 1 person to reply to.
@@ -3459,27 +3455,24 @@ function LoadMsgWithRemoteContent() {
 }
 
 /**
  * Populate the remote content options for the current message.
  */
 function onRemoteContentOptionsShowing(aEvent) {
   let origins = aEvent.target.value ? aEvent.target.value.split(" ") : [];
 
-  let addresses = {};
-  MailServices.headerParser.parseHeadersWithArray(
-    gMessageDisplay.displayedMessage.author,
-    addresses,
-    {},
-    {}
+  let addresses = MailServices.headerParser.parseEncodedHeader(
+    gMessageDisplay.displayedMessage.author
   );
-  let adrCount = addresses.value[0] ? 1 : 0;
+  addresses = addresses.slice(0, 1);
   // If there is an author's email, put it also in the menu.
+  let adrCount = addresses.length;
   if (adrCount > 0) {
-    let authorEmailAddress = addresses.value[0];
+    let authorEmailAddress = addresses[0].email;
     let authorEmailAddressURI = Services.io.newURI(
       "chrome://messenger/content/email=" + authorEmailAddress
     );
     let mailPrincipal = Services.scriptSecurityManager.createContentPrincipal(
       authorEmailAddressURI,
       {}
     );
     origins.push(mailPrincipal.origin);
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -4195,37 +4195,28 @@ function OutputFormatMenuSelect(target) 
     gContentChanged = currentSendFormat != gSendFormat;
   }
 }
 
 // walk through the recipients list and add them to the inline spell checker ignore list
 function addRecipientsToIgnoreList(aAddressesToAdd) {
   if (gSpellChecker.enabled) {
     // break the list of potentially many recipients back into individual names
-    var emailAddresses = {};
-    var names = {};
-    var fullNames = {};
-    MailServices.headerParser.parseHeadersWithArray(
-      aAddressesToAdd,
-      emailAddresses,
-      names,
-      fullNames
+    let addresses = MailServices.headerParser.parseEncodedHeader(
+      aAddressesToAdd
     );
-    if (!names) {
-      return;
-    }
     let tokenizedNames = [];
 
     // Each name could consist of multiple word delimited by either commas or spaces, i.e. Green Lantern
     // or Lantern,Green. Tokenize on comma first, then tokenize again on spaces.
-    for (let name in names.value) {
-      if (!names.value[name]) {
+    for (let addr of addresses) {
+      if (!addr.name) {
         continue;
       }
-      let splitNames = names.value[name].split(",");
+      let splitNames = addr.name.split(",");
       for (let i = 0; i < splitNames.length; i++) {
         // now tokenize off of white space
         let splitNamesFromWhiteSpaceArray = splitNames[i].split(" ");
         for (
           let whiteSpaceIndex = 0;
           whiteSpaceIndex < splitNamesFromWhiteSpaceArray.length;
           whiteSpaceIndex++
         ) {
--- a/mail/test/mozmill/content-policy/test-general-content-policy.js
+++ b/mail/test/mozmill/content-policy/test-general-content-policy.js
@@ -432,24 +432,18 @@ function checkAllowFeedMsg(test) {
  */
 function checkAllowForSenderWithPerms(test) {
   let msgDbHdr = addToFolder(
     test.type + " priv sender test message " + gMsgNo,
     msgBodyStart + test.body + msgBodyEnd,
     folder
   );
 
-  let addresses = {};
-  MailServices.headerParser.parseHeadersWithArray(
-    msgDbHdr.author,
-    addresses,
-    {},
-    {}
-  );
-  let authorEmailAddress = addresses.value[0];
+  let addresses = MailServices.headerParser.parseEncodedHeader(msgDbHdr.author);
+  let authorEmailAddress = addresses[0].email;
 
   let uri = Services.io.newURI(
     "chrome://messenger/content/email=" + authorEmailAddress
   );
   addPermission(uri, Services.perms.ALLOW_ACTION);
   assert_equals(checkPermission(uri), Services.perms.ALLOW_ACTION);
 
   // select the newly created message
--- a/mail/test/mozmill/folder-display/test-summarization.js
+++ b/mail/test/mozmill/folder-display/test-summarization.js
@@ -341,27 +341,20 @@ function test_summary_when_multiple_iden
   add_sets_to_folders([folder1], [thread1]);
   be_in_folder(folderVirtual);
   select_shift_click_row(1);
 
   assert_summary_contains_N_elts(".item_header > .subject", 2);
 }
 
 function extract_first_address(thread) {
-  let addresses = {};
-  let fullNames = {};
-  let names = {};
-  MailServices.headerParser.parseHeadersWithArray(
-    thread1.getMsgHdr(0).mime2DecodedAuthor,
-    addresses,
-    names,
-    fullNames
+  let addresses = MailServices.headerParser.parseEncodedHeader(
+    thread1.getMsgHdr(0).mime2DecodedAuthor
   );
-
-  return { email: addresses.value[0], name: names.value[0] };
+  return addresses[0];
 }
 
 function check_address_name(name) {
   let htmlframe = mc.e("multimessage");
   let match = htmlframe.contentDocument.querySelector(".author");
   if (match.textContent != name) {
     throw new Error(
       "Expected to find sender named '" +
--- a/mail/test/mozmill/message-header/test-message-header.js
+++ b/mail/test/mozmill/message-header/test-message-header.js
@@ -1088,38 +1088,25 @@ function test_toolbar_collapse_and_expan
 /**
  * Test if the tooltip text of the more widget contains the correct addresses
  * not shown in the header and the number of addresses also hidden in the
  * tooltip text.
  * @param aMsg the message for which the subtest should be performed
  */
 function subtest_more_button_tooltip(aMsg) {
   // check for more indicator number of the more widget
-  let addresses = {};
-  let fullNames = {};
-  let names = {};
-  let numAddrsCC = MailServices.headerParser.parseHeadersWithArray(
-    aMsg.ccList,
-    addresses,
-    names,
-    fullNames
-  );
-  let numAddrsTo = MailServices.headerParser.parseHeadersWithArray(
-    aMsg.recipients,
-    addresses,
-    names,
-    fullNames
-  );
+  let ccAddrs = MailServices.headerParser.parseEncodedHeader(aMsg.ccList);
+  let toAddrs = MailServices.headerParser.parseEncodedHeader(aMsg.recipients);
 
   let shownToAddrNum = get_number_of_addresses_in_header("expandedtoBox");
   let shownCCAddrNum = get_number_of_addresses_in_header("expandedccBox");
 
   // first check the number of addresses in the more widget
-  let hiddenCCAddrsNum = numAddrsCC - shownCCAddrNum;
-  let hiddenToAddrsNum = numAddrsTo - shownToAddrNum;
+  let hiddenCCAddrsNum = ccAddrs.length - shownCCAddrNum;
+  let hiddenToAddrsNum = toAddrs.length - shownToAddrNum;
 
   let moreNumberTo = get_number_of_more_button("expandedtoBox");
   assert_not_equals(NaN, moreNumberTo);
   assert_equals(hiddenToAddrsNum, moreNumberTo);
 
   let moreNumberCC = get_number_of_more_button("expandedccBox");
   assert_not_equals(NaN, moreNumberCC);
   assert_equals(hiddenCCAddrsNum, moreNumberCC);
@@ -1187,51 +1174,47 @@ function get_number_of_more_button(aHead
  */
 function subtest_addresses_in_tooltip_text(
   aRecipients,
   aHeaderBox,
   aShownAddrsNum,
   aHiddenAddrsNum
 ) {
   // check for more indicator number of the more widget
-  let addresses = {};
-  let fullNames = {};
-  let names = {};
-  let numAddresses = MailServices.headerParser.parseHeadersWithArray(
-    aRecipients,
-    addresses,
-    names,
-    fullNames
-  );
+  let addresses = MailServices.headerParser.parseEncodedHeader(aRecipients);
 
   let headerBoxElement = mc.e(aHeaderBox);
   let moreIndicator = headerBoxElement.more;
   let tooltipText = moreIndicator.getAttribute("tooltiptext");
   let maxTooltipAddrsNum = headerBoxElement.maxAddressesInMoreTooltipValue;
   let addrsNumInTooltip = 0;
 
   for (
     let i = aShownAddrsNum;
-    i < numAddresses && i < maxTooltipAddrsNum + aShownAddrsNum;
+    i < addresses.length && i < maxTooltipAddrsNum + aShownAddrsNum;
     i++
   ) {
-    assert_true(tooltipText.includes(fullNames.value[i]), fullNames.value[i]);
+    assert_true(
+      tooltipText.includes(addresses[i].toString()),
+      addresses[i].toString()
+    );
     addrsNumInTooltip += 1;
   }
 
   if (aHiddenAddrsNum < maxTooltipAddrsNum) {
     assert_equals(aHiddenAddrsNum, addrsNumInTooltip);
   } else {
     assert_equals(maxTooltipAddrsNum, addrsNumInTooltip);
     // check if ", and X more" shows the correct number
     let moreTooltipSplit = tooltipText.split(", ");
     let words = mc.window.document
       .getElementById("bundle_messenger")
       .getString("headerMoreAddrsTooltip");
-    let remainingAddresses = numAddresses - aShownAddrsNum - maxTooltipAddrsNum;
+    let remainingAddresses =
+      addresses.length - aShownAddrsNum - maxTooltipAddrsNum;
     let moreForm = mc.window.PluralForm.get(remainingAddresses, words).replace(
       "#1",
       remainingAddresses
     );
     assert_equals(
       moreForm,
       ", " + moreTooltipSplit[moreTooltipSplit.length - 1]
     );
--- a/mailnews/addrbook/content/abMailListDialog.js
+++ b/mailnews/addrbook/content/abMailListDialog.js
@@ -503,28 +503,20 @@ function DropListAddress(target, address
   // Set focus on a new available, visible row.
   awClickEmptySpace(target, true);
   if (top.MAX_RECIPIENTS == 0) {
     top.MAX_RECIPIENTS = 1;
   }
 
   // Break apart the MIME-ready header address into individual addressees to
   // add to the dialog.
-  let addresses = {},
-    names = {},
-    fullNames = {};
-  MailServices.headerParser.parseHeadersWithArray(
-    address,
-    addresses,
-    names,
-    fullNames
-  );
-  for (let full of fullNames.value) {
+  let addresses = MailServices.headerParser.parseEncodedHeader(address);
+  for (let addr of addresses) {
     let lastInput = awGetInputElement(top.MAX_RECIPIENTS);
-    lastInput.value = full;
+    lastInput.value = addr.toString();
     awAppendNewRow(true);
   }
 }
 
 /* Allows extensions to register a listener function for
  * when a mailing list is loaded.  The listener function
  * should take two parameters - the first being the
  * mailing list being loaded, the second one being the
--- a/mailnews/db/gloda/modules/utils.js
+++ b/mailnews/db/gloda/modules/utils.js
@@ -44,30 +44,22 @@ var GlodaUtils = {
    * addresses: a list of e-mail addresses (ex: ["bob@example.com"])
    * names: a list of names (ex: ["Bob Smith"])
    * fullAddresses: aka the list of name and e-mail together (ex: ['"Bob Smith"
    *  <bob@example.com>']).
    *
    * This method is a convenience wrapper around nsIMsgHeaderParser.
    */
   parseMailAddresses(aMailAddresses) {
-    let addresses = {},
-      names = {},
-      fullAddresses = {};
-    this._headerParser.parseHeadersWithArray(
-      aMailAddresses,
-      addresses,
-      names,
-      fullAddresses
-    );
+    let addresses = this._headerParser.parseEncodedHeader(aMailAddresses);
     return {
-      names: names.value,
-      addresses: addresses.value,
-      fullAddresses: fullAddresses.value,
-      count: names.value.length,
+      names: addresses.map(a => a.name || null),
+      addresses: addresses.map(a => a.email),
+      fullAddresses: addresses.map(a => a.toString()),
+      count: addresses.length,
     };
   },
 
   /**
    * MD5 hash a string and return the hex-string result. Impl from nsICryptoHash
    *  docs.
    */
   md5HashString(aString) {
--- a/mailnews/mime/public/nsIMsgHeaderParser.idl
+++ b/mailnews/mime/public/nsIMsgHeaderParser.idl
@@ -85,17 +85,17 @@ interface nsIMsgHeaderParser : nsISuppor
    *
    * @param aEncodedHeader  The RFC 2047-encoded header to parse.
    * @param aHeaderCharset  The charset to assume for raw octets.
    * @param aPreserveGroups If false (the default), the result is a flat array
    *                        of mailbox objects, containing no group objects.
    * @return                An array corresponding to the header description.
    */
   void parseEncodedHeader(in ACString aEncodedHeader,
-                          in string aHeaderCharset,
+                          [optional] in string aHeaderCharset,
                           [optional] in bool aPreserveGroups,
                           [optional] out unsigned long length,
                           [retval, array, size_is(length)]
                           out msgIAddressObject addresses);
 
   /**
    * Parse an address-based header that has not yet been 2047-decoded and does not
    * contain raw octets but instead wide (UTF-16) characters.
@@ -190,23 +190,16 @@ interface nsIMsgHeaderParser : nsISuppor
    * "Bond, James <agent007@mi5.invalid>" would produce one address object,
    * while the string "webmaster@nowhere.invalid, child@nowhere.invalid" would
    * produce two address objects.
    */
   void makeFromDisplayAddress(in AString aDisplayAddresses,
                               [optional] out unsigned long count,
                               [retval, array, size_is(count)] out msgIAddressObject addresses);
 
-  /* @deprecated */ void parseHeadersWithArray(in wstring aLine,
-                             [array, size_is(count)] out wstring aEmailAddresses,
-                             [array, size_is(count)] out wstring aNames,
-                             [array, size_is(count)] out wstring aFullNames,
-                             [retval] out unsigned long count);
-
-
   /**
    * Given a string which contains a list of Header addresses, returns a
    * comma-separated list of just the `mailbox' portions.
    *
    * @param aLine          The header line to parse.
    * @return               A comma-separated list of just the mailbox parts
    *                       of the email-addresses.
    */
--- a/mailnews/mime/src/mimeJSComponents.js
+++ b/mailnews/mime/src/mimeJSComponents.js
@@ -438,40 +438,16 @@ MimeAddressParser.prototype = {
       return this.makeMailboxObject(
         lbracket == 0 ? "" : aDisplayName.slice(0, lbracket).trim(),
         aDisplayName.slice(lbracket + 1, rbracket)
       );
     }
     return this.makeMailboxObject("", aDisplayName);
   },
 
-  // What follows is the deprecated API that will be removed shortly.
-
-  parseHeadersWithArray(aHeader, aAddrs, aNames, aFullNames) {
-    let addrs = [],
-      names = [],
-      fullNames = [];
-    let allAddresses = this.parseEncodedHeader(aHeader, undefined, false);
-
-    // Don't index the dummy empty address.
-    if (aHeader.trim() == "") {
-      allAddresses = [];
-    }
-    for (let address of allAddresses) {
-      addrs.push(address.email);
-      names.push(address.name || null);
-      fullNames.push(address.toString());
-    }
-
-    aAddrs.value = addrs;
-    aNames.value = names;
-    aFullNames.value = fullNames;
-    return allAddresses.length;
-  },
-
   extractHeaderAddressMailboxes(aLine) {
     return this.parseDecodedHeader(aLine)
       .map(addr => addr.email)
       .join(", ");
   },
 
   makeMimeAddress(aName, aEmail) {
     let object = this.makeMailboxObject(aName, aEmail);
--- a/mailnews/mime/test/unit/test_nsIMsgHeaderParser2.js
+++ b/mailnews/mime/test/unit/test_nsIMsgHeaderParser2.js
@@ -56,27 +56,16 @@ function run_test() {
     [
       "Undisclosed recipients:;",
       "", // Mailboxes
       "", // Address Names
       "",
     ], // Address Name
   ];
 
-  // this used to cause memory read overruns
-  let addresses = {},
-    names = {},
-    fullAddresses = {};
-  MailServices.headerParser.parseHeadersWithArray(
-    '" "@a a;b',
-    addresses,
-    names,
-    fullAddresses
-  );
-
   // Test - empty strings
 
   Assert.equal(MailServices.headerParser.extractHeaderAddressMailboxes(""), "");
   Assert.equal(MailServices.headerParser.extractFirstName(""), "");
 
   // Test - extractHeaderAddressMailboxes
 
   for (let i = 0; i < checks.length; ++i) {
--- a/mailnews/mime/test/unit/test_nsIMsgHeaderParser5.js
+++ b/mailnews/mime/test/unit/test_nsIMsgHeaderParser5.js
@@ -70,16 +70,24 @@ function run_test() {
       [{ name: "null=?UTF-8?Q?=00?=byte", email: "nullbyte@example.com" }],
       [{ name: "nullbyte", email: "nullbyte@example.com" }],
     ],
     [
       '"null=?UTF-8?B?AA==?=byte" <nullbyte@example.com>',
       [{ name: "null=?UTF-8?B?AA==?=byte", email: "nullbyte@example.com" }],
       [{ name: "nullbyte", email: "nullbyte@example.com" }],
     ],
+    ["", [], []],
+    [" \r\n\t", [], []],
+    [
+      // This used to cause memory read overruns.
+      '" "@a a;b',
+      [{ name: "", email: '" "@a a' }, { name: "b", email: "" }],
+      [{ name: "", email: "@a a" }, { name: "b", email: "" }],
+    ],
   ];
 
   for (let check of checks) {
     equalArrays(
       MailServices.headerParser.parseDecodedHeader(check[0]),
       check[1]
     );
     equalArrays(
deleted file mode 100644
--- a/mailnews/mime/test/unit/test_parseHeadersWithArray.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Test that nsIMsgHeaderParser.parseHeadersWithArray returns
- * null instead of 0-length strings.
- */
-
-var { MailServices } = ChromeUtils.import(
-  "resource:///modules/MailServices.jsm"
-);
-
-function run_test() {
-  let addresses = {},
-    names = {},
-    fullAddresses = {};
-  let n = MailServices.headerParser.parseHeadersWithArray(
-    "example@host.invalid",
-    addresses,
-    names,
-    fullAddresses
-  );
-  Assert.equal(1, n);
-  Assert.equal("example@host.invalid", addresses.value[0]);
-  Assert.equal(null, names.value[0]);
-  Assert.equal("example@host.invalid", fullAddresses.value[0]);
-}
--- a/mailnews/mime/test/unit/xpcshell.ini
+++ b/mailnews/mime/test/unit/xpcshell.ini
@@ -13,14 +13,13 @@ support-files = custom_header.js
 [test_message_attachment.js]
 [test_mimeContentType.js]
 [test_mimeStreaming.js]
 [test_nsIMsgHeaderParser1.js]
 [test_nsIMsgHeaderParser2.js]
 [test_nsIMsgHeaderParser3.js]
 [test_nsIMsgHeaderParser4.js]
 [test_nsIMsgHeaderParser5.js]
-[test_parseHeadersWithArray.js]
 [test_parser.js]
 [test_rfc822_body.js]
 [test_smime_decrypt.js]
 [test_structured_headers.js]
 [test_text_attachment.js]