Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/bitfireAT/vcard4android.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRicki Hirner <hirner@bitfire.at>2021-07-29 15:36:32 +0300
committerRicki Hirner <hirner@bitfire.at>2021-07-29 15:53:00 +0300
commit6ee90a223158b6f7f2320dee28157f91f40d112e (patch)
tree8aa32d0530b3b247b469beeb96bec34c0a7619e8
parent7bd858698d597abfa24016a2a1bde54ba35bff90 (diff)
Use ez-vcard scribes for custom properties
-rw-r--r--src/main/java/at/bitfire/vcard4android/Contact.kt95
-rw-r--r--src/main/java/at/bitfire/vcard4android/LabeledProperty.kt8
-rw-r--r--src/main/java/at/bitfire/vcard4android/property/AbLabel.kt15
-rw-r--r--src/main/java/at/bitfire/vcard4android/property/AddressBookServerKind.kt19
-rw-r--r--src/main/java/at/bitfire/vcard4android/property/AddressBookServerMember.kt18
-rw-r--r--src/main/java/at/bitfire/vcard4android/property/PhoneticFirstName.kt15
-rw-r--r--src/main/java/at/bitfire/vcard4android/property/PhoneticLastName.kt15
-rw-r--r--src/main/java/at/bitfire/vcard4android/property/PhoneticMiddleName.kt15
-rw-r--r--src/test/java/at/bitfire/vcard4android/ContactTest.kt3
9 files changed, 159 insertions, 44 deletions
diff --git a/src/main/java/at/bitfire/vcard4android/Contact.kt b/src/main/java/at/bitfire/vcard4android/Contact.kt
index 60d5a2f..7ccf52c 100644
--- a/src/main/java/at/bitfire/vcard4android/Contact.kt
+++ b/src/main/java/at/bitfire/vcard4android/Contact.kt
@@ -8,10 +8,12 @@
package at.bitfire.vcard4android
+import at.bitfire.vcard4android.property.*
import ezvcard.Ezvcard
import ezvcard.VCard
import ezvcard.VCardVersion
-import ezvcard.parameter.AddressType
+import ezvcard.io.text.VCardReader
+import ezvcard.io.text.VCardWriter
import ezvcard.parameter.EmailType
import ezvcard.parameter.ImageType
import ezvcard.parameter.TelephoneType
@@ -67,6 +69,7 @@ class Contact {
var anniversary: Anniversary? = null
var birthDay: Birthday? = null
+ val customDates = LinkedList<LabeledProperty<DateOrTimeProperty>>()
var photo: ByteArray? = null
@@ -75,16 +78,21 @@ class Contact {
companion object {
+
+ /** list of all custom scribes (will be registered to readers/writers) **/
+ val customScribes = arrayOf(
+ AbLabel.Scribe,
+ AddressBookServerKind.Scribe,
+ AddressBookServerMember.Scribe,
+ PhoneticFirstName.Scribe,
+ PhoneticMiddleName.Scribe,
+ PhoneticLastName.Scribe
+ )
+
// productID (if set) will be used to generate a PRODID property.
// You may set this statically from the calling application.
var productID: String? = null
- const val PROPERTY_ADDRESSBOOKSERVER_KIND = "X-ADDRESSBOOKSERVER-KIND"
- const val PROPERTY_ADDRESSBOOKSERVER_MEMBER = "X-ADDRESSBOOKSERVER-MEMBER"
-
- const val PROPERTY_PHONETIC_FIRST_NAME = "X-PHONETIC-FIRST-NAME"
- const val PROPERTY_PHONETIC_MIDDLE_NAME = "X-PHONETIC-MIDDLE-NAME"
- const val PROPERTY_PHONETIC_LAST_NAME = "X-PHONETIC-LAST-NAME"
const val PROPERTY_SIP = "X-SIP"
// TEL x-types to store Android types
@@ -121,7 +129,12 @@ class Contact {
* @throws ezvcard.io.CannotParseException when the vCard can't be parsed
*/
fun fromReader(reader: Reader, downloader: Downloader?): List<Contact> {
- val vcards = Ezvcard.parse(reader).all()
+ // create new vCard reader and add custom scribes to tell the reader how to read custom properties
+ val vCardReader = VCardReader(reader, VCardVersion.V3_0) // CardDAV requires vCard 3 or newer
+ for (scribe in customScribes)
+ vCardReader.scribeIndex.register(scribe)
+
+ val vcards = vCardReader.readAll()
val contacts = LinkedList<Contact>()
vcards?.forEach { contacts += fromVCard(it, downloader) }
return contacts
@@ -131,7 +144,7 @@ class Contact {
val c = Contact()
// get X-ABLabels
- val labels = vCard.getExtendedProperties(LabeledProperty.PROPERTY_AB_LABEL)
+ val labels = vCard.getProperties(AbLabel::class.java)
fun findAndRemoveLabel(group: String?): String? {
if (group == null)
@@ -139,7 +152,7 @@ class Contact {
for (label in labels) {
if (label.group.equals(group, true)) {
- vCard.extendedProperties.remove(label)
+ vCard.removeProperty(label)
return label.value
}
}
@@ -153,10 +166,20 @@ class Contact {
var remove = true
when (prop) {
is Uid -> c.uid = uriToUID(prop.value)
- is Kind -> c.group = prop.isGroup
- is Member -> uriToUID(prop.uri)?.let { c.members += it }
+
+ is Kind, is AddressBookServerKind -> {
+ val kindProp = prop as Kind
+ c.group = kindProp.isGroup
+ }
+ is Member, is AddressBookServerMember -> {
+ val uriProp = prop as Member
+ uriToUID(uriProp.uri)?.let { c.members += it }
+ }
is FormattedName -> c.displayName = prop.value.trim()
+ is PhoneticFirstName -> c.phoneticGivenName = StringUtils.trimToNull(prop.value)
+ is PhoneticMiddleName -> c.phoneticMiddleName = StringUtils.trimToNull(prop.value)
+ is PhoneticLastName -> c.phoneticFamilyName = StringUtils.trimToNull(prop.value)
is StructuredName -> {
c.prefix = StringUtils.trimToNull(prop.prefixes.joinToString(" "))
c.givenName = StringUtils.trimToNull(prop.given)
@@ -217,19 +240,7 @@ class Contact {
for (prop in vCard.extendedProperties) {
var remove = true
when (prop.propertyName) {
- PROPERTY_ADDRESSBOOKSERVER_KIND ->
- if (prop.value.equals(Kind.GROUP, true))
- c.group = true
-
- PROPERTY_ADDRESSBOOKSERVER_MEMBER ->
- uriToUID(prop.value)?.let { c.members += it }
-
- PROPERTY_PHONETIC_FIRST_NAME -> c.phoneticGivenName = StringUtils.trimToNull(prop.value)
- PROPERTY_PHONETIC_MIDDLE_NAME -> c.phoneticMiddleName = StringUtils.trimToNull(prop.value)
- PROPERTY_PHONETIC_LAST_NAME -> c.phoneticFamilyName = StringUtils.trimToNull(prop.value)
-
PROPERTY_SIP -> c.impps += LabeledProperty(Impp("sip", prop.value), findAndRemoveLabel(prop.group))
-
else -> remove = false // don't remove unknown extended properties
}
@@ -253,9 +264,12 @@ class Contact {
// store all remaining properties into unknownProperties
if (vCard.properties.isNotEmpty() || vCard.extendedProperties.isNotEmpty())
try {
- c.unknownProperties = vCard.write()
+ val writer = Ezvcard.write(vCard)
+ for (scribe in customScribes) // unknwown properties may contain custom scribes like an unmatched X-ABLabel
+ writer.register(scribe)
+ c.unknownProperties = writer.go()
} catch(e: Exception) {
- Constants.log.warning("Couldn't serialize unknown properties, dropping them")
+ Constants.log.log(Level.WARNING, "Couldn't serialize unknown properties, dropping them", e)
}
return c
@@ -327,8 +341,8 @@ class Contact {
vCard.kind = Kind.group()
members.forEach { vCard.members += Member("urn:uuid:$it") }
} else { // "vCard4 as vCard3" (Apple-style)
- vCard.setExtendedProperty(PROPERTY_ADDRESSBOOKSERVER_KIND, Kind.GROUP)
- members.forEach { vCard.addExtendedProperty(PROPERTY_ADDRESSBOOKSERVER_MEMBER, "urn:uuid:$it") }
+ vCard.setProperty(AddressBookServerKind(Kind.GROUP))
+ members.forEach { vCard.addProperty(AddressBookServerMember("urn:uuid:$it")) }
}
}
@@ -373,9 +387,9 @@ class Contact {
}
// phonetic names
- phoneticGivenName?.let { vCard.addExtendedProperty(PROPERTY_PHONETIC_FIRST_NAME, it) }
- phoneticMiddleName?.let { vCard.addExtendedProperty(PROPERTY_PHONETIC_MIDDLE_NAME, it) }
- phoneticFamilyName?.let { vCard.addExtendedProperty(PROPERTY_PHONETIC_LAST_NAME, it) }
+ phoneticGivenName?.let { vCard.addProperty(PhoneticFirstName(it)) }
+ phoneticMiddleName?.let { vCard.addProperty(PhoneticMiddleName(it)) }
+ phoneticFamilyName?.let { vCard.addProperty(PhoneticLastName(it)) }
// ORG, TITLE, ROLE
organization?.let { vCard.organization = it }
@@ -384,14 +398,15 @@ class Contact {
// will be used to count "itemXX." property groups
val labelIterator = AtomicInteger()
- // TODO outside function outside; make clear that it modifies labeledProperty.property
+ // TODO move function outside; make clear that it modifies labeledProperty.property
fun addLabel(labeledProperty: LabeledProperty<VCardProperty>) {
- labeledProperty.label?.let {
+ labeledProperty.label?.let { label ->
val group = "group${labelIterator.incrementAndGet()}"
labeledProperty.property.group = group
- val label = vCard.addExtendedProperty(LabeledProperty.PROPERTY_AB_LABEL, it)
- label.group = group
+ val abLabel = AbLabel(label)
+ abLabel.group = group
+ vCard.addProperty(abLabel)
}
}
@@ -487,12 +502,18 @@ class Contact {
}
// generate VCARD
- Ezvcard .write(vCard)
+ val writer = Ezvcard
+ .write(vCard)
.version(vCardVersion)
.versionStrict(false) // allow vCard4 properties in vCard3s
.caretEncoding(true) // enable RFC 6868 support
.prodId(productID == null)
- .go(os)
+
+ // tell the writer how to write custom properties
+ for (scribe in customScribes)
+ writer.register(scribe)
+
+ return writer .go(os)
}
diff --git a/src/main/java/at/bitfire/vcard4android/LabeledProperty.kt b/src/main/java/at/bitfire/vcard4android/LabeledProperty.kt
index 4b3b52d..51b4657 100644
--- a/src/main/java/at/bitfire/vcard4android/LabeledProperty.kt
+++ b/src/main/java/at/bitfire/vcard4android/LabeledProperty.kt
@@ -13,10 +13,4 @@ import ezvcard.property.VCardProperty
data class LabeledProperty<out T: VCardProperty> @JvmOverloads constructor(
val property: T,
var label: String? = null
-) {
-
- companion object {
- const val PROPERTY_AB_LABEL = "X-ABLabel"
- }
-
-}
+) \ No newline at end of file
diff --git a/src/main/java/at/bitfire/vcard4android/property/AbLabel.kt b/src/main/java/at/bitfire/vcard4android/property/AbLabel.kt
new file mode 100644
index 0000000..94a7c6b
--- /dev/null
+++ b/src/main/java/at/bitfire/vcard4android/property/AbLabel.kt
@@ -0,0 +1,15 @@
+package at.bitfire.vcard4android.property
+
+import ezvcard.io.scribe.StringPropertyScribe
+import ezvcard.property.TextProperty
+
+class AbLabel(value: String?): TextProperty(value) {
+
+ object Scribe :
+ StringPropertyScribe<AbLabel>(AbLabel::class.java, "X-ABLabel") {
+
+ override fun _parseValue(value: String?) = AbLabel(value)
+
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/at/bitfire/vcard4android/property/AddressBookServerKind.kt b/src/main/java/at/bitfire/vcard4android/property/AddressBookServerKind.kt
new file mode 100644
index 0000000..3124a75
--- /dev/null
+++ b/src/main/java/at/bitfire/vcard4android/property/AddressBookServerKind.kt
@@ -0,0 +1,19 @@
+package at.bitfire.vcard4android.property
+
+import ezvcard.io.scribe.KindScribe
+import ezvcard.io.scribe.StringPropertyScribe
+import ezvcard.io.scribe.UriPropertyScribe
+import ezvcard.property.Kind
+import ezvcard.property.TextProperty
+import ezvcard.property.UriProperty
+
+class AddressBookServerKind(value: String?): Kind(value) {
+
+ object Scribe :
+ StringPropertyScribe<AddressBookServerKind>(AddressBookServerKind::class.java, "X-ADDRESSBOOKSERVER-KIND") {
+
+ override fun _parseValue(value: String?) = AddressBookServerKind(value)
+
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/at/bitfire/vcard4android/property/AddressBookServerMember.kt b/src/main/java/at/bitfire/vcard4android/property/AddressBookServerMember.kt
new file mode 100644
index 0000000..b55ec97
--- /dev/null
+++ b/src/main/java/at/bitfire/vcard4android/property/AddressBookServerMember.kt
@@ -0,0 +1,18 @@
+package at.bitfire.vcard4android.property
+
+import ezvcard.io.scribe.StringPropertyScribe
+import ezvcard.io.scribe.UriPropertyScribe
+import ezvcard.property.Member
+import ezvcard.property.TextProperty
+import ezvcard.property.UriProperty
+
+class AddressBookServerMember(value: String?): Member(value) {
+
+ object Scribe :
+ UriPropertyScribe<AddressBookServerMember>(AddressBookServerMember::class.java, "X-ADDRESSBOOKSERVER-MEMBER") {
+
+ override fun _parseValue(value: String?) = AddressBookServerMember(value)
+
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/at/bitfire/vcard4android/property/PhoneticFirstName.kt b/src/main/java/at/bitfire/vcard4android/property/PhoneticFirstName.kt
new file mode 100644
index 0000000..d30a153
--- /dev/null
+++ b/src/main/java/at/bitfire/vcard4android/property/PhoneticFirstName.kt
@@ -0,0 +1,15 @@
+package at.bitfire.vcard4android.property
+
+import ezvcard.io.scribe.StringPropertyScribe
+import ezvcard.property.TextProperty
+
+class PhoneticFirstName(value: String?): TextProperty(value) {
+
+ object Scribe :
+ StringPropertyScribe<PhoneticFirstName>(PhoneticFirstName::class.java, "X-PHONETIC-FIRST-NAME") {
+
+ override fun _parseValue(value: String?) = PhoneticFirstName(value)
+
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/at/bitfire/vcard4android/property/PhoneticLastName.kt b/src/main/java/at/bitfire/vcard4android/property/PhoneticLastName.kt
new file mode 100644
index 0000000..c1dc171
--- /dev/null
+++ b/src/main/java/at/bitfire/vcard4android/property/PhoneticLastName.kt
@@ -0,0 +1,15 @@
+package at.bitfire.vcard4android.property
+
+import ezvcard.io.scribe.StringPropertyScribe
+import ezvcard.property.TextProperty
+
+class PhoneticLastName(value: String?): TextProperty(value) {
+
+ object Scribe :
+ StringPropertyScribe<PhoneticLastName>(PhoneticLastName::class.java, "X-PHONETIC-LAST-NAME") {
+
+ override fun _parseValue(value: String?) = PhoneticLastName(value)
+
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/at/bitfire/vcard4android/property/PhoneticMiddleName.kt b/src/main/java/at/bitfire/vcard4android/property/PhoneticMiddleName.kt
new file mode 100644
index 0000000..fe50a82
--- /dev/null
+++ b/src/main/java/at/bitfire/vcard4android/property/PhoneticMiddleName.kt
@@ -0,0 +1,15 @@
+package at.bitfire.vcard4android.property
+
+import ezvcard.io.scribe.StringPropertyScribe
+import ezvcard.property.TextProperty
+
+class PhoneticMiddleName(value: String?): TextProperty(value) {
+
+ object Scribe :
+ StringPropertyScribe<PhoneticMiddleName>(PhoneticMiddleName::class.java, "X-PHONETIC-MIDDLE-NAME") {
+
+ override fun _parseValue(value: String?) = PhoneticMiddleName(value)
+
+ }
+
+} \ No newline at end of file
diff --git a/src/test/java/at/bitfire/vcard4android/ContactTest.kt b/src/test/java/at/bitfire/vcard4android/ContactTest.kt
index 3f9682e..75ffc35 100644
--- a/src/test/java/at/bitfire/vcard4android/ContactTest.kt
+++ b/src/test/java/at/bitfire/vcard4android/ContactTest.kt
@@ -214,6 +214,9 @@ class ContactTest {
assertEquals("Firstname", c.givenName)
assertEquals("Middlename1 Middlename2", c.middleName)
assertEquals("Lastname", c.familyName)
+ assertEquals("Förstnehm", c.phoneticGivenName)
+ assertEquals("Mittelnehm", c.phoneticMiddleName)
+ assertEquals("Laastnehm", c.phoneticFamilyName)
// phonetic names
assertEquals("Förstnehm", c.phoneticGivenName)