Validate vCard 4 MEMBER and PID semantics

This commit is contained in:
2026-03-28 21:41:55 -05:00
parent ac25a4ec06
commit addb2a2d8d
2 changed files with 45 additions and 1 deletions

View File

@@ -1186,6 +1186,49 @@ func validate*(vc4: VCard4): void =
of vpcAny: of vpcAny:
discard discard
if vc4.member.len > 0:
if vc4.kind.isNone or vc4.kind.get.value.toLowerAscii != "group":
raise newException(ValueError,
"MEMBER properties require the KIND property to be set to 'group'")
var clientPidMaps = initTable[int, string]()
for clientPidMap in vc4.clientpidmap:
if clientPidMap.id <= 0:
raise newException(ValueError,
"CLIENTPIDMAP identifiers must be positive integers")
if clientPidMaps.contains(clientPidMap.id):
raise newException(ValueError,
"CLIENTPIDMAP identifier $# appears more than once" % [$clientPidMap.id])
clientPidMaps[clientPidMap.id] = clientPidMap.uri
var referencedSourceIds = initHashSet[int]()
for prop in vc4.content:
var pidParam = none[VC_Param]()
for param in prop.params:
if param.name == "PID":
pidParam = some(param)
break
if pidParam.isNone:
continue
let pidValues =
try:
parsePidValues(pidParam.get)
except VCardParsingError as exc:
raise newException(ValueError, exc.msg)
for pidValue in pidValues:
if pidValue.propertyId <= 0 or pidValue.sourceId <= 0:
raise newException(ValueError,
"PID identifiers must be positive integers")
referencedSourceIds.incl(pidValue.sourceId)
for sourceId in referencedSourceIds:
if not clientPidMaps.contains(sourceId):
raise newException(ValueError,
"PID source identifier $# is missing a matching CLIENTPIDMAP" %
[$sourceId])
# Setters # Setters
# ============================================================================= # =============================================================================

View File

@@ -141,7 +141,8 @@ suite "vcard/vcard4":
let parsed = parseSingleVCard4(vcard4Doc( let parsed = parseSingleVCard4(vcard4Doc(
"VERSION:4.0", "VERSION:4.0",
"FN:John Smith", "FN:John Smith",
"EMAIL;PID=1.7:test@example.com")) "EMAIL;PID=1.7:test@example.com",
"CLIENTPIDMAP:7;urn:uuid:device-7"))
check: check:
parsed.email.len == 1 parsed.email.len == 1
parsed.email[0].pid == @[PidValue(propertyId: 1, sourceId: 7)] parsed.email[0].pid == @[PidValue(propertyId: 1, sourceId: 7)]