Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 959570a7 authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Support jCard

parent 51b33ebb
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -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'
+1 −1
Original line number Diff line number Diff line
@@ -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()
+22 −9
Original line number Diff line number Diff line
@@ -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,13 +92,22 @@ 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
        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()

@@ -113,10 +120,16 @@ 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)
    }


+39 −16
Original line number Diff line number Diff line
@@ -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,17 +314,26 @@ class ContactWriter private constructor(val contact: Contact, val version: VCard
    }


    fun writeVCard(stream: OutputStream) {
        // validate vCard and log results
        val validation = vCard.validate(version)
        if (!validation.isEmpty) {
            val msgs = LinkedList<String>()
            for ((key, warnings) in validation)
                msgs += "  * " + key?.javaClass?.simpleName + " - " + warnings?.joinToString(" | ")
            Constants.log.log(Level.WARNING, "vCard validation warnings", msgs.joinToString(","))
        }
    /**
     * 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()

        val writer = VCardWriter(stream, version).apply {
                    // allow properties that are not defined in this vCard version
                    isVersionStrict = false
                }
            else
                VCardWriter(stream, version).apply {
                    isAddProdId = Contact.productID == null
                    registerCustomScribes()

@@ -333,10 +343,23 @@ class ContactWriter private constructor(val contact: Contact, val version: VCard
                    // 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) {
            val msgs = LinkedList<String>()
            for ((key, warnings) in validation)
                msgs += "  * " + key?.javaClass?.simpleName + " - " + warnings?.joinToString(" | ")
            Constants.log.log(Level.WARNING, "vCard validation warnings", msgs.joinToString(","))
        }
    }

}
 No newline at end of file
+17 −5
Original line number Diff line number Diff line
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()

}
Loading