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-10-21 09:13:57 +0300
committerRicki Hirner <hirner@bitfire.at>2021-10-21 09:23:52 +0300
commit959570a724766327f0ab56427d6b92cd7f334b1d (patch)
treecb4e621f05efba54c07314796cf2add214685237
parent51b33ebb26e4e7df8b94d0b1c010e39aad9dee43 (diff)
Support jCard
-rw-r--r--build.gradle2
-rw-r--r--src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt2
-rw-r--r--src/main/java/at/bitfire/vcard4android/Contact.kt31
-rw-r--r--src/main/java/at/bitfire/vcard4android/ContactWriter.kt55
-rw-r--r--src/main/java/at/bitfire/vcard4android/property/CustomScribes.kt22
-rw-r--r--src/test/java/at/bitfire/vcard4android/ContactTest.kt4
-rw-r--r--src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt17
7 files changed, 96 insertions, 37 deletions
diff --git a/build.gradle b/build.gradle
index b94553f..f53aace 100644
--- a/build.gradle
+++ b/build.gradle
@@ -87,8 +87,6 @@ dependencies {
// hCard functionality not needed
exclude group: 'org.jsoup'
exclude group: 'org.freemarker'
- // jCard functionality not needed
- exclude group: 'com.fasterxml.jackson.core'
}
androidTestImplementation 'androidx.test:runner:1.4.0'
diff --git a/src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt b/src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt
index 63df5b1..61b173e 100644
--- a/src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt
+++ b/src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt
@@ -110,7 +110,7 @@ class AndroidContactTest {
"TEL;CELL=;PREF=:+12345\r\n" +
"EMAIL;PREF=invalid:test@example.com\r\n" +
"END:VCARD\r\n"
- val contacts = Contact.fromReader(StringReader(vCard), null)
+ val contacts = Contact.fromReader(StringReader(vCard), false, null)
val dbContact = AndroidContact(addressBook, contacts.first(), null, null)
dbContact.add()
diff --git a/src/main/java/at/bitfire/vcard4android/Contact.kt b/src/main/java/at/bitfire/vcard4android/Contact.kt
index 98618f8..cd48a6a 100644
--- a/src/main/java/at/bitfire/vcard4android/Contact.kt
+++ b/src/main/java/at/bitfire/vcard4android/Contact.kt
@@ -11,6 +11,7 @@ package at.bitfire.vcard4android
import at.bitfire.vcard4android.property.CustomScribes.registerCustomScribes
import at.bitfire.vcard4android.property.XAbDate
import ezvcard.VCardVersion
+import ezvcard.io.json.JCardReader
import ezvcard.io.text.VCardReader
import ezvcard.property.*
import org.apache.commons.lang3.builder.HashCodeBuilder
@@ -19,7 +20,6 @@ import java.io.IOException
import java.io.OutputStream
import java.io.Reader
import java.util.*
-import kotlin.collections.HashSet
/**
* Data class for a contact; between vCards and the Android contacts provider.
@@ -84,8 +84,6 @@ class Contact {
// You may set this statically from the calling application.
var productID: String? = null
- const val LABEL_GROUP_PREFIX = "item"
-
const val DATE_PARAMETER_OMIT_YEAR = "X-APPLE-OMIT-YEAR"
const val DATE_PARAMETER_OMIT_YEAR_DEFAULT = 1604
@@ -94,15 +92,24 @@ class Contact {
*
* @param reader reader for the input stream containing the vCard (pay attention to the charset)
* @param downloader will be used to download external resources like contact photos (may be null)
+ * @param jCard *true*: content is jCard; *false*: content is vCard
+ *
* @return list of filled Event data objects (may have size 0) – doesn't return null
+ *
* @throws IOException on I/O errors when reading the stream
* @throws ezvcard.io.CannotParseException when the vCard can't be parsed
*/
- fun fromReader(reader: Reader, downloader: Downloader?): List<Contact> {
- // create new vCard reader and add custom scribes
- val vCards = VCardReader(reader, VCardVersion.V3_0) // CardDAV requires vCard 3 or newer
- .registerCustomScribes()
- .readAll()
+ fun fromReader(reader: Reader, jCard: Boolean, downloader: Downloader?): List<Contact> {
+ // create new reader and add custom scribes
+ val vCards =
+ if (jCard)
+ JCardReader(reader)
+ .registerCustomScribes()
+ .readAll()
+ else
+ VCardReader(reader, VCardVersion.V3_0) // CardDAV requires vCard 3 or newer
+ .registerCustomScribes()
+ .readAll()
return vCards.map { vCard ->
// convert every vCard to a Contact data object
@@ -114,9 +121,15 @@ class Contact {
@Throws(IOException::class)
+ fun writeJCard(os: OutputStream) {
+ val generator = ContactWriter.fromContact(this, VCardVersion.V4_0)
+ generator.writeCard(os, true)
+ }
+
+ @Throws(IOException::class)
fun writeVCard(vCardVersion: VCardVersion, os: OutputStream) {
val generator = ContactWriter.fromContact(this, vCardVersion)
- generator.writeVCard(os)
+ generator.writeCard(os, false)
}
diff --git a/src/main/java/at/bitfire/vcard4android/ContactWriter.kt b/src/main/java/at/bitfire/vcard4android/ContactWriter.kt
index c12a7e3..aa967e6 100644
--- a/src/main/java/at/bitfire/vcard4android/ContactWriter.kt
+++ b/src/main/java/at/bitfire/vcard4android/ContactWriter.kt
@@ -5,6 +5,7 @@ import at.bitfire.vcard4android.property.CustomScribes.registerCustomScribes
import ezvcard.Ezvcard
import ezvcard.VCard
import ezvcard.VCardVersion
+import ezvcard.io.json.JCardWriter
import ezvcard.io.text.VCardWriter
import ezvcard.parameter.ImageType
import ezvcard.parameter.RelatedType
@@ -313,7 +314,44 @@ class ContactWriter private constructor(val contact: Contact, val version: VCard
}
- fun writeVCard(stream: OutputStream) {
+ /**
+ * Validates and writes the vCard to an output stream.
+ *
+ * @param stream target output stream
+ * @param jCard *true*: write as jCard; *false*: write as vCard
+ */
+ fun writeCard(stream: OutputStream, jCard: Boolean) {
+ validate()
+
+ val writer =
+ if (jCard)
+ JCardWriter(stream).apply {
+ isAddProdId = Contact.productID == null
+ registerCustomScribes()
+
+ // allow properties that are not defined in this vCard version
+ isVersionStrict = false
+ }
+ else
+ VCardWriter(stream, version).apply {
+ isAddProdId = Contact.productID == null
+ registerCustomScribes()
+
+ // include trailing semicolons for maximum compatibility
+ isIncludeTrailingSemicolons = true
+
+ // use caret encoding for parameter values (RFC 6868)
+ isCaretEncodingEnabled = true
+
+ // allow properties that are not defined in this vCard version
+ isVersionStrict = false
+ }
+
+ writer.write(vCard)
+ writer.flush()
+ }
+
+ private fun validate() {
// validate vCard and log results
val validation = vCard.validate(version)
if (!validation.isEmpty) {
@@ -322,21 +360,6 @@ class ContactWriter private constructor(val contact: Contact, val version: VCard
msgs += " * " + key?.javaClass?.simpleName + " - " + warnings?.joinToString(" | ")
Constants.log.log(Level.WARNING, "vCard validation warnings", msgs.joinToString(","))
}
-
- val writer = VCardWriter(stream, version).apply {
- isAddProdId = Contact.productID == null
- registerCustomScribes()
-
- // include trailing semicolons for maximum compatibility
- isIncludeTrailingSemicolons = true
-
- // use caret encoding for parameter values (RFC 6868)
- isCaretEncodingEnabled = true
-
- isVersionStrict = false
- }
- writer.write(vCard)
- writer.flush()
}
} \ No newline at end of file
diff --git a/src/main/java/at/bitfire/vcard4android/property/CustomScribes.kt b/src/main/java/at/bitfire/vcard4android/property/CustomScribes.kt
index 640e657..0fda8a6 100644
--- a/src/main/java/at/bitfire/vcard4android/property/CustomScribes.kt
+++ b/src/main/java/at/bitfire/vcard4android/property/CustomScribes.kt
@@ -1,6 +1,8 @@
package at.bitfire.vcard4android.property
import ezvcard.io.chain.ChainingTextWriter
+import ezvcard.io.json.JCardReader
+import ezvcard.io.json.JCardWriter
import ezvcard.io.scribe.ScribeIndex
import ezvcard.io.text.VCardReader
import ezvcard.io.text.VCardWriter
@@ -27,15 +29,25 @@ object CustomScribes {
return this
}
- fun VCardReader.registerCustomScribes(): VCardReader {
+ fun ScribeIndex.registerCustomScribes() {
for (scribe in customScribes)
- scribeIndex.register(scribe)
+ register(scribe)
+ }
+
+ fun JCardReader.registerCustomScribes(): JCardReader {
+ scribeIndex.registerCustomScribes()
return this
}
- fun VCardWriter.registerCustomScribes() {
- for (scribe in customScribes)
- scribeIndex.register(scribe)
+ fun JCardWriter.registerCustomScribes() =
+ scribeIndex.registerCustomScribes()
+
+ fun VCardReader.registerCustomScribes(): VCardReader {
+ scribeIndex.registerCustomScribes()
+ return this
}
+ fun VCardWriter.registerCustomScribes() =
+ scribeIndex.registerCustomScribes()
+
}
diff --git a/src/test/java/at/bitfire/vcard4android/ContactTest.kt b/src/test/java/at/bitfire/vcard4android/ContactTest.kt
index 786ad30..0218808 100644
--- a/src/test/java/at/bitfire/vcard4android/ContactTest.kt
+++ b/src/test/java/at/bitfire/vcard4android/ContactTest.kt
@@ -28,13 +28,13 @@ class ContactTest {
private fun parseContact(fname: String, charset: Charset = Charsets.UTF_8) =
javaClass.classLoader!!.getResourceAsStream(fname).use { stream ->
- Contact.fromReader(InputStreamReader(stream, charset), null).first()
+ Contact.fromReader(InputStreamReader(stream, charset), false, null).first()
}
private fun regenerate(c: Contact, vCardVersion: VCardVersion): Contact {
val os = ByteArrayOutputStream()
c.writeVCard(vCardVersion, os)
- return Contact.fromReader(InputStreamReader(ByteArrayInputStream(os.toByteArray()), Charsets.UTF_8), null).first()
+ return Contact.fromReader(InputStreamReader(ByteArrayInputStream(os.toByteArray()), Charsets.UTF_8), false,null).first()
}
private fun toString(c: Contact, groupMethod: GroupMethod, vCardVersion: VCardVersion): String {
diff --git a/src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt b/src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt
index 0b0a19e..c242eb2 100644
--- a/src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt
+++ b/src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt
@@ -538,6 +538,19 @@ class ContactWriterTest {
@Test
+ fun testWriteJCard() {
+ val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0)
+ generator.vCard.revision = Revision(Calendar.getInstance(TimeZone.getTimeZone(ZoneOffset.UTC.id)).apply {
+ set(2021, 6, 30, 1, 2, 3)
+ })
+
+ val stream = ByteArrayOutputStream()
+ generator.writeCard(stream, true)
+ assertEquals("[\"vcard\",[[\"version\",{},\"text\",\"4.0\"],[\"prodid\",{},\"text\",\"ez-vcard 0.11.3\"],[\"rev\",{},\"timestamp\",\"2021-07-30T01:02:03Z\"]]]", stream.toString())
+ }
+
+
+ @Test
fun testWriteVCard() {
val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0)
generator.vCard.revision = Revision(Calendar.getInstance(TimeZone.getTimeZone(ZoneOffset.UTC.id)).apply {
@@ -545,7 +558,7 @@ class ContactWriterTest {
})
val stream = ByteArrayOutputStream()
- generator.writeVCard(stream)
+ generator.writeCard(stream, false)
assertEquals("BEGIN:VCARD\r\n" +
"VERSION:4.0\r\n" +
"PRODID:ez-vcard 0.11.3\r\n" +
@@ -565,7 +578,7 @@ class ContactWriterTest {
}
ContactWriter
.fromContact(contact, VCardVersion.V4_0)
- .writeVCard(stream)
+ .writeCard(stream, false)
assertTrue(stream.toString().contains("ADR;LABEL=\"Li^^ne 1,1 - ^' -\":;;Line1;;;;Line2"))
}