Skip to content

Commit

Permalink
Don't use empty N for vCard3 groups (otherwise they appear with name …
Browse files Browse the repository at this point in the history
…";;;;;" in Apple)
  • Loading branch information
rfc2822 committed Dec 20, 2022
1 parent b25c874 commit a6e9dc4
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 16 deletions.
16 changes: 11 additions & 5 deletions src/main/java/at/bitfire/vcard4android/ContactWriter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package at.bitfire.vcard4android

import at.bitfire.vcard4android.Utils.isEmpty
import at.bitfire.vcard4android.property.*
import at.bitfire.vcard4android.property.CustomScribes.registerCustomScribes
import ezvcard.Ezvcard
Expand Down Expand Up @@ -51,7 +52,6 @@ class ContactWriter private constructor(val contact: Contact, val version: VCard
Contact.productID?.let { vCard.setProductId(it) }

addKindAndMembers()

addFormattedName()
addStructuredName()
addPhoneticName()
Expand Down Expand Up @@ -227,11 +227,16 @@ class ContactWriter private constructor(val contact: Contact, val version: VCard

if (version == VCardVersion.V4_0) {
// add N only if there's some data in it
if (n.prefixes.isNotEmpty() || n.given != null || n.additionalNames.isNotEmpty() || n.family != null || n.suffixes.isNotEmpty())
if (!n.isEmpty())
vCard.structuredName = n

} else /* version == VCardVersion.V3_0 */ {
} else if (version == VCardVersion.V3_0) {
// vCard 3 REQUIRES N [RFC 2426 p. 29]

// don't use empty N for vCard3 groups (otherwise they appear with name ";;;;;" in Apple)
if (contact.group && n.isEmpty())
n.family = contact.displayName

vCard.structuredName = n
}
}
Expand Down Expand Up @@ -337,8 +342,9 @@ class ContactWriter private constructor(val contact: Contact, val version: VCard
isAddProdId = Contact.productID == null
registerCustomScribes()

// include trailing semicolons for maximum compatibility
isIncludeTrailingSemicolons = true
/* include trailing semicolons for maximum compatibility
Don't include trailing semicolons for groups because Apple then shows "N:Group;;;;" as "Group;;;;". */
isIncludeTrailingSemicolons = !contact.group

// use caret encoding for parameter values (RFC 6868)
isCaretEncodingEnabled = true
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/at/bitfire/vcard4android/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.database.Cursor
import android.database.DatabaseUtils
import android.net.Uri
import android.provider.ContactsContract
import ezvcard.property.StructuredName

object Utils {

Expand All @@ -19,6 +20,9 @@ object Utils {
return values
}

fun StructuredName.isEmpty() =
prefixes.isEmpty() && given == null && additionalNames.isEmpty() && family == null && suffixes.isEmpty()

fun Uri.asSyncAdapter(account: Account): Uri = buildUpon()
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type)
Expand Down
30 changes: 19 additions & 11 deletions src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -186,32 +186,40 @@ class ContactWriterTest {


@Test
fun testImpp() {
val vCard = generate {
impps.add(LabeledProperty(Impp.xmpp("test@example.com")))
}
assertEquals(URI("xmpp:test@example.com"), vCard.impps.first().uri)
}


@Test
fun testKindAndMember_vCard3() {
fun testGroup_vCard3() {
val vCard = generate(VCardVersion.V3_0) {
group = true
members += "member1"
displayName = "Sample vCard3 Group"
}
assertEquals(Kind.GROUP, vCard.getProperty(XAddressBookServerKind::class.java).value)
assertEquals("urn:uuid:member1", vCard.getProperty(XAddressBookServerMember::class.java).value)
assertEquals("Sample vCard3 Group", vCard.formattedName.value)
assertEquals(StructuredName().apply {
family = "Sample vCard3 Group"
}, vCard.structuredName)
}

@Test
fun testKindAndMember_vCard4() {
fun testGroup_vCard4() {
val vCard = generate(VCardVersion.V4_0) {
group = true
members += "member1"
displayName = "Sample vCard4 Group"
}
assertEquals(Kind.GROUP, vCard.getProperty(Kind::class.java).value)
assertEquals("urn:uuid:member1", vCard.members.first().value)
assertEquals("Sample vCard4 Group", vCard.formattedName.value)
assertNull(vCard.structuredName)
}


@Test
fun testImpp() {
val vCard = generate {
impps.add(LabeledProperty(Impp.xmpp("test@example.com")))
}
assertEquals(URI("xmpp:test@example.com"), vCard.impps.first().uri)
}


Expand Down

0 comments on commit a6e9dc4

Please sign in to comment.