RFC 9555
JSContact: Converting from and to vCard
RFC 9555: JSContact: Converting from and to vCard πβ¨
Okay bestie, this is the RFC that teaches JSContact and vCard to talk to each other. π«Ά Here's the title block, all the details up top:
- Stream: Internet Engineering Task Force (IETF) πΈ
- RFC number: 9555 π
- Authors: M. Loffredo (IIT-CNR/Registro.it) and R. Stepanek (Fastmail) π―
- Category: Standards Track π
- Date: May 2024 π
- ISSN: 2070-1721 π¦
- Updates:
6350(so it's an update to RFC 6350, the vCard spec) π₯ - Obsoletes: nothing is listed in this header π
Abstract π§
This doc is all about how to convert contact info between the JSContact and vCard data formats. It sets conversion rules for every JSContact and vCard element that was registered at IANA when it was published, so no element gets left out π . It also defines brand-new JSContact properties and vCard properties and parameters. Those exist so you can convert arbitrary or unknown JSContact and vCard elements too, even the weird ones πβ¨.
Status of This Memo π
This is an Internet Standards Track document, so it's official-official π.
It's a product of the Internet Engineering Task Force (IETF), and it represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check out Section 2 of RFC 7841 π«Ά.
You can find the current status of this document, any errata, and how to send feedback at https://www.rfc-editor.org/info/rfc9555 π¬.
Copyright Notice π
Copyright (c) 2024 IETF Trust and the people listed as the document authors. All rights reserved π.
This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info), as they stand on the publication date. Please read these carefully, because they spell out your rights and restrictions for this document π. Code components pulled out of this document have to include Revised BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, just like the Revised BSD License says βοΈ.
This document might include material from IETF Documents or IETF Contributions that were published or made publicly available before November 10, 2008. The people who control the copyright in some of that material may not have given the IETF Trust permission to allow modifications outside the IETF Standards Process π. Unless you get a proper license from those copyright holders, this document can't be modified outside the IETF Standards Process, and derivative works of it can't be made outside the IETF Standards Process either. The one exceptions are formatting it for publication as an RFC or translating it into languages other than English π.
Table of Contents π
1. Introduction
1.1. Motivation
1.2. Notational Conventions
1.3. ABNF Notations
2. Converting vCard to JSContact
2.1. General Rules
2.1.1. The Card uid Property
2.1.2. Choosing Identifiers
2.2. vCard Value Data Types
2.2.1. BOOLEAN
2.2.2. DATE, TIME, DATE-TIME, DATE-AND-OR-TIME, and TIMESTAMP
2.2.3. INTEGER
2.2.4. FLOAT
2.2.5. LANGUAGE-TAG
2.2.6. TEXT
2.2.7. URI
2.2.8. UTC-OFFSET
2.3. vCard Parameters
2.3.1. ALTID
2.3.2. AUTHOR
2.3.3. AUTHOR-NAME
2.3.4. CALSCALE
2.3.5. CC
2.3.6. CREATED
2.3.7. DERIVED
2.3.8. GEO
2.3.9. GROUP
2.3.10. INDEX
2.3.11. LANGUAGE
2.3.12. LABEL
2.3.13. LEVEL
2.3.14. MEDIATYPE
2.3.15. PHONETIC
2.3.16. PID
2.3.17. PREF
2.3.18. PROP-ID
2.3.19. SCRIPT
2.3.20. SERVICE-TYPE
2.3.21. SORT-AS
2.3.22. TYPE
2.3.23. TZ
2.3.24. USERNAME
2.3.25. VALUE
2.4. General Properties
2.4.1. BEGIN and END
2.4.2. KIND
2.4.3. SOURCE
2.4.4. XML
2.5. Identification Properties
2.5.1. ANNIVERSARY, BDAY, BIRTHPLACE, DEATHDATE, and
DEATHPLACE
2.5.2. FN
2.5.3. GENDER
2.5.4. GRAMGENDER and PRONOUNS
2.5.5. N
2.5.6. NICKNAME
2.5.7. PHOTO
2.6. Delivery Addressing Properties
2.6.1. ADR
2.7. Communications Properties
2.7.1. EMAIL
2.7.2. IMPP
2.7.3. LANG
2.7.4. LANGUAGE
2.7.5. SOCIALPROFILE
2.7.6. TEL
2.8. Geographical Properties
2.8.1. GEO
2.8.2. TZ
2.8.3. Combining Geographical Properties
2.9. Organizational Properties
2.9.1. CONTACT-URI
2.9.2. LOGO
2.9.3. MEMBER
2.9.4. ORG
2.9.5. RELATED
2.9.6. TITLE and ROLE
2.10. Personal Information Properties
2.10.1. EXPERTISE
2.10.2. HOBBY
2.10.3. INTEREST
2.10.4. ORG-DIRECTORY
2.11. Explanatory Properties
2.11.1. CATEGORIES
2.11.2. CLIENTPIDMAP
2.11.3. CREATED
2.11.4. NOTE
2.11.5. PRODID
2.11.6. REV
2.11.7. SOUND
2.11.8. UID
2.11.9. URL
2.11.10. VERSION
2.11.11. X-ABLabel
2.12. Security Properties
2.12.1. KEY
2.13. Calendar Properties
2.13.1. CALADRURI
2.13.2. CALURI
2.13.3. FBURL
2.14. Extended Properties and Parameters
2.15. New JSContact Properties
2.15.1. vCardProps
2.15.2. vCardParams
2.15.3. vCardName
3. Converting JSContact to vCard
3.1. Conversion Rules
3.1.1. Converting Unknown Properties
3.2. New vCard Properties
3.2.1. JSPROP
3.3. New vCard Parameters
3.3.1. JSCOMPS
3.3.2. JSPTR
4. Security Considerations
5. IANA Considerations
5.1. New vCard Property
5.2. New vCard Parameter
5.3. New JSContact Properties
5.4. New JSContact Type
6. References
6.1. Normative References
6.2. Informative References
Appendix A. Reverse Rules of Converting a vCard to a JSContact
Card
Acknowledgements
Authors' Addresses
1. Introduction πΈ
1.1. Motivation π
The JSContact data model and format [RFC9553] wants to be an alternative to the super popular vCard standard [RFC6350] and the jCard format [RFC7095] π.
Apps might prefer JSContact for swapping contact card data with other systems, but they'll probably still need to talk to services and clients that only speak vCard or jCard π±. On the flip side, existing contact data providers and consumers who already use vCard or jCard might want to show their contact data in JSContact too π¦.
So this doc sets up standard rules for converting contact data between JSContact and vCard, and by extension jCard, so everyone can get along π«Άβ¨.
1.2. Notational Conventions π
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here π₯.
1.3. ABNF Notations π§©
The ABNF definitions in this doc use the notations of [RFC5234]. Any ABNF rules that aren't defined here are defined in either [RFC5234] (for things like CRLF, WSP, DQUOTE, VCHAR, ALPHA, and DIGIT) or [RFC6350] π.
2. Converting vCard to JSContact π
This section has the conversion rules from the vCard to the JSContact Card π . It follows the same structure as vCard v4 [RFC6350]. Properties and parameters from vCard extension RFCs, including the ones in "vCard Format Extension for JSContact" [RFC9554], have been added to the matching subsections π.
2.1. General Rules π
2.1.1. The Card uid Property π
The UID property (Section 6.7.6 of [RFC6350]) in vCard is optional, but the Card object's uid property (Section 2.1.9 of [RFC9553]) is mandatory π₯Ί. So implementations that convert a vCard without a UID property MUST generate a unique identifier to use as the value for the uid property. This value SHOULD stay the same when you convert the same vCard multiple times, but how you pull that off is up to each implementation π€β¨.
2.1.2. Choosing Identifiers πͺͺ
Multivalued properties in JSContact are usually represented as a JSON object, where the object keys are of the Id type (Section 1.4.1 of [RFC9553]) and the object values are the converted vCard property π§. If there's no PROP-ID parameter (see Section 2.3.18), implementations are free to pick any identifier they want as the key for those entries π. Whatever identifier generation scheme an implementation uses, it MUST generate values that are valid according to the definition of the Id type in [RFC9553] π. For example, it could be an incrementing number across all identifier keys in the Card object, or it could just be unique within one JSON object π¦.
2.2. vCard Value Data Types π
2.2.1. BOOLEAN β
The BOOLEAN type (Section 4.4 of [RFC6350]) converts to the JSContact Boolean type (Section 1.3.2 of [RFC9553]) π«.
2.2.2. DATE, TIME, DATE-TIME, DATE-AND-OR-TIME, and TIMESTAMP π
The TIMESTAMP type (Section 4.3.5 of [RFC6350]) converts to the UTCDateTime type (Section 1.4.5 of [RFC9553]), except for anniversaries. For anniversaries, it converts to the Timestamp type (Section 2.8.1 of [RFC9553]) π.
The DATE type (Section 4.3.1 of [RFC6350]) converts to a PartialDate object (Section 2.8.1 of [RFC9553]) when it's used for an anniversary, unless the DATE value only has a month or a day (but not both) π.
These temporal types don't convert to a JSContact datetime type. Instead, vCard properties or parameters that have these value types convert as defined in Section 2.15 π§:
- TIME (Section 4.3.2 of [RFC6350])
- DATE-TIME (Section 4.3.3 of [RFC6350])
- DATE-AND-OR-TIME (Section 4.3.4 of [RFC6350])
- DATE type values that only define a month or day (but not both)
2.2.3. INTEGER π’
The INTEGER type (Section 4.5 of [RFC6350]) converts to the JSContact Int and UnsignedInt types (Section 1.4.2 of [RFC9553]) π.
2.2.4. FLOAT π
The FLOAT type (Section 4.6 of [RFC6350]) converts to the JSContact Number type (Section 1.3.2 of [RFC9553]) β¨.
2.2.5. LANGUAGE-TAG π
The LANGUAGE-TAG type (Section 4.8 of [RFC6350]) converts to the JSContact String type (Section 1.3.2 of [RFC9553]). The value MUST be a language tag as defined in [RFC5646] π£οΈ.
2.2.6. TEXT π
The TEXT type (Section 4.1 of [RFC6350]) converts to the JSContact String type (Section 1.3.2 of [RFC9553]) π.
2.2.7. URI π
The URI type (Section 4.2 of [RFC6350]) converts to the JSContact String type (Section 1.3.2 of [RFC9553]). The value MUST be a URI as defined in Section 3 of [RFC3986] π.
2.2.8. UTC-OFFSET π°οΈ
The UTC-OFFSET type (Section 4.7 of [RFC6350]) either converts to a String value containing an IANA Time Zone Database entry name (see Section 2.8.2), or it doesn't convert to any JSContact type at all. For the second case, vCard properties or parameters with these values convert as defined in Section 2.15 π.
2.3. vCard Parameters ποΈ
This section has the conversion rules for vCard parameters. A rule usually only applies to specific vCard properties. To convert a vCard parameter on an arbitrary vCard property, check out Section 2.15.2 π§Έ.
2.3.1. ALTID πͺ
The ALTID parameter (Section 5.4 of [RFC6350]) doesn't convert to an IANA-registered property in JSContact. Instead, several conversion rules use this parameter to combine multiple vCard properties into a single JSContact object instance π§©. For an example of that, see Section 2.6.1. To keep the verbatim value of the ALTID parameter, set the JSContact properties defined in Section 2.15 π.
2.3.2. AUTHOR ποΈ
Okay bestie, the AUTHOR parameter (Section 4.1 of [RFC9554]) on a NOTE property turns into the Author object's uri property (Section 2.8.3 of [RFC9553]) π Then that Author object gets set as the value of the Note object's author property (Section 2.8.3 of [RFC9553]). Main character energy!
2.3.3. AUTHOR-NAME πββοΈ
The AUTHOR-NAME parameter (Section 4.2 of [RFC9554]) on a NOTE property converts to the Author object's name property (Section 2.8.3 of [RFC9553]). And yep, that Author object is set as the value of the Note object's author property too. Iconic π
2.3.4. CALSCALE π
The CALSCALE parameter (Section 5.8 of [RFC6350]) set on a BDAY, DEATHDATE, or ANNIVERSARY property converts to the PartialDate object's calendarScale property (Section 2.8.1 of [RFC9553]) ποΈ
2.3.5. CC π
The CC parameter (Section 3.1 of [RFC8605]) on an ADR property converts to the Address object's countryCode property (Section 2.5.1.1 of [RFC9553]). Country codes, but make it organized π
2.3.6. CREATED β°
The CREATED parameter (Section 4.3 of [RFC9554]) on a NOTE property converts to the Note object's created property (Section 2.8.3 of [RFC9553]). Timestamp slay π¦
2.3.7. DERIVED π
Okay so the DERIVED parameter (Section 4.4 of [RFC9554]) does not convert to JSContact at all π If the DERIVED parameter is set to "true" on a vCard property, then implementations MAY choose not to convert that property. It's a choice, not a rule, so you're free to decide π
2.3.8. GEO πΊοΈ
The GEO parameter (Section 5.10 of [RFC6350]) set on an ADR property converts to the Address object's coordinates property (Section 2.5.1.1 of [RFC9553]). Pinned, bestie π
2.3.9. GROUP π§
The GROUP parameter (Section 7.1 of [RFC7095]) does not convert to JSContact. Its whole deal is jCard, and it MUST NOT be set in a vCard. Don't be that person π ββοΈ
Okay, now the lowkey important bit: you do NOT need to keep the exact group name when you go from vCard to JSContact and back again. Any group identifiers will do, as long as the resulting vCard still groups its properties the same way the original did. The grouping is the vibe, not the label π
If you still want the exact group name on a vCard property, implementations MAY set the jCard "group" parameter in the JSContact properties vCardProps or vCardParams, as defined in Section 2.15. Here's how that looks:
item1.TEL;VALUE=uri:tel:+1-555-555-5555
"phones": {
"p1": {
"number": "tel:+1-555-555-5555",
"vCardParams" : {
"group" : "item1"
}
}
}
Figure 1: Example of How to Preserve the Group Name in vCardParams during Conversion
item2.X-FOO:bar
"vCardProps": [
["x-foo", {
"group": "item2"
}, "unknown", "bar"]
]
Figure 2: Example of How to Preserve the Group Name in vCardProps during Conversion
2.3.10. INDEX ποΈ
The INDEX parameter (Section 3.1 of [RFC6715]) set on the EXPERTISE, HOBBY, INTEREST, and ORG-DIRECTORY properties converts to the PersonalInfo (Section 2.8.4 of [RFC9553]) and Directory (Section 2.6.2 of [RFC9553]) objects' listAs property. Sorted and serving β¨
2.3.11. LANGUAGE π
The LANGUAGE parameter (Section 5.1 of [RFC6350]) converts to an entry in the Card object's localizations property (Section 2.7.1 of [RFC9553]) for that vCard property the parameter is set on. The value of the LANGUAGE parameter becomes the language tag key in the localizations property. Multilingual and unbothered π«Ά
Now, this spec does NOT give you one standard rule for converting the property values. Building the localizations value is up to the implementation, so it's a little choose-your-own-adventure π Two options to populate the localizations property are:
- One Patch per Property: For each vCard property with a LANGUAGE parameter, set the complete path in the PatchObject to the JSContact property that the vCard property converts to. The value of the patch is the converted property value. This is simple to process and adequate if the vCard only contains a few properties with the LANGUAGE parameter. Easy mode πΈ
- Bundle Patches by Parent: If a PatchObject contains multiple paths that have the same parent paths, then it might be possible to combine these patches into one patch that patches the parent property. This is possible if the property in the Card is patched in its entirety. Big brain move π§
Generally, localizations only localize properties that are present in the non-localized version of this Card. Figure 3 shows what that looks like:
FN;LANGUAGE=EN:John Doe
TITLE;ALTID=1;LANGUAGE=EN:Boss
TITLE;ALTID=1;LANGUAGE=fr:Patron
"language": "en",
"name": {
"full": "John Doe"
},
"titles": {
"t1": {
"name": "Boss"
}
},
"localizations": {
"fr": {
"titles/t1/name": "Patron"
}
}
Figure 3: LANGUAGE Conversion Example: One Dominant Language
As a special case, if one or more vCard properties of the same type do NOT have the LANGUAGE parameter set, add them to the non-localized Card. Convert any with LANGUAGE parameters to the localizations property. Figure 4 has the deets:
FN:John Doe
TITLE;ALTID=1:Boss
TITLE;ALTID=1;LANGUAGE=fr:Patron
"name": {
"full": "John Doe"
},
"titles": {
"t1": {
"name": "Boss"
}
},
"localizations": {
"fr": {
"titles/t1/name": "Patron"
}
}
Figure 4: LANGUAGE Conversion Example: Property without Language
2.3.12. LABEL π·οΈ
The LABEL parameter (Section 6.3.1 of [RFC6350]) on an ADR property converts to the Address object's full property (Section 2.5.1.1 of [RFC9553]). Full address, full send π
2.3.13. LEVEL πΆ
The LEVEL parameter (Section 3.2 of [RFC6715]) converts to the PersonalInfo object's level property (Section 2.8.4 of [RFC9553]). If this parameter is set on the EXPERTISE property, then its values convert like this:
"beginner"converts to"low";"average"converts to"medium"; and"expert"converts to"high".
In all other cases, the values convert verbatim, but lowercase MUST be used for the JSContact value. Lowercase is the only way, babe π
2.3.14. MEDIATYPE π
The MEDIATYPE parameter (Section 5.7 of [RFC6350]) converts to the Resource object's mediaType property (Section 1.4.4 of [RFC9553]). File types, served π
2.3.15. PHONETIC π£οΈ
The PHONETIC parameter (Section 4.6 of [RFC9554]) converts to the phoneticSystem property of the Name (Section 2.2.1 of [RFC9553]) and Address (Section 2.5.1 of [RFC9553]) objects, UNLESS the parameter value is "script". In that case, the phoneticSystem property is not set at all π
The value of the SCRIPT parameter converts to the phoneticScript property (see Section 2.3.19).
The related N or ADR property is defined by the vCard ALTID parameter. The conversion rules for the N (Section 2.5.5) and ADR (Section 2.6.1) properties define how the vCard components convert to JSContact.
The component values of the property the PHONETIC parameter is set on convert to the respective NameComponent or AddressComponent objects' phonetic properties.
If more than one property has the PHONETIC parameter set and they all relate to the same property, then they convert to the Card object's localizations property according to their LANGUAGE parameter values, as outlined in Section 2.3.11. Figure 5 is a whole thing:
LANGUAGE=zh-Hant
N;ALTID=1;LANGUAGE=zh-Hant:ε«;δΈε±±;ζ,ιΈδ»;;
N;ALTID=1;PHONETIC=jyut;
SCRIPT=Latn;LANGUAGE=yue:syun1;zung1saan1;man4,jat6sin1;;
"language": "zh-Hant",
"name": {
"components": [
{ "kind": "surname", "value": "ε«" },
{ "kind": "given", "value": "δΈε±±" },
{ "kind": "given2", "value": "ζ" },
{ "kind": "given2", "value": "ιΈδ»" }
]
},
"localizations": {
"yue": {
"name/phoneticSystem": "jyut",
"name/phoneticScript": "Latn",
"name/components/0/phonetic": "syun1",
"name/components/1/phonetic": "zung1saan1",
"name/components/2/phonetic": "man4",
"name/components/3/phonetic": "jat6sin1"
}
}
Figure 5: PHONETIC Conversion Example
2.3.16. PID π’
The PID parameter (Section 5.5 of [RFC6350]) converts to the vCardParams property; see Section 2.15.2. Receipts kept π§Ύ
2.3.17. PREF β
The PREF parameter (Section 5.3 of [RFC6350]) converts to the pref property of the derived JSContact object. Preferred, obviously π
2.3.18. PROP-ID πͺͺ
The PROP-ID parameter (Section 4.7 of [RFC9554]) converts to the Id-typed key of the derived JSContact object. Every property gets its own name tag π·οΈ Figure 6 shows it:
TEL;PROP-ID=PHONE-A;VALUE=uri;PREF=1;TYPE="voice,home"
:tel:+1-555-555-5555;ext=5555
TEL;PROP-ID=PHONE-B;VALUE=uri;TYPE=home
:tel:+33-01-23-45-67
"phones": {
"PHONE-A": {
"contexts": { "private": true },
"features": { "voice": true },
"number": "tel:+1-555-555-5555;ext=5555",
"pref": 1
},
"PHONE-B": {
"contexts": { "private": true },
"number": "tel:+33-01-23-45-67"
}
}
Figure 6: PROP-ID Conversion Example
2.3.19. SCRIPT βοΈ
The SCRIPT parameter (Section 4.8 of [RFC9554]) converts to the phoneticScript property of the Name (Section 2.2.1 of [RFC9553]) or Address (Section 2.5.1 of [RFC9553]) objects.
Also see Section 2.3.15. Go check it out, it's connected π
2.3.20. SERVICE-TYPE π
The SERVICE-TYPE parameter (Section 4.9 of [RFC9554]) converts to the OnlineService object's service property (Section 2.3.2 of [RFC9553]). Online service, but make it a whole service π
2.3.21. SORT-AS π€
The SORT-AS parameter (Section 5.9 of [RFC6350]) converts to the sortAs properties of the Name, Organization, and OrgUnit objects. Alphabetized, no cap π
2.3.22. TYPE π
The TYPE parameter (Section 5.6 of [RFC6350]) converts to either the contexts property or the kind property, depending on the sections defined later on. If not otherwise specified, the vCard "home" and "work" parameter values convert to the JSContact "private" and "work" contexts, respectively. Home is where the contexts are π
2.3.23. TZ π°οΈ
The TZ parameter (Section 5.11 of [RFC6350]) on an ADR property converts to the Address object's timeZone property (Section 2.5.1.1 of [RFC9553]). Also see the conversion of the TZ property in Section 2.8.2. Time zones, bestie, time zones β³
2.3.24. USERNAME π§βπ»
The USERNAME parameter (Section 4.10 of [RFC9554]) converts to the OnlineService object's user property (Section 2.3.2 of [RFC9553]). Username, who dis π
2.3.25. VALUE π
The VALUE parameter (Section 5.2 of [RFC6350]) does not convert to an IANA-registered property in JSContact. If you want to keep properties with experimental values, see Sections 2.15.1 and 2.15.2. Experimental, but make it safe π§ͺ
2.4. General Properties π·
2.4.1. BEGIN and END π¬
The BEGIN and END properties do not convert to IANA-registered properties in JSContact. Start, end, that's the whole story π¬
2.4.2. KIND π
The KIND property (Section 6.1.4 of [RFC6350]) converts to the kind property (Figure 7). Allowed values are the ones described in Section 6.1.4 of [RFC6350], extended with the values declared in [RFC6473] and [RFC6869]. Figure 7 shows it, no cap:
KIND:individual
"kind": "individual"
Figure 7: KIND Conversion Example
2.4.3. SOURCE π
The SOURCE property (Section 6.1.3 of [RFC6350]) converts to a Directory object (Section 2.6.2 of [RFC9553]) in the Card object's directories property (Figure 8). The Directory object's kind property is set to "entry", and its uri property is set to the SOURCE property value. Source of truth energy π«Ά
The PREF and MEDIATYPE parameters convert according to the rules defined in Section 2.3.
SOURCE:https://dir.example.com/addrbook/jdoe/Jean%20Dupont.vcf
"directories": {
"ENTRY-1": {
"kind": "entry",
"uri": "https://dir.example.com/addrbook/jdoe/Jean%20Dupont.vcf"
}
}
Figure 8: SOURCE Conversion Example
2.4.4. XML π«§
The XML property (Section 6.1.5 of [RFC6350]) converts to the vCardProps property; see Section 2.15.1. Extra XML, extra vibes π
2.5. Identification Properties πͺ
2.5.1. ANNIVERSARY, BDAY, BIRTHPLACE, DEATHDATE, and DEATHPLACE π
okay so these five properties all turn into Anniversary objects inside the Card object's anniversaries property (Figure 9) π
ANNIVERSARY(Section 6.2.6 of [RFC6350])BDAY(Section 6.2.5 of [RFC6350])BIRTHPLACE(Section 2.1 of [RFC6474])DEATHDATE(Section 2.3 of [RFC6474])DEATHPLACE(Section 2.2 of [RFC6474])
BDAY and BIRTHPLACE convert to an Anniversary object (Section 2.8.1 of [RFC9553]) with the date and place properties set. The kind property is set to "birth" πΌ
DEATHDATE and DEATHPLACE convert to an Anniversary object with the date and place properties set. The Anniversary object's kind property is set to "death" ποΈ
ANNIVERSARY converts to the Anniversary object's date property. The Anniversary object's kind property is set to "wedding" π
If the BIRTHPLACE or DEATHPLACE property value is of type URI using the "geo:" URI scheme, then it converts to the Address object's coordinates property. If the value type is TEXT, then it converts to the Address object's full property. Otherwise, it converts to the vCardProps property; see Section 2.15.1 β¨
The ALTID and LANGUAGE parameters of both the BIRTHPLACE and DEATHPLACE properties convert according to the rules defined in Section 2.3 π
BDAY:19531015T231000Z
BIRTHPLACE:
123 Main Street\nAny Town, CA 91921-1234\nU.S.A.
DEATHDATE:19960415
DEATHPLACE:
5 Court Street\nNew England, ND 58647\nU.S.A.
ANNIVERSARY:19860201
"anniversaries": {
"ANNIVERSARY-1" : {
"kind": "birth",
"date": {
"@type": "Timestamp",
"utc": "1953-10-15T23:10:00Z"
},
"place": {
"full":
"123 Main Street\nAny Town, CA 91921-1234\nU.S.A."
}
},
"ANNIVERSARY-2" : {
"kind": "death",
"date": {
"year": 1996,
"month": 4,
"year": 15
},
"place": {
"full": "5 Court Street\nNew England, ND 58647\nU.S.A."
}
},
"ANNIVERSARY-3" : {
"kind": "wedding",
"date": {
"year": 1986,
"month": 2,
"day": 1
}
}
}
Figure 9: ANNIVERSARY, BDAY, BIRTHPLACE, DEATHDATE, and
DEATHPLACE Conversion Example
2.5.2. FN
The FN property (Section 6.2.1 of [RFC6350]) converts to the Name object's full property (Figure 10) πΈ If the LANGUAGE parameter is set, then the FN property converts as outlined in Section 2.3.11. In the unexpected case where the vCard contains more than one FN property without the LANGUAGE parameter, convert the FN property that has the least parameters. If multiple such FN properties are present, choose any of them. All other FN properties convert to the vCardProps (Section 2.15.1) property π§
FN:John Q. Public, Esq.
"name": {
"full": "John Q. Public, Esq."
}
Figure 10: FN Conversion Example
2.5.3. GENDER
The GENDER property (Section 6.2.7 of [RFC6350]) does not convert to an IANA-registered property in JSContact. To convert this property, see Section 2.15.1. Alternatively, the Card object's speakToAs property defines how to address and refer to an individual represented by the Card, as do the newly defined vCard GRAMGENDER and PRONOUNS properties of [RFC9554] π«Ά
2.5.4. GRAMGENDER and PRONOUNS
The GRAMGENDER property (Section 3.2 of [RFC9554]) converts to the SpeakToAs object's grammaticalGender property (Figure 11) π
The PRONOUNS property (Section 3.4 of [RFC9554]) converts to the SpeakToAs object's pronouns property (Figure 11) π
GRAMGENDER:NEUTER
PRONOUNS;PREF=2:they/them
PRONOUNS;PREF=1:xe/xir
"speakToAs": {
"grammaticalGender": "neuter",
"pronouns": {
"PRONOUNS-1": {
"pronouns": "they/them",
"pref": 2
},
"PRONOUNS-2": {
"pronouns": "xe/xir",
"pref": 1
}
}
}
Figure 11: GRAMGENDER and PRONOUNS Conversion Example
2.5.5. N
The N property (Section 6.2.2 of [RFC6350]) converts to a Name object (Section 2.2.1 of [RFC9553]) in the Card object's name property. Each component in the N property structured value converts to a NameComponent in the Name object's components property. The following table shows this relation π¦
+============+===============+==============================+
| N | NameComponent | Remarks |
| component | kind | |
+============+===============+==============================+
| Family | surname | To vCard: add any "surname2" |
| name | | NameComponent to the Family |
| | | name component, after all |
| | | "surname" values. |
| | | From vCard: ignore any value |
| | | that also occurs in the |
| | | Secondary surname component. |
+------------+---------------+------------------------------+
| Given name | given | |
+------------+---------------+------------------------------+
| Additional | given2 | |
| name | | |
+------------+---------------+------------------------------+
| Honorific | title | |
| prefix | | |
+------------+---------------+------------------------------+
| Honorific | credential | To vCard: add any |
| suffix | | "generation" NameComponent |
| | | to the Honorific suffix |
| | | component. |
| | | From vCard: ignore any value |
| | | that also occurs in the |
| | | Generation component. |
+------------+---------------+------------------------------+
| Secondary | surname2 | |
| surname | | |
+------------+---------------+------------------------------+
| Generation | generation | |
+------------+---------------+------------------------------+
Table 1: N Components Conversion
If the JSCOMPS (Section 3.3.1) parameter is set, then the Name object's isOrdered property value is "true", and the defaultSeparator property and any "separator" NameComponent objects are set according to the parameter value. The order in the components property MUST adhere to the order of the JSCOMPS parameter value π
If the JSCOMPS parameter is not set, then the Name object's isOrdered property value is "false", and the defaultSeparator property MUST NOT be set. The order in the components property MUST follow the order of values in the N structured value when read from left to right π
If the SORT-AS parameter is set, then its structured value converts to the Name object's sortAs property according to Table 1. An empty or non-existent component value indicates that no sort is defined for this kind β¨
N;SORT-AS="Stevenson,John Philip":
Stevenson;John;Philip,Paul;Dr.;Jr.,M.D.,A.C.P.;;Jr.
"name": {
"components":[
{ "kind": "surname", "value": "Stevenson" },
{ "kind": "given", "value": "John" },
{ "kind": "given2", "value": "Philip" },
{ "kind": "given2", "value": "Paul" },
{ "kind": "title", "value": "Dr." },
{ "kind": "credential", "value": "M.D." },
{ "kind": "credential", "value": "A.C.P." },
{ "kind": "generation", "value": "Jr." }
],
"sortAs": {
"surname": "Stevenson",
"given": "John Philip"
}
}
Figure 12: N Conversion Example
See Section 3.3.1 for examples of using the JSCOMPS parameter for vCard-structured property values π
2.5.6. NICKNAME
The NICKNAME property (Section 6.2.3 of [RFC6350]) converts to a Nickname object (Section 2.2.2 of [RFC9553]) in the Card object's nicknames property (Figure 13). The name property is set to the NICKNAME property value π
The PREF and TYPE parameters convert according to the rules defined in Section 2.3 πΈ
NICKNAME:Johnny
"nicknames": {
"NICK-1": {
"name": "Johnny"
}
}
Figure 13: NICKNAME Conversion Example
2.5.7. PHOTO
The PHOTO property (Section 6.2.4 of [RFC6350]) converts to a Media object (Section 2.6.4 of [RFC9553]) in the Card object's media property (Figure 14). The Media object's kind property is set to "photo" and the uri property is set to the PHOTO value πΈ
The PREF and MEDIATYPE parameters convert according to the rules defined in Section 2.3 π¦
PHOTO:https://www.example.com/pub/photos/jqpublic.gif
"media": {
"PHOTO-1": {
"kind": "photo",
"uri": "https://www.example.com/pub/photos/jqpublic.gif"
}
}
Figure 14: PHOTO Conversion Example
2.6. Delivery Addressing Properties π¬
2.6.1. ADR β¨
okay so ADR is the address property π (Section 6.3.1 of [RFC6350]), and it turns into an Address object (Section 2.5.1.1 of [RFC9553]) inside the Card object's addresses property π. Each component in the ADR-structured value gets its own AddressComponent in the Address object's components property, so it's giving very organized π¦
[RFC9554] defines new components for the ADR property. Implementations SHOULD set these new components, even if all their values are the empty string π«Ά
here's the big mapping of ADR components to AddressComponent kinds πΊοΈ
+=============+==================+===============================+
| ADR | AddressComponent | Remarks |
| component | kind | |
+=============+==================+===============================+
| post office | postOfficeBox | [RFC6350] recommends that |
| box | | this component not be set, |
| | | but this is now disputable |
| | | given the new components. |
| | | Instead, set this component |
| | | and use the new ADR value |
| | | format defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
| extended | apartment | To vCard: set the values of |
| address | | the following components: |
| | | |
| | | * room |
| | | |
| | | * floor |
| | | |
| | | * apartment |
| | | |
| | | * building |
| | | |
| | | From vCard: ignore if the ADR |
| | | structured value is of the |
| | | format defined in [RFC9554]. |
| | | Otherwise, convert to |
| | | "apartment". |
+-------------+------------------+-------------------------------+
| street | name | To vCard: set the values of |
| address | | the following components: |
| | | |
| | | * number |
| | | |
| | | * name |
| | | |
| | | * block |
| | | |
| | | * direction |
| | | |
| | | * landmark |
| | | |
| | | * subdistrict |
| | | |
| | | * district |
| | | |
| | | From vCard: ignore if the ADR |
| | | structured value is of the |
| | | format defined in [RFC9554]. |
| | | Otherwise, convert to "name". |
+-------------+------------------+-------------------------------+
| locality | locality | |
+-------------+------------------+-------------------------------+
| region | region | |
+-------------+------------------+-------------------------------+
| postal code | postcode | |
+-------------+------------------+-------------------------------+
| apartment | apartment | Defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
| block | block | Defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
| building | building | Defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
| direction | direction | Defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
| district | district | Defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
| floor | floor | Defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
| landmark | landmark | Defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
| room | room | Defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
| street | number | Defined in [RFC9554]. |
| number | | |
+-------------+------------------+-------------------------------+
| subdistrict | subdistrict | Defined in [RFC9554]. |
+-------------+------------------+-------------------------------+
Table 2: ADR Components Conversion
okay now the JSCOMPS (Section 3.3.1) parameter, which is the ordering one π. If it's set, the Address object's isOrdered property is "true", and the defaultSeparator property plus any separator name components get set to match the parameter value. The order in the components property MUST adhere to the order of the JSCOMPS parameter value π―
if JSCOMPS is not set, then isOrdered is "false" and defaultSeparator MUST NOT be set π ββοΈ and the components order MUST follow the order of the ADR structured value, read left to right β‘οΈ
the LABEL parameter converts to the Address object's full property π·οΈ
the GEO parameter converts to the Address object's coordinates property π
the TZ parameter converts to the Address object's timeZone property π°οΈ
the CC parameter converts to the Address object's countryCode property π
PREF and TYPE convert by the rules in Section 2.3. the ADR-specific TYPE values from Sections 5.1 and 5.2 of [RFC9554] convert to the matching entries of the contexts property, as defined in Section 2.5.1 of [RFC9553] π
ALTID and LANGUAGE convert by the rules in Section 2.3 too. each possible language-dependent alternative becomes an entry of the PatchObject, where the key references the full property π§
ADR;TYPE=work;CC=US:
;;54321 Oak St;Reston;VA;20190;USA;;;;54321;Oak St;;;;;;
"addresses": {
"ADDR-1" : {
"contexts": { "work": true },
"components": [
{ "kind": "number", "value": "54321" },
{ "kind": "name", "value": "Oak St" },
{ "kind": "locality", "value": "Reston" },
{ "kind": "region", "value": "VA" },
{ "kind": "postcode", "value": "20190" },
{ "kind": "country", "value": "USA" }
],
"countryCode": "US"
}
}
Figure 15: ADR Conversion Example
for JSCOMPS examples on vCard-structured property values, check Section 3.3.1 πΈ
2.7. Communications Properties π¬
2.7.1. EMAIL π§
the EMAIL property (Section 6.4.2 of [RFC6350]) converts to an EmailAddress object (Section 2.3.1 of [RFC9553]) in the Card object's emails property (Figure 16). the EmailAddress object's address property is set to the EMAIL value π
PREF and TYPE convert by the rules in Section 2.3 β¨
EMAIL;TYPE=work:jqpublic@xyz.example.com
EMAIL;PREF=1:jane_doe@example.com
"emails": {
"EMAIL-1": {
"contexts": { "work": true },
"address": "jqpublic@xyz.example.com"
},
"EMAIL-2": {
"address": "jane_doe@example.com",
"pref": 1
}
}
Figure 16: EMAIL Conversion Example
2.7.2. IMPP π¬
the IMPP property (Section 6.4.3 of [RFC6350]) converts to an OnlineService object (Section 2.3.2 of [RFC9553]) in the Card object's onlineServices property (Figure 17). the vCardName property is set to "impp", and the uri property is set to the IMPP value π¦
SERVICE-TYPE, USERNAME, PREF, and TYPE convert by the rules in Section 2.3 π«Ά
IMPP;PREF=1:xmpp:alice@example.com
"onlineServices": {
"OS-1": {
"uri": "xmpp:alice@example.com",
"pref": 1,
"vCardName": "impp"
}
}
Figure 17: IMPP Conversion Example
2.7.3. LANG π
the LANG property (Section 6.4.4 of [RFC6350]) converts to a LanguagePref object (Section 2.3.4 of [RFC9553]) in the Card object's preferredLanguages property (Figure 18). the LANG property value converts to the LanguagePref object's language property value π£οΈ
PREF and TYPE convert by the rules in Section 2.3 π
LANG;TYPE=work;PREF=1:en
LANG;TYPE=work;PREF=2:fr
LANG;TYPE=home:fr
"preferredLanguages": {
"LANG-1": {
"language": "en",
"contexts": { "work": true },
"pref": 1
},
"LANG-2": {
"language": "fr",
"contexts": { "work": true },
"pref": 2
},
"LANG-3": {
"language": "fr",
"contexts": { "private": true }
}
}
Figure 18: LANG Conversion Example
2.7.4. LANGUAGE π©πͺ
the LANGUAGE property (Section 3.3 of [RFC9554]) converts to the Card object's language property (Figure 19) π
LANGUAGE:de-AT
"language": "de-AT"
Figure 19: LANGUAGE Conversion Example
2.7.5. SOCIALPROFILE π
the SOCIALPROFILE property (Section 3.5 of [RFC9554]) converts to an OnlineService object (Section 2.3.2 of [RFC9553]) in the Card object's onlineServices property (Figure 20). the vCardName property is set to "socialprofile", or it can be omitted π if the SOCIALPROFILE property value is of type URI, then the OnlineService object's uri property is set. otherwise, the user property is set π
SERVICE-TYPE, USERNAME, PREF, and TYPE convert by the rules in Section 2.3 π
SOCIALPROFILE;SERVICE-TYPE=Mastodon:https://example.com/@foo
"onlineServices": {
...
"OS-1": {
"service": "Mastodon",
"uri": "https://example.com/@foo"
}
}
Figure 20: SOCIALPROFILE Conversion Example
2.7.6. TEL π
okay so the TEL property (Section 6.4.1 of [RFC6350]) turns into a Phone object (Section 2.3.3 of [RFC9553]) living in the Card object's phones property (Figure 21) π
The TEL-specific values of the TYPE parameter convert to the features property keys, as shown in Table 3 β¨ Now bestie, watch this twist π Section 6.4.1 of [RFC6350] says the default type is "voice", BUT the default Phone features property is absent by default π So an implementation SHOULD only set the Phone object's features property if the TEL property actually has a TEL-specific TYPE parameter set. No phantom features, periodt π
+=============+===============+
| TYPE value | Phone feature |
+=============+===============+
| cell | mobile |
+-------------+---------------+
| fax | fax |
+-------------+---------------+
| main-number | main-number |
+-------------+---------------+
| pager | pager |
+-------------+---------------+
| text | text |
+-------------+---------------+
| textphone | textphone |
+-------------+---------------+
| video | video |
+-------------+---------------+
| voice | voice |
+-------------+---------------+
Table 3: TEL TYPE Conversion π
The value of the TEL property converts to the Phone object's number property π±
The PREF and TYPE parameters convert according to the rules defined in Section 2.3 π¦
TEL;VALUE=uri;PREF=1;TYPE="voice,home":tel:+1-555-555-5555;ext=5555
TEL;VALUE=uri;TYPE=home:tel:+33-01-23-45-67
"phones": {
"PHONE-1": {
"contexts": { "private": true },
"features": { "voice": true },
"number": "tel:+1-555-555-5555;ext=5555",
"pref": 1
},
"PHONE-2": {
"contexts": { "private": true },
"number": "tel:+33-01-23-45-67"
}
}
Figure 21: TEL Conversion Example πΈ
2.8. Geographical Properties π
2.8.1. GEO πΊοΈ
The GEO property (Section 6.5.2 of [RFC6350]) converts to the Address object's coordinates property (Section 2.5.1 of [RFC9553]) β¨ Also see Section 2.8.3 to figure out which Address object instance to convert to π§
2.8.2. TZ β°
The TZ property (Section 6.5.1 of [RFC6350]) converts an Address object (Section 2.5.1 of [RFC9553]) in the Card object's addresses property π
A value of type TEXT converts to the Address object's timeZone property π
A value of type UTC-OFFSET converts to the Address object's timeZone property if the offset has zero minutes and the hour offset is between -12 and +14, both inclusively. Note that:
- If the hour offset is zero, use the time zone name
"Etc/UTC". - Otherwise, construct the time zone name with
"Etc/GMT"suffixed with the string representation of the reversed sign hour offset, including the sign but excluding leading zeros and minutes. For example, the UTC offset value"-0500"converts to"Etc/GMT+5".
For such property values, also see Section 2.8.3 to determine which Address object instance to convert to π
Any other value of type UTC-OFFSET or URI does not convert to an IANA-registered property in JSContact. To convert such property, see Section 2.15.1 π ββοΈ
2.8.3. Combining Geographical Properties π§©
In vCard, the properties ADR, GEO, and TZ occur independently of each other. In JSContact, they all convert to properties of an Address object. It is implementation-specific if these vCard properties convert to separate address instances in JSContact or if some or all of them convert to the same address. That being said, implementations MUST convert the properties to the same address for the following cases:
- The GROUP parameter values of the properties match.
- The GROUP parameters are not set, but they are set on any other ADR, GEO, and TZ properties.
2.9. Organizational Properties π’
2.9.1. CONTACT-URI π§
The CONTACT-URI property (Section 2.1 of [RFC8605]) converts to a Link object (Section 2.6.3 of [RFC9553]) in the Card object's links property (Figure 22) π The Link object's kind property is set to "contact" and the uri property is set to the CONTACT-URI property value π
The PREF and TYPE parameters convert according to the rules defined in Section 2.3 π
CONTACT-URI;PREF=1:mailto:contact@example.com
"links": {
"CONTACT-1": {
"kind": "contact",
"uri": "mailto:contact@example.com",
"pref": 1
}
}
Figure 22: CONTACT-URI Conversion Example π¦
2.9.2. LOGO πΌοΈ
The LOGO property (Section 6.6.3 of [RFC6350]) converts to a Media object (Section 2.6.4 of [RFC9553]) in the Card object's media property (Figure 23) π The Media object's kind property is set to "logo" and the uri property is set to the LOGO property value π«Ά
The PREF and TYPE parameters convert according to the rules defined in Section 2.3 π
LOGO:https://www.example.com/pub/logos/abccorp.jpg
"media": {
"LOGO-1": {
"kind": "logo",
"uri": "https://www.example.com/pub/logos/abccorp.jpg"
}
}
Figure 23: LOGO Conversion Example β¨
2.9.3. MEMBER π―
The MEMBER property (Section 6.6.5 of [RFC6350]) converts to the Card object's members property (Figure 24). Each MEMBER property value is a key in the members property. The PREF parameter (Section 5.3 of [RFC6350]) does not convert to JSContact π
KIND:group
FN:The Doe family
MEMBER:urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af
MEMBER:urn:uuid:b8767877-b4a1-4c70-9acc-505d3819e519
"kind": "group",
"name": {
"full": "The Doe family"
},
"uid": "urn:uuid:ab4310aa-fa43-11e9-8f0b-362b9e155667",
"members": {
"urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af": true,
"urn:uuid:b8767877-b4a1-4c70-9acc-505d3819e519": true
}
Figure 24: Group Example π
2.9.4. ORG π¬
The ORG property (Section 6.6.4 of [RFC6350]) converts to an Organization object (Section 2.2.3 of [RFC9553]) in the Card object's organizations property (Figure 25). The Organization object's name property is set to the ORG property organizational name component. The Organization object's units property is an array of OrgUnit objects that each contain an organizational unit name component value of the ORG property value.
Implementations MAY allow representation of organizational units without the organizational name. In this case, the first component of the ORG value MUST be an empty string (e.g., ORG:;DepartmentA) π§
The ALTID and LANGUAGE parameters convert according to the rules defined in Section 2.3 π·
The first item of the comma-separated SORT-AS parameter value converts to the sortAs property of the Organization object. The subsequent items convert to the sortAs property of the corresponding OrgUnit object ποΈ
The TYPE parameter converts according to the rules defined in Section 2.3 π
ORG;SORT-AS="ABC":ABC\, Inc.;North American Division;Marketing
"organizations": {
"ORG-1": {
"name": "ABC, Inc.",
"units":[
{ "name": "North American Division" },
{ "name": "Marketing" }
],
"sortAs": "ABC"
}
}
Figure 25: ORG Conversion Example π
2.9.5. RELATED π€
The RELATED property (Section 6.6.6 of [RFC6350]) converts to the Card object's relatedTo property (Figure 26). The property value converts to the key in the relatedTo property. The TYPE parameters convert to the Relation object's relation property (Section 2.1.8 of [RFC9553]). Any other parameters convert as defined in Section 2.15.2 π«
RELATED;TYPE=friend:urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6
RELATED;TYPE=contact:https://example.com/directory/john.vcf
RELATED;VALUE=text:Please contact my deputy John for any inquiries.
"relatedTo" : {
"urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6" : {
"relation" : {
"friend" : true
}
},
"https://example.com/directory/john.vcf" : {
"relation" : {
"contact" : true
}
},
"Please contact my deputy John for any inquiries." : {
"relation" : { }
}
}
Figure 26: RELATED Conversion Example π
2.9.6. TITLE and ROLE πΌ
The TITLE (Section 6.6.1 of [RFC6350]) and ROLE (Section 6.6.2 of [RFC6350]) properties convert to a Title object (Section 2.2.5 of [RFC9553]) in the Card object's titles property (Figure 27) π©βπΌ The Title object's kind property is set to "title" or "role" for the TITLE and ROLE vCard properties, respectively. The name property is set to the vCard property value.
The value of the organizationId property can be derived if the TITLE or ROLE property is a member of a vCard property group and if exactly one other ORG property is also a part of that group π
The ALTID and LANGUAGE parameters convert according to the rules defined in Section 2.3 πΌ
TITLE:Research Scientist
group1.ROLE:Project Leader
group1.ORG:ABC, Inc.
"titles": {
"TITLE-1": {
"kind": "title",
"name": "Research Scientist"
},
"TITLE-2": {
"kind": "role",
"name": "Project Leader",
"organizationId": "ORG-1"
}
},
"organizations": {
"ORG-1": {
"name": "ABC, Inc."
}
}
Figure 27: TITLE and ROLE Conversion Example π
2.10. Personal Information Properties π§
2.10.1. EXPERTISE π
The EXPERTISE property (Section 2.1 of [RFC6715]) converts to a PersonalInfo object (Section 2.8.4 of [RFC9553]) in the Card object's personalInfo property (Figure 28). The PersonalInfo object's kind property is set to "expertise" π
The INDEX and LEVEL parameters convert according to the rules defined in Section 2.3 π
EXPERTISE;LEVEL=beginner;INDEX=2:Chinese literature
EXPERTISE;INDEX=1;LEVEL=expert:chemistry
"personalInfo": {
"PERSINFO-1" : {
"kind": "expertise",
"value": "Chinese literature",
"level": "low",
"listAs": 2
},
"PERSINFO-2" : {
"kind": "expertise",
"value": "chemistry",
"level": "high",
"listAs": 1
}
}
Figure 28: EXPERTISE Conversion Example π§
2.10.2. HOBBY π¨
The HOBBY property (Section 2.2 of [RFC6715]) converts to a PersonalInfo object (Section 2.8.4 of [RFC9553]) in the Card object's personalInfo property (Figure 29). The PersonalInfo object's kind property is set to "hobby" π§΅
The INDEX and LEVEL parameters convert according to the rules defined in Section 2.3 π
HOBBY;INDEX=1;LEVEL=high:reading
HOBBY;INDEX=2;LEVEL=high:sewing
"personalInfo": {
"PERSINFO-1" : {
"kind": "hobby",
"value": "reading",
"level": "high",
"listAs": 1
},
"PERSINFO-2" : {
"kind": "hobby",
"value": "sewing",
"level": "high",
"listAs": 2
}
}
Figure 29: HOBBY Conversion Example πΈ
2.10.3. INTEREST π
okay so the INTEREST property (Section 2.3 of [RFC6715]) turns into a PersonalInfo object (Section 2.8.4 of [RFC9553]) that lives in the Card object's personalInfo property (Figure 30) π
the PersonalInfo object's kind gets set to "interest" β¨
the INDEX and LEVEL parameters convert according to the rules defined in Section 2.3 π«Ά
INTEREST;INDEX=1;LEVEL=medium:r&b music
INTEREST;INDEX=2;LEVEL=high:rock&roll music
"personalInfo": {
"PERSINFO-1" : {
"kind": "interest",
"value": "r&b music",
"level": "medium",
"listAs": 1
},
"PERSINFO-2" : {
"kind": "interest",
"value": "rock&roll music",
"level": "high",
"listAs": 2
}
}
Figure 30: INTEREST Conversion Example
2.10.4. ORG-DIRECTORY ποΈ
the ORG-DIRECTORY property (Section 2.4 of [RFC6715]) [RFC6715] becomes a Directory object (Section 2.6.2 of [RFC9553]) in the Card object's directories property (Figure 31) πΈ the Directory object's kind is set to "directory", and the uri property is set to the ORG-DIRECTORY property value π
the INDEX, PREF, and TYPE parameters convert according to the rules defined in Section 2.3 β¨
ORG-DIRECTORY;INDEX=1:https://directory.mycompany.example.com
ORG-DIRECTORY;PREF=1:ldap://ldap.tech.example/o=Tech,ou=Engineering
"directories": {
"DIRECTORY-1": {
"kind": "directory",
"uri": "https://directory.mycompany.example.com",
"listAs": 1
},
"DIRECTORY-2": {
"kind": "directory",
"uri": "ldap://ldap.tech.example/o=Tech,ou=Engineering",
"pref": 1
}
}
Figure 31: ORG-DIRECTORY Conversion Example
2.11. Explanatory Properties π
2.11.1. CATEGORIES π·οΈ
the CATEGORIES property (Section 6.7.1 of [RFC6350]) converts to a set of entries in the Card object's keywords property (Figure 32) π the keys are the comma-separated text values of the CATEGORIES property π
in this case the PREF parameter doesn't have a JSContact counterpart, but the implementors MAY insert the entries by order of preference β¨
CATEGORIES:internet,IETF,Industry,Information Technology
"keywords": {
"internet": true,
"IETF": true,
"Industry": true,
"Information Technology": true
}
Figure 32: CATEGORIES Conversion Example
2.11.2. CLIENTPIDMAP π§©
the CLIENTPIDMAP property (Section 6.7.7 of [RFC6350]) converts to the vCardProps (Section 2.15.1) property π«§
2.11.3. CREATED π°οΈ
the CREATED property (Section 3.1 of [RFC9554]) converts to the Card object's created property (Figure 33) π·
CREATED:19940930T143510Z
"created": "1994-09-30T14:35:10Z"
Figure 33: CREATED Conversion Example
2.11.4. NOTE π
the NOTE property (Section 6.7.2 of [RFC6350]) converts to a Note object (Section 2.8.3 of [RFC9553]) in the Card object's notes property (Figure 34) π
the ALTID and LANGUAGE parameters convert according to the rules defined in Section 2.3 π«Ά
NOTE;CREATED=20221123T150132Z;AUTHOR-NAME="John":
Office hours are from 0800 to 1715 EST\, Mon-Fri.
"notes": {
"NOTE-1" : {
"note": "Office hours are from 0800 to 1715 EST, Mon-Fri.",
"created": "2022-11-23T15:01:32Z",
"author": {
"name": "John"
}
}
}
Figure 34: NOTE Conversion Example
2.11.5. PRODID π₯οΈ
the PRODID property (Section 6.7.3 of [RFC6350]) converts to the Card object's prodId property (Figure 35) π
PRODID:ACME Contacts App version 1.23.5
"prodId": "ACME Contacts App version 1.23.5"
Figure 35: PRODID Conversion Example
2.11.6. REV β°
the REV property (Section 6.7.4 of [RFC6350]) converts to the Card object's updated property (Figure 36) π¦
REV:19951031T222710Z
"updated": "1995-10-31T22:27:10Z"
Figure 36: REV Conversion Example
2.11.7. SOUND π
the SOUND property (Section 6.7.5 of [RFC6350]) converts to a Media object (Section 2.6.4 of [RFC9553]) in the Card object's media property (Figure 37) π§ the Media object's kind is set to "sound", and the uri property is set to the SOUND value πΆ
the PREF and TYPE parameters convert according to the rules defined in Section 2.3 β¨
SOUND:CID:JOHNQPUBLIC.19960229T080000.xyzMail@example.com
"media": {
...
"SOUND-1": {
"kind": "sound",
"uri": "CID:JOHNQPUBLIC.19960229T080000.xyzMail@example.com"
}
}
Figure 37: SOUND Conversion Example
2.11.8. UID π
the UID property (Section 6.7.6 of [RFC6350]) converts to the Card object's uid property (Figure 38) πͺͺ
UID:urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6
"uid": "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
Figure 38: UID Conversion Example
2.11.9. URL π
the URL property (Section 6.7.8 of [RFC6350]) converts to a Link object (Section 2.6.3 of [RFC9553]) in the Card object's links property (Figure 39) π the Link object's uri property is set to the URL value π
the PREF and TYPE parameters convert according to the rules defined in Section 2.3 π«Ά
URL:https://example.org/restaurant.french/~chezchic.html
"links": {
"LINK-1": {
"uri": "https://example.org/restaurant.french/~chezchic.html"
}
}
Figure 39: URL Conversion Example
2.11.10. VERSION π’
the VERSION property (Section 6.7.9 of [RFC6350]) converts to the vCardProps (Section 2.15.1) property π§
2.11.11. X-ABLabel π·οΈ
the X-ABLabel property is experimental, but it's widely used in existing vCard data, so it's giving real-world relevance π it converts to the label property of a JSContact object. the X-ABLabel property is preceded by a vCard property group name, and the label converts to the JSContact object that was converted from a vCard property of the same group π«§
the group name is not preserved, and implementations are free to choose any unique group name when converting back to vCard π for an example on how to preserve the group name, see Section 2.3.9 π
item1.TEL;VALUE=uri:tel:+1-555-555-5555
item1.X-ABLabel:foo
"phones": {
"p1": {
"number": "tel:+1-555-555-5555",
"label": "foo"
}
}
Figure 40: X-ABLabel Conversion Example
2.12. Security Properties π
2.12.1. KEY ποΈ
the KEY property (Section 6.8.1 of [RFC6350]) converts to a CryptoKey object (Section 2.6.1 of [RFC9553]) in the Card object's cryptoKeys property (Figure 41) π the CryptoKey object's uri property is set to the KEY property value π
the PREF and TYPE parameters convert according to the rules defined in Section 2.3 β¨
KEY:https://www.example.com/keys/jdoe.cer
"cryptoKeys": {
"KEY-1": {
"uri": "https://www.example.com/keys/jdoe.cer"
}
}
Figure 41: KEY Conversion Example
2.13. Calendar Properties π
2.13.1. CALADRURI π
the CALADRURI property (Section 6.9.2 of [RFC6350]) converts to a SchedulingAddress object (Section 2.4.2 of [RFC9553]) in the Card object's schedulingAddresses property (Figure 42) ποΈ the SchedulingAddress object's uri property is set to the CALADRURI value π
the PREF parameter (Section 5.3 of [RFC6350]) converts according to the rules defined in Section 2.3 π«Ά
CALADRURI;PREF=1:mailto:janedoe@example.com
CALADRURI:https://example.com/calendar/jdoe
"schedulingAddresses": {
"SCHEDULING-1": {
"uri": "mailto:janedoe@example.com",
"pref": 1
},
"SCHEDULING-2": {
"uri": "https://example.com/calendar/jdoe"
}
}
Figure 42: CALADRURI Conversion Example
2.13.2. CALURI ποΈ
the CALURI property (Section 6.9.3 of [RFC6350]) converts to a Calendar object (Section 2.4.1 of [RFC9553]) in the Card object's calendars property (Figure 43) πΈ the Calendar object's kind is set to "calendar", and the uri property is set to the CALURI value β¨
the PREF and TYPE parameters convert according to the rules defined in Section 2.3 π
CALURI;PREF=1:https://cal.example.com/calA
CALURI;MEDIATYPE=text/calendar:https://ftp.example.com/calA.ics
"calendars": {
"CAL-1": {
"kind": "calendar",
"uri": "https://cal.example.com/calA",
"pref": 1
},
"CAL-2": {
"kind": "calendar",
"uri": "https://ftp.example.com/calA.ics",
"mediaType": "text/calendar"
}
}
Figure 43: CALURI Conversion Example
2.13.3. FBURL π«§
the FBURL property (Section 6.9.1 of [RFC6350]) converts to a Calendar object (Section 2.4.1 of [RFC9553]) in the Card object's calendars property (Figure 44) π¦ the Calendar object's kind is set to "freeBusy", and the uri property is set to the FBURL value π
the PREF and TYPE parameters convert according to the rules defined in Section 2.3 π«Ά
FBURL;PREF=1:https://www.example.com/busy/janedoe
FBURL;MEDIATYPE=text/calendar:https://example.com/busy/project-a.ifb
"calendars": {
"FBURL-1": {
"kind": "freeBusy",
"uri": "https://www.example.com/busy/janedoe",
"pref": 1
},
"FBURL-2": {
"kind": "freeBusy",
"uri": "https://example.com/busy/project-a.ifb",
"mediaType": "text/calendar"
}
}
Figure 44: FBURL Conversion Example
2.14. Extended Properties and Parameters π¦
extended properties and parameters convert as specified in Section 2.15 π§
2.15. New JSContact Properties π§
okay so vCards may contain properties or parameters for which no IANA-registered JSContact property is defined π for example, a vCard may contain properties and parameters whose semantics or purposes the implementation doesn't know, see Section 6.10 of [RFC6350] π
this section defines JSContact properties by which such vCard properties and parameters MAY be represented in JSContact π implementations MAY choose to convert differently if they deem that more appropriate π«Ά
2.15.1. vCardProps π«§
vCardProps: JCardProp[] (optional). contains vCard properties that get set in the vCard represented by this JSContact object π
the JCardProp type denotes a jCard-encoded vCard property as defined in Section 3.3 of [RFC7095] β¨
Example: This illustrates how to convert a vCard extension property:
item1.X-FOO;X-BAR=Hello:World!
"vCardProps": [
["x-foo", {
"x-bar": "Hello",
"group": "item1"
}, "unknown", "World!"]
]
Figure 45: JSContact vCardProps Example
2.15.2. vCardParams π
vCardParams: String[String|String[]] (optional). contains vCard parameters that are set on the vCard property represented by this JSContact object π the value MUST be a JSON object containing vCard property parameters as defined in Section 3.3 of [RFC7095] π«Ά each entry represents a parameter of the vCard property that converts to the JSContact object π
Example: This illustrates how to convert a vCard extension parameter:
EMAIL;X-FOO=Bar:jane_doe@example.com
"emails": {
"email1": {
"address": "jane_doe@example.com",
"vCardParams": {
"x-foo": "Bar"
}
}
}
Figure 46: JSContact vCardParams Example
2.15.3. vCardName π
vCardName: String (optional). okay so this one holds the name of the vCard element that this JSContact object represents π Why does that matter? When multiple vCard properties all convert to the same JSContact type, this is how you keep track of which one it started as π§ The case-insensitive value MUST be valid according to the "name" ABNF defined in Section 3.3 of [RFC6350]. π
Example: Both vCard IMPP and SOCIALPROFILE convert to an OnlineService object (Section 2.3.2 of [RFC9553]) in JSContact. The vCardName property value shows that the vCard source element was IMPP, like this π
IMPP:xmpp:alice@example.com
"onlineServices": {
"os1": {
"uri": "xmpp:alice@example.com",
"vCardName": "impp"
},
}
Figure 47: JSContact vCardName Example
3. Converting JSContact to vCard π¦
3.1. Conversion Rules
So a Card object goes back to vCard by running the reverse of the vCard-to-JSContact rules π On top of the ones in Appendix A, these also apply:
- Multivalued JSContact properties turn into separate copies of their equivalent vCard property, and every
PROP-IDparameter MUST be set to the Id-typed key of the converted value (see Section 2.3.18). - The
fullproperty of the name property in JSContact is optional, but theFNproperty is mandatory in vCard. Here's how that plays out:- If the Name object's
fullproperty is set, then implementations MUST use its value for the vCardFNproperty. - If the Name object's
fullproperty is not set, then implementations SHOULD derive the full name from the Name object'scomponentsproperty values. If theisOrderedproperty is"true", then this can be done by concatenating the name component values. Otherwise, or as an alternative, an implementation can choose any other heuristic to generate the full name from its components, such as [CLDRPersonName]. Implementations MUST set theDERIVEDparameter on theFNproperty. β¨ - Otherwise, the
FNproperty MUST be set to the empty value.
- If the Name object's
- Vendor-specific and unknown properties convert to vCard as outlined in Section 3.1.1.
3.1.1. Converting Unknown Properties
JSContact objects can have properties that no IANA-registered vCard property covers π€·ββοΈ Like, a JSContact object might hold vendor-specific stuff where nobody knows what it means or what it's for π
This spec introduces the JSPROP vCard property (Section 3.2.1) and the JSPTR vCard parameter (Section 3.3.2), and that's how those JSContact properties MAY get represented in vCard π Implementations MAY choose to convert differently if they deem that more appropriate. π«Ά
3.2. New vCard Properties
3.2.1. JSPROP
Property name: JSPROP
Purpose: Represents a JSContact property in vCard.
Value type: TEXT. Also peek at "Format definition" below for the value restrictions π
Conformance: Can be specified multiple times in a vCard.
Property parameters: The JSPTR parameter MUST be set on this property. Other IANA-registered and experimental property parameters can be specified on it too.
Description: This one converts any arbitrary JSContact property to and from vCard π The vCard property value is the JSON-encoded value of that JSContact property, stored as a TEXT value. The JSON format MUST be compact, e.g., no insignificant whitespace (as defined in Section 2 of [RFC8259]) π§ The JSPTR parameter's value points at the JSContact property inside the Card.
The root of the JSON pointer is always the Card object this vCard converts to πΈ, whether or not the pointer starts with the SOLIDUS (U+002F) character. The pointer MUST NOT reference into an array.
All the JSPROP properties in one vCard team up to form a PatchObject (as defined in [RFC9553]) π§© Each JSPTR value lines up with a key in that PatchObject, and the JSPROP value is the value for that key. Going from vCard to JSContact, the PatchObject MUST only be applied after every other vCard property has already been converted. The PatchObject MUST be valid too, and an invalid PatchObject MUST NOT be applied. π«
Format definition: Here's the notation this property is defined with π
jsprop = "JSPROP" jsprop-param ":" TEXT
jsprop-param = *(
; The following are REQUIRED and MUST NOT
; occur more than once
( ";" jsptr-param ) / ; see next section
( ";" "VALUE" "=" "TEXT")
;
; The following is OPTIONAL
; and MAY occur more than once.
;
(";" other-param)
;
)
Example(s): Here's how to convert a property sitting at the top level of a Card that the implementation doesn't recognize π
"someUnknownProperty": true
JSPROP;JSPTR="someUnknownProperty":true
Figure 48: Unknown Property Example
Next up: a vendor-specific property at the top level of a Card π
Heads up, the JSPTR value has to be a quoted string, which lets the path include the COLON (U+003A) character π
"example.com:foo": {
"bar": 1234
}
JSPROP;JSPTR="example.com:foo":{"bar":1234}
Figure 49: Vendor-Specific Property Conversion Example
Last one: a vendor-specific property nested down a level, using a path relative to the Card. It's not recommended, but this property name has a SOLIDUS (U+002F) in it, so it needs escaping in the JSON pointer π
"phones": {
"phone1": {
"number": "tel:+33-01-23-45-67",
"example.com:foo/bar": "tux hux"
}
}
TEL:tel:+33-01-23-45-67
JSPROP;JSPTR="phones/phone1/example.com:foo~1bar":
"tux hux"
Figure 50: Nested Vendor-Specific Property Example with a Path Relative to Card
3.3. New vCard Parameters β¨
3.3.1. JSCOMPS π
Parameter name: JSCOMPS
Purpose: okay bestie, this parameter decides the order and separators for the pieces of a structured property value π
Description: the JSCOMPS parameter is the translator for name and address components between JSContact and vCard β¨ It keeps the order of the JSContact property's components and carries the verbatim values of the separator components π¦
If this parameter is set and its value is valid (see later), then implementations MUST set the isOrdered property of the Name or Address object to "true". Otherwise, they MUST set the isOrdered property value to "false" π«Ά
The JSCOMPS parameter value is a structured type value, and its value MUST be quoted π It's a sequence of entries separated by the SEMICOLON character (U+003B). The first entry sets the value of the defaultSeparator property. If that entry is the empty string, then no default separator is defined. Otherwise, the first entry MUST be a separator entry πΈ All the following entries, processed in order, make an ordered list of JSContact components, and each one MUST be one of these two kinds:
- A positional. This points at a component value in the vCard structured value. A position is the numeric index of a component in the structured value, optionally followed by a COMMA (U+002C) character and the non-zero index of a value within that component. The zero index selects the first component or value, respectively. The second index is zero by default, in which case it MUST be omitted (as well as the leading COMMA) π§
The resulting JSContact component gets its kind from its position in the vCard structured value, and its value is the verbatim value of the vCard component. Figures 51 and 52 show this by example β¨
- A separator. This contains the verbatim value of a separator component. It starts with the LATIN SMALL LETTER S (U+0073) character, then the COMMA (U+002C) character, then zero or more "param-value" characters (see Section 3.3 of [RFC6350]). The COMMA (U+002C) and SEMICOLON (U+003B) characters MUST be escaped according to the rules defined in Section 3.4 of [RFC6350]. Figure 53 shows this by example π
The resulting JSContact component gets its kind set to "separator", and its value is the verbatim value of the entry.
A JSCOMPS parameter value is valid if and only if:
- All indexes in the positional entries refer to an existing component value in the vCard property value.
- The count of positional entries equals the count of deduplicated component values. Deduplication is required because some values may show up in both their designated and backwards-compatible components in the vCard property value π
- A value that occurs in both the N property secondary surname component and the family name component only counts once.
- A value that occurs in both the N property generation component and the honorific suffix component only counts once.
- A value in the ADR property street address component does not count if the ADR property value contains a value in one of the new components defined in [RFC9554].
- All other values count once each.
Format definition:
jscomps-param = "JSCOMPS" "=" DQUOTE [jscomps-entry-sep ] ";"
jscomps-entrylist DQUOTE
jscomps-entrylist = jscomps-entry *(";" jscomps-entry)
jscomps-entry = jscomps-entry-pos / jscomps-entry-sep
jscomps-entry-pos = 1*DIGIT [ "," 1*DIGIT ]
jscomps-entry-sep = "s" "," jscomps-entry-verb
jscomps-entry-verb = *QSAFE-CHAR ; encode according to RFC 6868
Example(s): this one's the "Jane Doe" example, and it's giving clean positional entries π The given name comes before the surname. No secondary index is needed for either positional, because both are zero.
"name": {
"components": [
{ "kind": "given", "value": "Jane" },
{ "kind": "surname", "value": "Doe" }
],
"isOrdered": true
}
N;JSCOMPS=";1;0":Doe;Jane;;;;;;
FN;DERIVED=TRUE:Jane Doe
Figure 51: Example of a Secondary Positional Index
Now the secondary positional index, and it's so iconic π The "Jr." generation marker only counts once, because it shows up in both the designated generation component and the backwards-compatible honorific suffixes component.
"name": {
"components": [
{ "kind": "given", "value": "John" },
{ "kind": "given2", "value": "Philip" },
{ "kind": "given2", "value": "Paul" },
{ "kind": "surname", "value": "Stevenson" },
{ "kind": "generation", "value": "Jr." },
{ "kind": "credential", "value": "M.D." }
],
"isOrdered": true
}
N;JSCOMPS=";1;2;2,1;0;6;4,1":
Stevenson;John;Philip,Paul;;Jr.,M.D.;;Jr.
Figure 52: Example of Positional Entries
Last one, and it's a whole vibe π¦ This shows separator entries for the (shortened for brevity) address "54321 Oak St, Reston". The first entry sets the default separator to ", ". The second and fourth positional entries are separated with the separator value " ". For backwards compatibility, the street address component of the ADR property contains both the street number and name, but it isn't referred to in the JSCOMPS parameter, so it doesn't contribute to the count of values.
"addresses": {
"a1": {
"components": [
{ "kind": "number", "value": "54321" },
{ "kind": "separator", "value": " " },
{ "kind": "name", "value": "Oak St" },
{ "kind": "locality", "value": "Reston" }
],
"defaultSeparator": ", ",
"isOrdered": true
}
}
ADR;JSCOMPS="s,\, ;11;s, ;10;3":
;;54321 Oak St;Reston;;;;;;;Oak St;54321;;;;;;
Figure 53: Example of Separator Entries
3.3.2. JSPTR π
Parameter name: JSPTR
Purpose: this parameter gets set on a JSPROP (Section 3.2.1) property π Its value is a JSON pointer [RFC6901] that points to the JSContact property holding the value of the JSPROP property.
Description: this parameter has a single value, and that value MUST be a valid JSON pointer as defined in [RFC6901]. Note that the value MUST be quoted according to the "param-value" ABNF in [RFC6350] π
Format definition:
jsptr-param = "JSPTR" "=" param-value
; also see param-value in RFC 6350, Section 3.3
Example(s): here's a simple one, and for more examples, check out Section 3.2.1 π«Ά
JSPROP;JSPTR="example.com:foo":"bar"
4. Security Considerations π
This specification defines how to convert between the JSContact and vCard formats. The security considerations for parsing and formatting such data apply, and they're outlined in Section 4 of [RFC9553] and Section 9 of [RFC6350]. Please take these seriously, bestie, this is not the place for vibes-only security π
5. IANA Considerations πΈ
5.1. New vCard Property
IANA has added the following entry to the "vCard Properties" registry, as defined in Section 10.3.1 of [RFC6350] β¨
+===========+==========+=========================+
| Namespace | Property | Reference |
+===========+==========+=========================+
| | JSPROP | RFC 9555, Section 3.2.1 |
+-----------+----------+-------------------------+
Table 4: New vCard Property
5.2. New vCard Parameter
IANA has added the following entry to the "vCard Parameters" registry, as defined in Section 10.3.2 of [RFC6350] π¦
+===========+===========+=========================+
| Namespace | Parameter | Reference |
+===========+===========+=========================+
| | JSPTR | RFC 9555, Section 3.3.2 |
+-----------+-----------+-------------------------+
Table 5: New vCard Parameter
5.3. New JSContact Properties
IANA has added the following entries to the "JSContact Properties" registry. Note that the Since Version is 1.0, the Until Version is not set, and the Change Controller is IETF for all of these properties π
+===========+=======================+=========+========+===========+
|Property |Property Type |Property |Intended|Reference/ |
|Name | |Context |Usage |Description|
+===========+=======================+=========+========+===========+
|vCardName |String |Any |common |RFC 9555, |
| | |JSContact| |Section |
| | |object | |2.15.3 |
+-----------+-----------------------+---------+--------+-----------+
|vCardParams|String[String|String[]]|Any |common |RFC 9555, |
| | |JSContact| |Section |
| | |object | |2.15.2 |
+-----------+-----------------------+---------+--------+-----------+
|vCardProps |JCardProp[] |Card |common |RFC 9555, |
| | | | |Section |
| | | | |2.15.1 |
+-----------+-----------------------+---------+--------+-----------+
Table 6: JSContact Properties Registry
5.4. New JSContact Type
IANA has added the following entry to the "JSContact Types" registry. Note that the Since Version is 1.0, the Until Version is not set, and the Change Controller is IETF for this type π
+===========+================+==========================+
| Type Name | Intended Usage | Reference/Description |
+===========+================+==========================+
| JCardProp | common | RFC 9555, Section 2.15.1 |
+-----------+----------------+--------------------------+
Table 7: JSContact Types Registry
6. References β¨
6.1. Normative References πβ¨
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.
[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005, <https://www.rfc-editor.org/info/rfc3986>.
[RFC5234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, DOI 10.17487/RFC5234, January 2008, <https://www.rfc-editor.org/info/rfc5234>.
[RFC5646] Phillips, A., Ed. and M. Davis, Ed., "Tags for Identifying Languages", BCP 47, RFC 5646, DOI 10.17487/RFC5646, September 2009, <https://www.rfc-editor.org/info/rfc5646>.
[RFC6350] Perreault, S., "vCard Format Specification", RFC 6350, DOI 10.17487/RFC6350, August 2011, <https://www.rfc-editor.org/info/rfc6350>.
[RFC6473] Saint-Andre, P., "vCard KIND:application", RFC 6473, DOI 10.17487/RFC6473, December 2011, <https://www.rfc-editor.org/info/rfc6473>.
[RFC6474] Li, K. and B. Leiba, "vCard Format Extensions: Place of Birth, Place and Date of Death", RFC 6474, DOI 10.17487/RFC6474, December 2011, <https://www.rfc-editor.org/info/rfc6474>.
[RFC6715] Cauchie, D., Leiba, B., and K. Li, "vCard Format Extensions: Representing vCard Extensions Defined by the Open Mobile Alliance (OMA) Converged Address Book (CAB) Group", RFC 6715, DOI 10.17487/RFC6715, August 2012, <https://www.rfc-editor.org/info/rfc6715>.
[RFC6869] Salgueiro, G., Clarke, J., and P. Saint-Andre, "vCard KIND:device", RFC 6869, DOI 10.17487/RFC6869, February 2013, <https://www.rfc-editor.org/info/rfc6869>.
[RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed., "JavaScript Object Notation (JSON) Pointer", RFC 6901, DOI 10.17487/RFC6901, April 2013, <https://www.rfc-editor.org/info/rfc6901>.
[RFC7095] Kewisch, P., "jCard: The JSON Format for vCard", RFC 7095, DOI 10.17487/RFC7095, January 2014, <https://www.rfc-editor.org/info/rfc7095>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", STD 90, RFC 8259, DOI 10.17487/RFC8259, December 2017, <https://www.rfc-editor.org/info/rfc8259>.
[RFC9553] Stepanek, R. and M. Loffredo, "JSContact: A JSON Representation of Contact Data", RFC 9553, DOI 10.17487/RFC9553, May 2024, <https://www.rfc-editor.org/info/rfc9553>.
[RFC9554] Stepanek, R. and M. Loffredo, "vCard Format Extensions for JSContact", RFC 9554, DOI 10.17487/RFC9554, May 2024, <https://www.rfc-editor.org/info/rfc9554>.
6.2. Informative References πΈ
[CLDRPersonName] Davis, M., Edberg, P., Gillam, R., Kolisnychenko, A., McKenna, M., and other CLDR committee members, "Unicode Locale Data Markup Language (LDML) Part 8: Person Names", Unicode Technical Standard #35, Version 44.1, July 2023, <https://www.unicode.org/reports/tr35/tr35-personNames.html>.
[RFC8605] Hollenbeck, S. and R. Carney, "vCard Format Extensions: ICANN Extensions for the Registration Data Access Protocol (RDAP)", RFC 8605, DOI 10.17487/RFC8605, May 2019, <https://www.rfc-editor.org/info/rfc8605>.
[vOBJECT] Tse, R., Tam, P., and M. Douglass, "vObject Internationalization", Work in Progress, Internet-Draft, draft-calconnect-vobject-i18n-00, 8 June 2018, <https://datatracker.ietf.org/doc/html/draft-calconnect-vobject-i18n-00>.
Appendix A. Reverse Rules of Converting a vCard to a JSContact Card π¦
Table 8 lists the relevant document sections for each JSContact type and property. π
Okay bestie, this is the lookup table π It's basically a cheat sheet that tells you where every JSContact type and property gets explained. Find your type, find your property, and the Relevant Section(s) column tells you where to look π¦
+===================+=====================+=====================+
| JSContact Type | Property Name | Relevant Section(s) |
+===================+=====================+=====================+
| Address | @type | not applicable |
+-------------------+---------------------+---------------------+
| Address | components | Sections 2.6.1 and |
| | | 3.3.1 |
+-------------------+---------------------+---------------------+
| Address | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| Address | coordinates | Sections 2.3.8 and |
| | | 2.8.1 |
+-------------------+---------------------+---------------------+
| Address | country | Section 2.6.1 |
+-------------------+---------------------+---------------------+
| Address | countryCode | Section 2.6.1 |
+-------------------+---------------------+---------------------+
| Address | defaultSeparator | Sections 2.6.1 and |
| | | 3.3.1 |
+-------------------+---------------------+---------------------+
| Address | full | Section 2.6.1 |
+-------------------+---------------------+---------------------+
| Address | isOrdered | Sections 2.6.1 and |
| | | 3.3.1 |
+-------------------+---------------------+---------------------+
| Address | locality | Section 2.6.1 |
+-------------------+---------------------+---------------------+
| Address | phoneticScript | Sections 2.3.15 and |
| | | 2.3.19 |
+-------------------+---------------------+---------------------+
| Address | phoneticSystem | Section 2.3.15 |
+-------------------+---------------------+---------------------+
| Address | postcode | Section 2.6.1 |
+-------------------+---------------------+---------------------+
| Address | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| Address | region | Section 2.6.1 |
+-------------------+---------------------+---------------------+
| Address | timeZone | Sections 2.3.23 and |
| | | 2.8.2 |
+-------------------+---------------------+---------------------+
| AddressComponent | phonetic | Section 2.3.15 |
+-------------------+---------------------+---------------------+
| Anniversary | @type | not applicable |
+-------------------+---------------------+---------------------+
| Anniversary | date | Section 2.5.1 |
+-------------------+---------------------+---------------------+
| Anniversary | kind | Section 2.5.1 |
+-------------------+---------------------+---------------------+
| Anniversary | place | Section 2.5.1 |
+-------------------+---------------------+---------------------+
| Author | @type | not applicable |
+-------------------+---------------------+---------------------+
| Author | name | Section 2.3.3 |
+-------------------+---------------------+---------------------+
| Author | uri | Section 2.3.2 |
+-------------------+---------------------+---------------------+
| Calendar | @type | not applicable |
+-------------------+---------------------+---------------------+
| Calendar | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| Calendar | kind | Sections 2.13.2 and |
| | | 2.13.3 |
+-------------------+---------------------+---------------------+
| Calendar | label | Section 2.11.11 |
+-------------------+---------------------+---------------------+
| Calendar | mediaType | Section 2.3.14 |
+-------------------+---------------------+---------------------+
| Calendar | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| Calendar | uri | Sections 2.13.2 and |
| | | 2.13.3 |
+-------------------+---------------------+---------------------+
| Card | @type | not applicable |
+-------------------+---------------------+---------------------+
| Card | @version | not applicable |
+-------------------+---------------------+---------------------+
| Card | addresses | Section 2.6.1 |
+-------------------+---------------------+---------------------+
| Card | anniversaries | Section 2.5.1 |
+-------------------+---------------------+---------------------+
| Card | calendars | Sections 2.13.2 and |
| | | 2.13.3 |
+-------------------+---------------------+---------------------+
| Card | created | Section 2.11.3 |
+-------------------+---------------------+---------------------+
| Card | directories | Sections 2.4.3 and |
| | | 2.10.4 |
+-------------------+---------------------+---------------------+
| Card | emails | Section 2.7.1 |
+-------------------+---------------------+---------------------+
| Card | keywords | Section 2.11.1 |
+-------------------+---------------------+---------------------+
| Card | kind | Section 2.4.2 |
+-------------------+---------------------+---------------------+
| Card | language | Section 2.7.4 |
+-------------------+---------------------+---------------------+
| Card | links | Sections 2.9.1 and |
| | | 2.11.9 |
+-------------------+---------------------+---------------------+
| Card | localizations | Section 2.3.11 |
+-------------------+---------------------+---------------------+
| Card | media | Sections 2.5.7, |
| | | 2.9.2, and 2.11.7 |
+-------------------+---------------------+---------------------+
| Card | members | Section 2.9.3 |
+-------------------+---------------------+---------------------+
| Card | name | Section 2.5.5 |
+-------------------+---------------------+---------------------+
| Card | nicknames | Section 2.5.6 |
+-------------------+---------------------+---------------------+
| Card | notes | Section 2.11.4 |
+-------------------+---------------------+---------------------+
| Card | onlineServices | Section 2.7.2 |
+-------------------+---------------------+---------------------+
| Card | organizations | Section 2.9.4 |
+-------------------+---------------------+---------------------+
| Card | personalInfo | Sections 2.10.1, |
| | | 2.10.2, and 2.10.3 |
+-------------------+---------------------+---------------------+
| Card | phones | Section 2.7.6 |
+-------------------+---------------------+---------------------+
| Card | preferredLanguages | Section 2.7.3 |
+-------------------+---------------------+---------------------+
| Card | prodId | Section 2.11.5 |
+-------------------+---------------------+---------------------+
| Card | relatedTo | Section 2.9.5 |
+-------------------+---------------------+---------------------+
| Card | schedulingAddresses | Section 2.13.1 |
+-------------------+---------------------+---------------------+
| Card | speakToAs | Section 2.5.4 |
+-------------------+---------------------+---------------------+
| Card | titles | Section 2.9.6 |
+-------------------+---------------------+---------------------+
| Card | uid | Section 2.11.8 |
+-------------------+---------------------+---------------------+
| Card | updated | Section 2.11.6 |
+-------------------+---------------------+---------------------+
| CryptoKey | @type | not applicable |
+-------------------+---------------------+---------------------+
| CryptoKey | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| CryptoKey | kind | not applicable |
+-------------------+---------------------+---------------------+
| CryptoKey | label | Section 2.11.11 |
+-------------------+---------------------+---------------------+
| CryptoKey | mediaType | Section 2.3.14 |
+-------------------+---------------------+---------------------+
| CryptoKey | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| CryptoKey | uri | Section 2.12.1 |
+-------------------+---------------------+---------------------+
| Directory | @type | not applicable |
+-------------------+---------------------+---------------------+
| Directory | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| Directory | kind | Sections 2.4.3 and |
| | | 2.10.4 |
+-------------------+---------------------+---------------------+
| Directory | label | Section 2.11.11 |
+-------------------+---------------------+---------------------+
| Directory | listAs | Section 2.3.10 |
+-------------------+---------------------+---------------------+
| Directory | mediaType | Section 2.3.14 |
+-------------------+---------------------+---------------------+
| Directory | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| Directory | uri | Sections 2.4.3 and |
| | | 2.10.4 |
okay bestie, the mapping table keeps going π Each row pairs a JSContact type and property with the section that covers it. Here's the next batch π β¨
+-------------------+---------------------+---------------------+
| EmailAddress | @type | not applicable |
+-------------------+---------------------+---------------------+
| EmailAddress | address | Section 2.7.1 |
+-------------------+---------------------+---------------------+
| EmailAddress | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| EmailAddress | label | Section 2.11.11 |
+-------------------+---------------------+---------------------+
| EmailAddress | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| LanguagePref | @type | not applicable |
+-------------------+---------------------+---------------------+
| LanguagePref | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| LanguagePref | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| Link | @type | not applicable |
+-------------------+---------------------+---------------------+
| Link | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| Link | kind | Section 2.9.1 |
+-------------------+---------------------+---------------------+
| Link | label | Section 2.11.11 |
+-------------------+---------------------+---------------------+
| Link | mediaType | Section 2.3.14 |
+-------------------+---------------------+---------------------+
| Link | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| Link | uri | Sections 2.9.1 and |
| | | 2.11.9 |
+-------------------+---------------------+---------------------+
| Media | @type | not applicable |
+-------------------+---------------------+---------------------+
| Media | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| Media | kind | Sections 2.5.7, |
| | | 2.9.2, and 2.11.7 |
+-------------------+---------------------+---------------------+
| Media | label | Section 2.11.11 |
+-------------------+---------------------+---------------------+
| Media | mediaType | Section 2.3.14 |
+-------------------+---------------------+---------------------+
| Media | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| Media | uri | Sections 2.5.7, |
| | | 2.9.2, and 2.11.7 |
+-------------------+---------------------+---------------------+
| Name | @type | not applicable |
+-------------------+---------------------+---------------------+
| Name | components | Sections 2.5.5 and |
| | | 3.3.1 |
+-------------------+---------------------+---------------------+
| Name | defaultSeparator | Sections 2.5.5 and |
| | | 3.3.1 |
+-------------------+---------------------+---------------------+
| Name | full | Section 2.5.2 |
+-------------------+---------------------+---------------------+
| Name | phoneticScript | Sections 2.3.15 and |
| | | 2.3.19 |
+-------------------+---------------------+---------------------+
| Name | phoneticSystem | Section 2.3.15 |
+-------------------+---------------------+---------------------+
| Name | isOrdered | Sections 2.5.5 and |
| | | 3.3.1 |
+-------------------+---------------------+---------------------+
| Name | sortAs | Section 2.3.21 |
+-------------------+---------------------+---------------------+
| NameComponent | @type | not applicable |
+-------------------+---------------------+---------------------+
| NameComponent | kind | Section 2.5.5 |
+-------------------+---------------------+---------------------+
| NameComponent | phonetic | Section 2.3.15 |
+-------------------+---------------------+---------------------+
| NameComponent | value | Section 2.5.5 |
+-------------------+---------------------+---------------------+
| Nickname | @type | not applicable |
+-------------------+---------------------+---------------------+
| Nickname | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| Nickname | name | Section 2.5.5 |
+-------------------+---------------------+---------------------+
| Nickname | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| Note | @type | not applicable |
+-------------------+---------------------+---------------------+
| Note | author | Sections 2.3.2 and |
| | | 2.3.3 |
+-------------------+---------------------+---------------------+
| Note | created | Section 2.3.6 |
+-------------------+---------------------+---------------------+
| Note | note | Section 2.11.4 |
+-------------------+---------------------+---------------------+
| OnlineService | @type | not applicable |
+-------------------+---------------------+---------------------+
| OnlineService | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| OnlineService | label | Section 2.11.11 |
+-------------------+---------------------+---------------------+
| OnlineService | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| OnlineService | service | Section 2.3.20 |
+-------------------+---------------------+---------------------+
| OnlineService | uri | Sections 2.7.2 and |
| | | 2.7.5 |
+-------------------+---------------------+---------------------+
| OnlineService | user | Section 2.3.24 |
+-------------------+---------------------+---------------------+
| OrgUnit | @type | not applicable |
+-------------------+---------------------+---------------------+
| OrgUnit | name | Section 2.9.4 |
+-------------------+---------------------+---------------------+
| OrgUnit | sortAs | Section 2.3.21 |
+-------------------+---------------------+---------------------+
| Organization | @type | not applicable |
+-------------------+---------------------+---------------------+
| Organization | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| Organization | name | Section 2.9.4 |
+-------------------+---------------------+---------------------+
| Organization | sortAs | Section 2.3.21 |
+-------------------+---------------------+---------------------+
| Organization | units | Section 2.9.4 |
+-------------------+---------------------+---------------------+
| PartialDate | @type | not applicable |
+-------------------+---------------------+---------------------+
| PartialDate | calendarScale | Section 2.3.4 |
+-------------------+---------------------+---------------------+
| PartialDate | day | Section 2.2.2 |
+-------------------+---------------------+---------------------+
| PartialDate | month | Section 2.2.2 |
+-------------------+---------------------+---------------------+
| PartialDate | year | Section 2.2.2 |
+-------------------+---------------------+---------------------+
| PatchObject | @type | not applicable |
+-------------------+---------------------+---------------------+
| PersonalInfo | @type | not applicable |
+-------------------+---------------------+---------------------+
| PersonalInfo | kind | Sections 2.10.1, |
| | | 2.10.2, and 2.10.3 |
+-------------------+---------------------+---------------------+
| PersonalInfo | listAs | Section 2.3.10 |
+-------------------+---------------------+---------------------+
| PersonalInfo | level | Section 2.3.13 |
+-------------------+---------------------+---------------------+
| PersonalInfo | value | Sections 2.10.1, |
| | | 2.10.2, and 2.10.3 |
+-------------------+---------------------+---------------------+
| Phone | @type | not applicable |
+-------------------+---------------------+---------------------+
| Phone | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| Phone | features | Section 2.7.6 |
+-------------------+---------------------+---------------------+
| Phone | label | Section 2.11.11 |
+-------------------+---------------------+---------------------+
| Phone | number | Section 2.7.6 |
+-------------------+---------------------+---------------------+
| Phone | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| Pronouns | @type | not applicable |
+-------------------+---------------------+---------------------+
| Pronouns | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| Pronouns | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| Pronouns | pronouns | Section 2.5.4 |
+-------------------+---------------------+---------------------+
| Relation | @type | not applicable |
Okay bestie, this is the conversion table that wraps up Appendix A π It maps every JSContact type and property to where it lives in the rules above, so you can always find your way back. Table 8 is the one to screenshot πΈ
+-------------------+---------------------+---------------------+
| Relation | relation | Section 2.9.5 |
+-------------------+---------------------+---------------------+
| Resource | @type | not applicable |
+-------------------+---------------------+---------------------+
| SchedulingAddress | @type | not applicable |
+-------------------+---------------------+---------------------+
| SchedulingAddress | contexts | Section 2.3.22 |
+-------------------+---------------------+---------------------+
| SchedulingAddress | label | Section 2.11.11 |
+-------------------+---------------------+---------------------+
| SchedulingAddress | pref | Section 2.3.17 |
+-------------------+---------------------+---------------------+
| SchedulingAddress | uri | Section 2.13.1 |
+-------------------+---------------------+---------------------+
| SpeakToAs | @type | not applicable |
+-------------------+---------------------+---------------------+
| SpeakToAs | grammaticalGender | Section 2.5.4 |
+-------------------+---------------------+---------------------+
| SpeakToAs | pronouns | Section 2.5.4 |
+-------------------+---------------------+---------------------+
| AddressComponent | @type | not applicable |
+-------------------+---------------------+---------------------+
| AddressComponent | kind | Section 2.6.1 |
+-------------------+---------------------+---------------------+
| AddressComponent | value | Section 2.6.1 |
+-------------------+---------------------+---------------------+
| Timestamp | @type | not applicable |
+-------------------+---------------------+---------------------+
| Timestamp | utc | Section 2.2.2 |
+-------------------+---------------------+---------------------+
| Title | @type | not applicable |
+-------------------+---------------------+---------------------+
| Title | kind | Section 2.9.6 |
+-------------------+---------------------+---------------------+
| Title | name | Section 2.9.6 |
+-------------------+---------------------+---------------------+
| Title | organizationId | Section 2.9.6 |
+-------------------+---------------------+---------------------+
Table 8: Conversion Rules for JSContact Types and Properties
Acknowledgements π«Ά
The definition and examples of the PHONETIC (Section 2.3.15) and SCRIPT (Section 2.3.19) parameters are based on the initial draft version of [vOBJECT]. So the whole vibe of those two parameters was inspired by an early draft of [vOBJECT] πΈ Big credit where it's due! β¨
Authors' Addresses π¦
Here's where to find the authors, with their contact info exactly as published π
Mario Loffredo
IIT-CNR/Registro.it
Via Moruzzi, 1
56124 Pisa
Italy
Email: mario.loffredo@iit.cnr.it
URI: https://www.iit.cnr.it
Robert Stepanek
Fastmail
PO Box 234
Collins St. West
Melbourne VIC 8007
Australia
Email: rsto@fastmailteam.com
URI: https://www.fastmail.com
And that's the whole RFC, bestie! ππ We made it through all twelve parts. Iconic behaviour from everyone involved π§π
π¦ where this page comes from
- ietf: rfc9555 2024-05
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms