Bug 1793415 - Catch and report errors parsing dates from vCards. r=mkmelin

The parsing may fail but that shouldn't break things.

Changes to test_vCard.js are mostly reinstating a test I should not have removed (in https://hg.mozilla.org/comm-central/diff/7b22f4a4287431034851651aa94fa6c88717e235/mailnews/addrbook/test/unit/test_vCard.js) with some additional cases in the birthday section.

Differential Revision: https://phabricator.services.mozilla.com/D158539

--HG--
extra : rebase_source : d2e00b8653b33e23a7bc4803935bc9a14ffca26b
extra : amend_source : 3df743fc84663fc60d8e267169e044b9bbbd8591
This commit is contained in:
Geoff Lankow 2022-10-04 12:02:13 +13:00
Родитель cc353b7222
Коммит a3a6fc5d5d
4 изменённых файлов: 311 добавлений и 13 удалений

Просмотреть файл

@ -3032,7 +3032,12 @@ var detailsPane = {
list.replaceChildren();
let formatDate = function(date) {
date = ICAL.VCardTime.fromDateAndOrTimeString(date);
try {
date = ICAL.VCardTime.fromDateAndOrTimeString(date);
} catch (ex) {
Cu.reportError(ex);
return "";
}
if (date.year && date.month && date.day) {
return new Services.intl.DateTimeFormat(
Services.locale.appLocalesAsBCP47,

Просмотреть файл

@ -135,15 +135,20 @@ class VCardSpecialDateComponent extends HTMLElement {
return;
}
// Default value is date-and-or-time.
let dateValue = ICAL.VCardTime.fromDateAndOrTimeString(
this.vCardPropertyEntry.value || "",
"date-and-or-time"
);
let dateValue;
try {
dateValue = ICAL.VCardTime.fromDateAndOrTimeString(
this.vCardPropertyEntry.value || "",
"date-and-or-time"
);
} catch (ex) {
Cu.reportError(ex);
}
// Always set the month first since that controls the available days.
this.month.value = dateValue.month || "";
this.month.value = dateValue?.month || "";
this.fillDayOptions();
this.day.value = dateValue.day || "";
this.year.value = dateValue.year || "";
this.day.value = dateValue?.day || "";
this.year.value = dateValue?.year || "";
}
fromUIToVCardPropertyEntry() {

Просмотреть файл

@ -403,10 +403,14 @@ function dateProperty(abCardPrefix, vPropName) {
yield [vPropName, {}, "date", dateValue.toString()];
},
*toAbCard(value) {
let dateValue = ICAL.VCardTime.fromDateAndOrTimeString(value);
yield [`${abCardPrefix}Year`, String(dateValue.year)];
yield [`${abCardPrefix}Month`, String(dateValue.month)];
yield [`${abCardPrefix}Day`, String(dateValue.day)];
try {
let dateValue = ICAL.VCardTime.fromDateAndOrTimeString(value);
yield [`${abCardPrefix}Year`, String(dateValue.year ?? "")];
yield [`${abCardPrefix}Month`, String(dateValue.month ?? "")];
yield [`${abCardPrefix}Day`, String(dateValue.day ?? "")];
} catch (ex) {
Cu.reportError(ex);
}
},
};
}

Просмотреть файл

@ -2,10 +2,294 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at http://mozilla.org/MPL/2.0/. */
let { VCardUtils } = ChromeUtils.import("resource:///modules/VCardUtils.jsm");
let { VCardProperties, VCardUtils } = ChromeUtils.import(
"resource:///modules/VCardUtils.jsm"
);
const ANY_UID = "UID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
add_task(function testVCardToPropertyMap() {
function check(vCardLine, expectedProps) {
let vCard = `BEGIN:VCARD\r\n${vCardLine}\r\nEND:VCARD\r\n`;
info(vCard);
let properties = VCardProperties.fromVCard(vCard).toPropertyMap();
// Check that every property in expectedProps is present in `properties`.
// No other property can be present unless it is in `propWhitelist`.
for (let [name, value] of properties) {
if (name in expectedProps) {
Assert.equal(value, expectedProps[name], `expected ${name}`);
delete expectedProps[name];
} else {
Assert.ok(false, `card should not have property '${name}'`);
}
}
for (let name of Object.keys(expectedProps)) {
Assert.ok(false, `expected ${name} not found`);
}
}
// Name
check("N:Last;First", { FirstName: "First", LastName: "Last" });
check("N:Last;First;;;", { FirstName: "First", LastName: "Last" });
check("N:Last;First;Middle;Prefix;Suffix", {
FirstName: "First",
LastName: "Last",
AdditionalNames: "Middle",
NamePrefix: "Prefix",
NameSuffix: "Suffix",
});
check("N:Stevenson;John;Philip,Paul;Dr.;Jr.,M.D.,A.C.P.", {
FirstName: "John",
LastName: "Stevenson",
AdditionalNames: "Philip Paul",
NamePrefix: "Dr.",
NameSuffix: "Jr. M.D. A.C.P.",
});
// Address
check(
"ADR:PO Box 3.14;Apartment 4;123 Main Street;Any Town;CA;91921-1234;U.S.A.",
{
WorkPOBox: "PO Box 3.14",
WorkAddress2: "Apartment 4",
WorkAddress: "123 Main Street",
WorkCity: "Any Town",
WorkState: "CA",
WorkZipCode: "91921-1234",
WorkCountry: "U.S.A.",
}
);
check(
"ADR;TYPE=work:PO Box 3.14;Apartment 4;123 Main Street;Any Town;CA;91921-1234;U.S.A.",
{
WorkPOBox: "PO Box 3.14",
WorkAddress2: "Apartment 4",
WorkAddress: "123 Main Street",
WorkCity: "Any Town",
WorkState: "CA",
WorkZipCode: "91921-1234",
WorkCountry: "U.S.A.",
}
);
check(
"ADR;TYPE=home:PO Box 3.14;Apartment 4;123 Main Street;Any Town;CA;91921-1234;U.S.A.",
{
HomePOBox: "PO Box 3.14",
HomeAddress2: "Apartment 4",
HomeAddress: "123 Main Street",
HomeCity: "Any Town",
HomeState: "CA",
HomeZipCode: "91921-1234",
HomeCountry: "U.S.A.",
}
);
// Phone
check("TEL:11-2358-13-21", { WorkPhone: "11-2358-13-21" });
check("TEL;TYPE=work:11-2358-13-21", { WorkPhone: "11-2358-13-21" });
check("TEL;TYPE=home:11-2358-13-21", { HomePhone: "11-2358-13-21" });
check("TEL;TYPE=cell:11-2358-13-21", { CellularNumber: "11-2358-13-21" });
check("TEL;TYPE=pager:11-2358-13-21", { PagerNumber: "11-2358-13-21" });
check("TEL;TYPE=fax:11-2358-13-21", { FaxNumber: "11-2358-13-21" });
check("TEL;TYPE=work;PREF:11-2358-13-21", { WorkPhone: "11-2358-13-21" });
check("TEL;TYPE=work,cell:11-2358-13-21", { WorkPhone: "11-2358-13-21" });
check("TEL;TYPE=work;TYPE=cell:11-2358-13-21", {
WorkPhone: "11-2358-13-21",
});
check("TEL;TYPE=work;VALUE=TEXT:11-2358-13-21", {
WorkPhone: "11-2358-13-21",
});
check("TEL;TYPE=home;VALUE=TEXT:011-2358-13-21", {
HomePhone: "011-2358-13-21",
});
check(
"TEL;TYPE=work;VALUE=TEXT:11-2358-13-21\r\nTEL;TYPE=home;VALUE=TEXT:011-2358-13-21",
{
WorkPhone: "11-2358-13-21",
HomePhone: "011-2358-13-21",
}
);
check("TEL;TYPE=cell:11-2358-13-21\r\nTEL;TYPE=cell:011-2358-13-21", {
CellularNumber: "11-2358-13-21",
});
check("TEL;TYPE=cell;PREF=1:11-2358-13-21\r\nTEL;TYPE=cell:011-2358-13-21", {
CellularNumber: "11-2358-13-21",
});
check("TEL;TYPE=cell:11-2358-13-21\r\nTEL;TYPE=cell;PREF=1:011-2358-13-21", {
CellularNumber: "011-2358-13-21",
});
// Birthday
check("BDAY;VALUE=DATE:19830403", {
BirthDay: "3",
BirthMonth: "4",
BirthYear: "1983",
});
check("BDAY:--0415", { BirthDay: "15", BirthMonth: "4" });
check("BDAY:2001", { BirthYear: "2001" });
check("BDAY:2006-06", { BirthYear: "2006", BirthMonth: "6" });
check("BDAY:--12", { BirthMonth: "12" });
check("BDAY:---30", { BirthDay: "30" });
// These are error cases, testing that it doesn't throw.
check("BDAY;VALUE=DATE:NaN-NaN-NaN", {});
check("BDAY;VALUE=TEXT:07/07/1949", {});
// Anniversary
check("ANNIVERSARY;VALUE=DATE:20041207", {
AnniversaryDay: "7",
AnniversaryMonth: "12",
AnniversaryYear: "2004",
});
// Organization: any number of values is valid here.
check("ORG:Acme Widgets, Inc.", {
Company: "Acme Widgets, Inc.",
});
check("ORG:Acme Widgets, Inc.;Manufacturing", {
Company: "Acme Widgets, Inc.",
Department: "Manufacturing",
});
check("ORG:Acme Widgets, Inc.;Manufacturing;Thingamies", {
Company: "Acme Widgets, Inc.",
Department: "Manufacturing",
});
// URL
// If no type is given assume its WebPage1 (work).
check("URL:https://www.thunderbird.net/", {
WebPage1: "https://www.thunderbird.net/",
});
check("URL;TYPE=work:https://developer.thunderbird.net/", {
WebPage1: "https://developer.thunderbird.net/",
});
check("URL;TYPE=home:https://addons.thunderbird.net/", {
WebPage2: "https://addons.thunderbird.net/",
});
check(
formatVCard`
URL;TYPE=home:https://addons.thunderbird.net/
URL;TYPE=work:https://developer.thunderbird.net/`,
{
WebPage1: "https://developer.thunderbird.net/",
WebPage2: "https://addons.thunderbird.net/",
}
);
// If a URL without a type is given and a Work Web Page do not import the URL without type.
check(
formatVCard`
URL:https://www.thunderbird.net/
URL;TYPE=home:https://addons.thunderbird.net/
URL;TYPE=work:https://developer.thunderbird.net/`,
{
WebPage1: "https://developer.thunderbird.net/",
WebPage2: "https://addons.thunderbird.net/",
}
);
// Email: just to be difficult, email is stored by priority, not type.
check("EMAIL:first@invalid", { PrimaryEmail: "first@invalid" });
check("EMAIL;PREF=1:first@invalid", { PrimaryEmail: "first@invalid" });
check("EMAIL;PREF=1:first@invalid\r\nEMAIL:second@invalid", {
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
});
check("EMAIL:second@invalid\r\nEMAIL;PREF=1:first@invalid", {
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
});
check("EMAIL;PREF=1:first@invalid\r\nEMAIL;PREF=2:second@invalid", {
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
});
check("EMAIL;PREF=2:second@invalid\r\nEMAIL;PREF=1:first@invalid", {
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
});
check(
"EMAIL;PREF=1:first@invalid\r\nEMAIL;PREF=2:second@invalid\r\nEMAIL;PREF=3:third@invalid",
{
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
}
);
check(
"EMAIL;PREF=2:second@invalid\r\nEMAIL;PREF=3:third@invalid\r\nEMAIL;PREF=1:first@invalid",
{
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
}
);
check(
"EMAIL;PREF=3:third@invalid\r\nEMAIL;PREF=1:first@invalid\r\nEMAIL;PREF=2:second@invalid",
{
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
}
);
check(
"EMAIL;PREF=3:third@invalid\r\nEMAIL;PREF=2:second@invalid\r\nEMAIL;PREF=1:first@invalid",
{
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
}
);
check(
"EMAIL;PREF=2:second@invalid\r\nEMAIL;PREF=1:first@invalid\r\nEMAIL;PREF=3:third@invalid",
{
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
}
);
check(
"EMAIL;PREF=1:first@invalid\r\nEMAIL;PREF=3:third@invalid\r\nEMAIL;PREF=2:second@invalid",
{
PrimaryEmail: "first@invalid",
SecondEmail: "second@invalid",
}
);
// Group-prefixed properties.
check(
formatVCard`
item1.EMAIL:first@invalid
item1.X-ABLabel:First`,
{
PrimaryEmail: "first@invalid",
}
);
check(
formatVCard`
item1.EMAIL:first@invalid
item1.X-ABLabel:First
item2.EMAIL:second@invalid
item2.X-ABLabel:Second`,
{ PrimaryEmail: "first@invalid", SecondEmail: "second@invalid" }
);
check(
formatVCard`
foo-bar.EMAIL:first@invalid
foo-bar.X-ABLabel:First
EMAIL:second@invalid`,
{ PrimaryEmail: "first@invalid", SecondEmail: "second@invalid" }
);
check(
formatVCard`
EMAIL:first@invalid
abc.EMAIL:second@invalid
abc.X-ABLabel:Second`,
{ PrimaryEmail: "first@invalid", SecondEmail: "second@invalid" }
);
check("xyz.TEL:11-2358-13-21", { WorkPhone: "11-2358-13-21" });
});
add_task(function testAbCardToVCard() {
function check(abCardProps, ...expectedLines) {
let abCard = Cc["@mozilla.org/addressbook/cardproperty;1"].createInstance(