From e20a85661438105833a81a309b488db62725a732 Mon Sep 17 00:00:00 2001 From: Geoff Lankow Date: Wed, 20 May 2020 10:42:35 +1200 Subject: [PATCH] Bug 1639430 - Create utility functions to use ICAL.js for parsing and encoding vCard. r=mkmelin --HG-- extra : rebase_source : b5082be98f08bedef81adcb1de45c115c6f7a690 extra : histedit_source : 972c42a1d65b79ac160ca439b19a4e425ba3fba8 --- mail/test/browser/message-window/browser.ini | 1 + mailnews/addrbook/jsaddrbook/VCardUtils.jsm | 307 +++++++++++++ mailnews/addrbook/jsaddrbook/moz.build | 1 + mailnews/addrbook/test/unit/test_vCard.js | 417 ++++++++++++++++++ mailnews/addrbook/test/unit/xpcshell.ini | 5 + .../resources/becky/addressbooks/4e4d186e.bab | 18 +- .../resources/becky/addressbooks/4e4d186f.bab | 9 +- mailnews/import/test/unit/xpcshell.ini | 2 + 8 files changed, 748 insertions(+), 12 deletions(-) create mode 100644 mailnews/addrbook/jsaddrbook/VCardUtils.jsm create mode 100644 mailnews/addrbook/test/unit/test_vCard.js diff --git a/mail/test/browser/message-window/browser.ini b/mail/test/browser/message-window/browser.ini index 590b2296c4..5f45c671b3 100644 --- a/mail/test/browser/message-window/browser.ini +++ b/mail/test/browser/message-window/browser.ini @@ -15,4 +15,5 @@ skip-if = os == "linux" || os = "mac" [browser_emlSubject.js] [browser_messageSidebar.js] [browser_vcardActions.js] +tags = vcard [browser_viewPlaintext.js] diff --git a/mailnews/addrbook/jsaddrbook/VCardUtils.jsm b/mailnews/addrbook/jsaddrbook/VCardUtils.jsm new file mode 100644 index 0000000000..a761637d44 --- /dev/null +++ b/mailnews/addrbook/jsaddrbook/VCardUtils.jsm @@ -0,0 +1,307 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +const EXPORTED_SYMBOLS = ["VCardUtils"]; + +const { ICAL } = ChromeUtils.import("resource:///modules/calendar/Ical.jsm"); + +/** + * Utilities for working with vCard data. This file uses ICAL.js as parser and + * formatter to avoid reinventing the wheel. + * @see RFC 6350. + */ + +var VCardUtils = { + vCardToAbCard(vCard) { + let [, properties] = ICAL.parse(vCard); + let abCard = Cc["@mozilla.org/addressbook/cardproperty;1"].createInstance( + Ci.nsIAbCard + ); + + for (let [name, params, , value] of properties) { + if (name == "uid") { + abCard.UID = value; + continue; + } + if (["adr", "tel"].includes(name)) { + if ( + params.type && + ["home", "work", "cell"].includes(params.type.toLowerCase()) + ) { + name = `${name}.${params.type.toLowerCase()}`; + } else { + name = `${name}.work`; + } + } + if (name in propertyMap) { + for (let [abPropName, abPropValue] of Object.entries( + propertyMap[name].toAbCard(value) + )) { + if (abPropValue) { + abCard.setProperty(abPropName, abPropValue); + } + } + } + } + return abCard; + }, + modifyVCard(vCard, abCard) { + let card = ICAL.parse(vCard); + let [, vProps] = card; + + // Collect all of the AB card properties into a Map. + let abProps = new Map(); + for (let abProp of abCard.properties) { + if (abProp.value) { + abProps.set(abProp.name, abProp.value); + } + } + + // Collect all of the existing vCard properties into a Map. + let indices = new Map(); + for (let i = 0; i < vProps.length; i++) { + let [vPropName, vPropParams] = vProps[i]; + if (vPropParams.type) { + vPropName += `.${vPropParams.type}`; + } + indices.set(vPropName, i); + } + + // Update the vCard. + for (let vPropName of Object.keys(propertyMap)) { + let vProp = propertyMap[vPropName].fromAbCard(abProps); + + let index = indices.get(vPropName); + if (vProp) { + // The vCard might have the property, but with no type specified. + // If it does, use that. + if (index === undefined && vPropName.includes(".")) { + index = indices.get(vPropName.split(".")[0]); + // Default to not specifying a type, where this applies. + delete vProp[1].type; + } + + if (index === undefined) { + // New property, add it. + vProps.push(vProp); + } else { + // Existing property, update it. + vProps[index][3] = vProp[3]; + } + } else if (index !== undefined) { + // Removed property, remove it. + vProps.splice(index, 1); + } + } + + // Always add a UID if there isn't one. + if (vProps.findIndex(prop => prop[0] == "uid") == -1) { + vProps.push(["uid", {}, "text", abCard.UID]); + } + + return ICAL.stringify(card); + }, + abCardToVCard(abCard) { + let vProps = [["version", {}, "text", "4.0"]]; + + // Collect all of the AB card properties into a Map. + let abProps = new Map(); + for (let abProp of abCard.properties) { + if (abProp.value) { + abProps.set(abProp.name, abProp.value); + } + } + + // Add the properties to the vCard. + for (let vPropName of Object.keys(propertyMap)) { + let vProp = propertyMap[vPropName].fromAbCard(abProps, vPropName); + if (vProp) { + vProps.push(vProp); + } + } + + // If there's only one address or telephone number, don't specify type. + let adrProps = vProps.filter(p => p[0] == "adr"); + if (adrProps.length == 1) { + delete adrProps[0][1].type; + } + let telProps = vProps.filter(p => p[0] == "tel"); + if (telProps.length == 1) { + delete telProps[0][1].type; + } + + vProps.push(["uid", {}, "text", abCard.UID]); + return ICAL.stringify(["vcard", vProps]); + }, +}; + + +/** Helper functions for propertyMap. */ + +function singleTextProperty( + abPropName, + vPropName, + vPropParams = {}, + vPropType = "text" +) { + return { + /** + * Formats nsIAbCard properties into an array for use by ICAL.js. + * + * @param {Map} map - A map of address book properties to map. + * @return {?Array} - Values in a jCard array for use with ICAL.js. + */ + fromAbCard(map) { + if (map.has(abPropName)) { + return [vPropName, { ...vPropParams }, vPropType, map.get(abPropName)]; + } + return null; + }, + /** + * Parses a vCard value into properties usable by nsIAbCard. + * + * @param {string} value - vCard string to map to an address book card property. + * @return {Object} - A dictionary of address book properties. + */ + toAbCard(value) { + if (typeof value != "string") { + console.warn(`Unexpected value for ${vPropName}: ${value}`); + return {}; + } + return { [abPropName]: value }; + }, + }; +} +function dateProperty(abCardPrefix, vPropName) { + return { + fromAbCard(map) { + if ( + !map.has(`${abCardPrefix}Year`) || + !map.has(`${abCardPrefix}Month`) || + !map.has(`${abCardPrefix}Day`) + ) { + return null; + } + let dateValue = new ICAL.VCardTime( + { + year: Number(map.get(`${abCardPrefix}Year`)), + month: Number(map.get(`${abCardPrefix}Month`)), + day: Number(map.get(`${abCardPrefix}Day`)), + }, + null, + "date" + ); + return [vPropName, {}, "date", dateValue.toString()]; + }, + toAbCard(value) { + let dateValue = new Date(value); + return { + [`${abCardPrefix}Year`]: String(dateValue.getFullYear()), + [`${abCardPrefix}Month`]: String(dateValue.getMonth() + 1), + [`${abCardPrefix}Day`]: String(dateValue.getDate()), + }; + }, + }; +} +function multiTextProperty(abPropNames, vPropName, vPropParams = {}) { + return { + fromAbCard(map) { + if (abPropNames.every(name => !map.has(name))) { + return null; + } + return [ + vPropName, + { ...vPropParams }, + "text", + abPropNames.map(name => map.get(name) || ""), + ]; + }, + toAbCard(value) { + let result = {}; + if (!Array.isArray(value)) { + console.warn(`Unexpected value for ${vPropName}: ${value}`); + return result; + } + for (let abPropName of abPropNames) { + let valuePart = value.shift(); + if (abPropName && valuePart) { + result[abPropName] = valuePart; + } + } + return result; + }, + }; +} + +/** + * Properties we support for conversion between nsIAbCard and vCard. + * + * Keys correspond to vCard property keys, with the type appended where more + * than one type is supported (e.g. work and home). + * + * Values are objects with toAbCard and fromAbCard functions which convert + * property values in each direction. See the docs on the object returned by + * singleTextProperty. + */ +var propertyMap = { + email: singleTextProperty("PrimaryEmail", "email"), + fn: singleTextProperty("DisplayName", "fn"), + nickname: singleTextProperty("NickName", "nickname"), + note: singleTextProperty("Notes", "note"), + org: multiTextProperty(["Company", "Department"], "org"), + title: singleTextProperty("JobTitle", "title"), + bday: dateProperty("Birth", "bday"), + anniversary: dateProperty("Anniversary", "anniversary"), + n: multiTextProperty(["LastName", "FirstName", null, null, null], "n"), + "adr.home": multiTextProperty( + [ + null, + "HomeAddress2", + "HomeAddress", + "HomeCity", + "HomeState", + "HomeZipCode", + "HomeCountry", + ], + "adr", + { type: "home" } + ), + "adr.work": multiTextProperty( + [ + null, + "WorkAddress2", + "WorkAddress", + "WorkCity", + "WorkState", + "WorkZipCode", + "WorkCountry", + ], + "adr", + { type: "work" } + ), + "tel.home": singleTextProperty("HomePhone", "tel", { type: "home" }), + "tel.work": singleTextProperty("WorkPhone", "tel", { type: "work" }), + "tel.fax": singleTextProperty("FaxNumber", "tel", { type: "fax" }), + "tel.pager": singleTextProperty("PagerNumber", "tel", { type: "pager" }), + "tel.cell": singleTextProperty("CellularNumber", "tel", { type: "cell" }), + url: singleTextProperty("WebPage1", "url", {}, "url"), + "x-mozilla-html": { + fromAbCard(map) { + switch (map.get("PreferMailFormat")) { + case Ci.nsIAbPreferMailFormat.html: + return ["x-mozilla-html", {}, "boolean", true]; + case Ci.nsIAbPreferMailFormat.plaintext: + return ["x-mozilla-html", {}, "boolean", false]; + } + return null; + }, + toAbCard(value) { + if (typeof value != "boolean") { + console.warn(`Unexpected value for x-mozilla-html: ${value}`); + return {}; + } + return { PreferMailFormat: value }; + }, + }, +}; diff --git a/mailnews/addrbook/jsaddrbook/moz.build b/mailnews/addrbook/jsaddrbook/moz.build index c08e4a874d..da44623ffc 100644 --- a/mailnews/addrbook/jsaddrbook/moz.build +++ b/mailnews/addrbook/jsaddrbook/moz.build @@ -8,6 +8,7 @@ EXTRA_JS_MODULES += [ 'AddrBookMailingList.jsm', 'AddrBookManager.jsm', 'AddrBookUtils.jsm', + 'VCardUtils.jsm', ] XPCOM_MANIFESTS += [ diff --git a/mailnews/addrbook/test/unit/test_vCard.js b/mailnews/addrbook/test/unit/test_vCard.js new file mode 100644 index 0000000000..6380ac5066 --- /dev/null +++ b/mailnews/addrbook/test/unit/test_vCard.js @@ -0,0 +1,417 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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"); + +const ANY_UID = "UID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; + +add_task(function testVCardToAbCard() { + function check(vCardLine, expectedProps) { + const propWhitelist = [ + "LastModifiedDate", + "PopularityIndex", + "PreferMailFormat", + ]; + + let vCard = `BEGIN:VCARD\r\n${vCardLine}\r\nEND:VCARD\r\n`; + info(vCard); + let abCard = VCardUtils.vCardToAbCard(vCard); + // Check that every property in expectedProps is present in `abCard`. + // No other property can be present unless it is in `propWhitelist`. + for (let prop of abCard.properties) { + if (prop.name in expectedProps) { + equal(prop.value, expectedProps[prop.name], `expected ${prop.name}`); + delete expectedProps[prop.name]; + } else if (!propWhitelist.includes(prop.name)) { + ok(false, `unexpected ${prop.name}`); + } + } + + for (let name of Object.keys(expectedProps)) { + ok(false, `expected ${name} not found`); + } + } + + // UID + check("UID:12345678-1234-1234-1234-123456789012", { + UID: "12345678-1234-1234-1234-123456789012", + }); + // Name + check("N:Last;First;Middle;Prefix;Suffix", { + FirstName: "First", + LastName: "Last", + }); + + // Address + check("ADR:;;123 Main Street;Any Town;CA;91921-1234;U.S.A.", { + WorkAddress: "123 Main Street", + WorkCity: "Any Town", + WorkState: "CA", + WorkZipCode: "91921-1234", + WorkCountry: "U.S.A.", + }); + check("ADR;TYPE=work:;;123 Main Street;Any Town;CA;91921-1234;U.S.A.", { + WorkAddress: "123 Main Street", + WorkCity: "Any Town", + WorkState: "CA", + WorkZipCode: "91921-1234", + WorkCountry: "U.S.A.", + }); + check("ADR;TYPE=home:;;123 Main Street;Any Town;CA;91921-1234;U.S.A.", { + 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;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", + } + ); + // Birthday + check("BDAY;VALUE=DATE:19830403", { + BirthDay: "3", + BirthMonth: "4", + BirthYear: "1983", + }); + // Anniversary + check("ANNIVERSARY;VALUE=DATE:20041207", { + AnniversaryDay: "7", + AnniversaryMonth: "12", + AnniversaryYear: "2004", + }); +}); + +add_task(function testModifyVCard() { + function check( + inVCard, + newProps, + expectedLines = [], + unexpectedPrefixes = [] + ) { + let abCard = VCardUtils.vCardToAbCard(inVCard); + for (let [name, value] of Object.entries(newProps)) { + if (value === null) { + abCard.deleteProperty(name); + } else { + abCard.setProperty(name, value); + } + } + + let outVCard = VCardUtils.modifyVCard(inVCard, abCard); + info(outVCard); + + let lineCounts = {}; + for (let line of expectedLines) { + let [prefix] = line.split(":"); + if (prefix in lineCounts) { + lineCounts[prefix]++; + } else { + lineCounts[prefix] = 1; + } + } + + // Check if `prefix` is expected. If it is expected, check that `line` is + // exactly as specified. If it is unexpected, complain. Otherwise, ignore. + for (let line of outVCard.split("\r\n")) { + let [prefix] = line.split(":"); + if (prefix == "UID" && expectedLines.includes(ANY_UID)) { + line = ANY_UID; + } + + if (unexpectedPrefixes.includes(prefix)) { + ok(false, `unexpected ${prefix} line`); + } else if (prefix in lineCounts) { + let index = expectedLines.indexOf(line); + ok(index > -1, `line was expected: ${line}`); + expectedLines.splice(index, 1); + lineCounts[prefix]--; + } else { + ok(true, `line was ignored: ${line}`); + } + } + + // Check that all expected lines are in `outVCard`. + for (let [prefix, count] of Object.entries(lineCounts)) { + equal(count, 0, `${count} ${prefix} lines remain`); + } + } + + // Empty card, no modifications. + check( + formatVCard` + BEGIN:VCARD + END:VCARD`, + {}, + [ANY_UID] + ); + // Card with UID, no modifications. + check( + formatVCard` + BEGIN:VCARD + UID:12345678-1234-1234-1234-123456789012 + END:VCARD`, + {}, + ["UID:12345678-1234-1234-1234-123456789012"] + ); + // Display name changed, notes removed, UID unchanged. + check( + formatVCard` + BEGIN:VCARD + FN:Original Full Name + NOTE:This property will be removed. + UID:12345678-1234-1234-1234-123456789012 + END:VCARD`, + { + DisplayName: "New Full Name", + Notes: null, + }, + ["FN:New Full Name", "UID:12345678-1234-1234-1234-123456789012"], + ["NOTE"] + ); + // Last name changed. + check( + formatVCard` + BEGIN:VCARD + N:Last;First;;; + END:VCARD`, + { + LastName: "Changed", + }, + ["N:Changed;First;;;", ANY_UID] + ); + // First and last name changed. + check( + formatVCard` + BEGIN:VCARD + N:Last;First;;; + END:VCARD`, + { + LastName: "Changed", + FirstName: "New", + }, + ["N:Changed;New;;;", ANY_UID] + ); + // Work address changed. Other address types should not appear. + check( + formatVCard` + BEGIN:VCARD + ADR;TYPE=work:;;123 Main Street;Any Town;CA;91921-1234;U.S.A. + END:VCARD`, + { + WorkAddress: "345 Main Street", + }, + ["ADR;TYPE=work:;;345 Main Street;Any Town;CA;91921-1234;U.S.A.", ANY_UID], + ["ADR", "ADR;TYPE=home"] + ); + // Home address changed. Other address types should not appear. + check( + formatVCard` + BEGIN:VCARD + ADR;TYPE=home:;;123 Main Street;Any Town;CA;91921-1234;U.S.A. + END:VCARD`, + { + HomeAddress: "345 Main Street", + }, + ["ADR;TYPE=home:;;345 Main Street;Any Town;CA;91921-1234;U.S.A.", ANY_UID], + ["ADR", "ADR;TYPE=work"] + ); + // Address changed. Other address types should not appear. + check( + formatVCard` + BEGIN:VCARD + ADR:;;123 Main Street;Any Town;CA;91921-1234;U.S.A. + END:VCARD`, + { + WorkAddress: "345 Main Street", + }, + ["ADR:;;345 Main Street;Any Town;CA;91921-1234;U.S.A.", ANY_UID], + ["ADR;TYPE=work", "ADR;TYPE=home"] + ); + // Card with properties we don't support. They should remain unchanged. + check( + formatVCard` + BEGIN:VCARD + X-FOO-BAR:foo bar + X-BAZ;VALUE=URI:https://www.example.com/ + QUUX:This property is out of spec but we shouldn't touch it anyway. + FN:My full name + END:VCARD`, + { + DisplayName: "My other full name", + }, + [ + "FN:My other full name", + "X-FOO-BAR:foo bar", + "X-BAZ;VALUE=URI:https://www.example.com/", + "QUUX:This property is out of spec but we shouldn't touch it anyway.", + ANY_UID, + ] + ); +}); + +add_task(function testAbCardToVCard() { + function check(abCardProps, ...expectedLines) { + let abCard = Cc["@mozilla.org/addressbook/cardproperty;1"].createInstance( + Ci.nsIAbCard + ); + for (let [name, value] of Object.entries(abCardProps)) { + if (name == "UID") { + abCard.UID = abCardProps.UID; + continue; + } + abCard.setProperty(name, value); + } + + let vCard = VCardUtils.abCardToVCard(abCard); + info(vCard); + let vCardLines = vCard.split("\r\n"); + if (expectedLines.includes(ANY_UID)) { + for (let i = 0; i < vCardLines.length; i++) { + if (vCardLines[i].startsWith("UID:")) { + vCardLines[i] = ANY_UID; + } + } + } + + for (let line of expectedLines) { + Assert.ok(vCardLines.includes(line), line); + } + } + + // UID + check( + { + UID: "12345678-1234-1234-1234-123456789012", + }, + "UID:12345678-1234-1234-1234-123456789012" + ); + // Name + check( + { + FirstName: "First", + LastName: "Last", + }, + "N:Last;First;;;", + ANY_UID + ); + + // Address + check( + { + WorkAddress: "123 Main Street", + WorkCity: "Any Town", + WorkState: "CA", + WorkZipCode: "91921-1234", + WorkCountry: "U.S.A.", + }, + "ADR:;;123 Main Street;Any Town;CA;91921-1234;U.S.A.", + ANY_UID + ); + check( + { + HomeAddress: "123 Main Street", + HomeCity: "Any Town", + HomeState: "CA", + HomeZipCode: "91921-1234", + HomeCountry: "U.S.A.", + }, + "ADR:;;123 Main Street;Any Town;CA;91921-1234;U.S.A.", + ANY_UID + ); + // Phone + check( + { + WorkPhone: "11-2358-13-21", + }, + "TEL;VALUE=TEXT:11-2358-13-21", + ANY_UID + ); + check( + { + HomePhone: "011-2358-13-21", + }, + "TEL;VALUE=TEXT:011-2358-13-21", + ANY_UID + ); + check( + { + WorkPhone: "11-2358-13-21", + HomePhone: "011-2358-13-21", + }, + "TEL;TYPE=work;VALUE=TEXT:11-2358-13-21", + "TEL;TYPE=home;VALUE=TEXT:011-2358-13-21", + ANY_UID + ); + // Birthday + check( + { + BirthDay: "3", + BirthMonth: "4", + BirthYear: "1983", + }, + "BDAY;VALUE=DATE:19830403", + ANY_UID + ); + // Anniversary + check( + { + AnniversaryDay: "7", + AnniversaryMonth: "12", + AnniversaryYear: "2004", + }, + "ANNIVERSARY;VALUE=DATE:20041207", + ANY_UID + ); +}); + +add_task(function() { + // Check that test_becky_addressbook.js won't fail, without being on Windows. + let v = formatVCard` + BEGIN:VCARD + VERSION:3.0 + UID:4E4D17E8.0043655C + FN:The first man + ORG:Organization;Post; + X-BECKY-IMAGE:0 + N:The nick name of the first man + TEL;TYPE=HOME:11-1111-1111 + TEL;TYPE=WORK:22-2222-2222 + TEL;TYPE=CELL:333-3333-3333 + EMAIL;TYPE=INTERNET;PREF:first@host.invalid + NOTE;ENCODING=QUOTED-PRINTABLE:This is a note. + END:VCARD`; + + let a = VCardUtils.vCardToAbCard(v); + Assert.equal(a.getProperty("DisplayName", "BAD"), "The first man"); + Assert.equal(a.getProperty("PrimaryEmail", "BAD"), "first@host.invalid"); + Assert.equal(a.getProperty("HomePhone", "BAD"), "11-1111-1111"); + Assert.equal(a.getProperty("WorkPhone", "BAD"), "22-2222-2222"); + Assert.equal(a.getProperty("CellularNumber", "BAD"), "333-3333-3333"); + Assert.equal(a.getProperty("Company", "BAD"), "Organization"); + Assert.equal(a.getProperty("Notes", "BAD"), "This is a note."); +}); + +function formatVCard([str]) { + let lines = str.split("\n"); + let indent = lines[1].length - lines[1].trimLeft().length; + let outLines = []; + for (let line of lines) { + if (line.length > 0) { + outLines.push(line.substring(indent) + "\r\n"); + } + } + return outLines.join(""); +} diff --git a/mailnews/addrbook/test/unit/xpcshell.ini b/mailnews/addrbook/test/unit/xpcshell.ini index d03388f3e1..d85c04ef48 100644 --- a/mailnews/addrbook/test/unit/xpcshell.ini +++ b/mailnews/addrbook/test/unit/xpcshell.ini @@ -6,6 +6,7 @@ tags = addrbook [test_basic_nsIAbCard.js] [test_basic_nsIAbDirectory.js] [test_bug387403.js] +tags = vcard [test_bug448165.js] [test_bug534822.js] [test_bug1522453.js] @@ -15,6 +16,7 @@ tags = addrbook [test_db_enumerator.js] [test_delete_book.js] [test_export.js] +tags = vcard [test_jsaddrbook.js] [test_ldap1.js] [test_ldap2.js] @@ -37,4 +39,7 @@ skip-if = debug # Fails for unknown reasons. [test_nsAbManager4.js] [test_nsAbManager5.js] [test_nsIAbCard.js] +tags = vcard [test_search.js] +[test_vCard.js] +tags = vcard diff --git a/mailnews/import/test/unit/resources/becky/addressbooks/4e4d186e.bab b/mailnews/import/test/unit/resources/becky/addressbooks/4e4d186e.bab index 9decbb55e0..2b7e4de7e9 100644 --- a/mailnews/import/test/unit/resources/becky/addressbooks/4e4d186e.bab +++ b/mailnews/import/test/unit/resources/becky/addressbooks/4e4d186e.bab @@ -1,24 +1,26 @@ BEGIN:VCARD +VERSION:3.0 UID:4E4D17E8.0043655C FN:The first man ORG:Organization;Post; X-BECKY-IMAGE:0 N:The nick name of the first man -TEL;HOME:11-1111-1111 -TEL;WORK:22-2222-2222 -TEL;CELL:333-3333-3333 -EMAIL;PREF:first@host.invalid +TEL;TYPE=HOME:11-1111-1111 +TEL;TYPE=WORK:22-2222-2222 +TEL;TYPE=CELL:333-3333-3333 +EMAIL;TYPE=INTERNET;PREF:first@host.invalid NOTE;ENCODING=QUOTED-PRINTABLE:This is a note. END:VCARD BEGIN:VCARD +VERSION:3.0 UID:4EBBF6FE.00AC632B FN:The second man ORG:Organization;post; X-BECKY-IMAGE:0 N:The nick name of the second man -TEL;HOME:44-4444-4444 -TEL;WORK:55-5555-5555 -TEL;CELL:666-6666-6666 -EMAIL;PREF:second@host.invalid +TEL;TYPE=HOME:44-4444-4444 +TEL;TYPE=WORK:55-5555-5555 +TEL;TYPE=CELL:666-6666-6666 +EMAIL;TYPE=INTERNET;PREF:second@host.invalid NOTE;ENCODING=QUOTED-PRINTABLE:This is a note. END:VCARD diff --git a/mailnews/import/test/unit/resources/becky/addressbooks/4e4d186f.bab b/mailnews/import/test/unit/resources/becky/addressbooks/4e4d186f.bab index d4497dc96f..13df134ef8 100644 --- a/mailnews/import/test/unit/resources/becky/addressbooks/4e4d186f.bab +++ b/mailnews/import/test/unit/resources/becky/addressbooks/4e4d186f.bab @@ -1,12 +1,13 @@ BEGIN:VCARD +VERSION:3.0 UID:4E57AB44.0001D53E FN:The third man ORG:Organization;post; X-BECKY-IMAGE:0 N:The third man -TEL;HOME:77-7777-7777 -TEL;WORK:88-8888-8888 -TEL;CELL:999-9999-9999 -EMAIL;PREF:third@host.invalid +TEL;TYPE=HOME:77-7777-7777 +TEL;TYPE=WORK:88-8888-8888 +TEL;TYPE=CELL:999-9999-9999 +EMAIL;TYPE=INTERNET;PREF:third@host.invalid NOTE;ENCODING=QUOTED-PRINTABLE:This is a note. END:VCARD diff --git a/mailnews/import/test/unit/xpcshell.ini b/mailnews/import/test/unit/xpcshell.ini index d0823a2b46..fdaa9dc805 100644 --- a/mailnews/import/test/unit/xpcshell.ini +++ b/mailnews/import/test/unit/xpcshell.ini @@ -8,6 +8,7 @@ support-files = resources/* [test_csv_GetSample.js] [test_becky_addressbook.js] run-if = os == 'win' +tags = vcard [test_becky_filters.js] run-if = os == 'win' [test_csv_import.js] @@ -18,5 +19,6 @@ run-if = os == 'win' [test_shiftjis_csv.js] [test_utf16_csv.js] [test_vcard_import.js] +tags = vcard [test_winmail.js] run-if = os == 'win'