diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt index 67c98c8b..dab9f899 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/Constants.kt @@ -29,7 +29,7 @@ const val DEFAULT_EVENT_TYPE = CommonDataKinds.Event.TYPE_BIRTHDAY // export/import const val BEGIN_VCARD = "BEGIN:VCARD" const val END_VCARD = "END:VCARD" -const val N = "N:" +const val N = "N" const val TEL = "TEL" const val BDAY = "BDAY:" const val ANNIVERSARY = "ANNIVERSARY:" diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/QuotedPrintable.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/QuotedPrintable.kt new file mode 100644 index 00000000..7d415cc9 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/QuotedPrintable.kt @@ -0,0 +1,43 @@ +package com.simplemobiletools.contacts.helpers + +import java.io.ByteArrayOutputStream + +// https://alvinalexander.com/java/jwarehouse/android/core/java/com/google/android/mms/pdu/QuotedPrintable.java.shtml +object QuotedPrintable { + private const val ESCAPE_CHAR: Byte = '='.toByte() + fun decode(value: String?): String { + val bytes = value?.toByteArray() + if (bytes == null || bytes.isEmpty()) { + return "" + } + + val buffer = ByteArrayOutputStream() + var i = 0 + while (i < bytes.size) { + val b = bytes[i].toInt() + if (b == ESCAPE_CHAR.toInt()) { + try { + if ('\r' == bytes[i + 1].toChar() && '\n' == bytes[i + 2].toChar()) { + i += 2 + continue + } + + val u = Character.digit(bytes[++i].toChar(), 16) + val l = Character.digit(bytes[++i].toChar(), 16) + if (u == -1 || l == -1) { + return "" + } + + buffer.write(((u shl 4) + l).toChar().toInt()) + } catch (e: ArrayIndexOutOfBoundsException) { + return "" + } + + } else { + buffer.write(b) + } + i++ + } + return String(buffer.toByteArray()) + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt index 6bf5d141..74cc6ad7 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfExporter.kt @@ -36,7 +36,7 @@ class VcfExporter { for (contact in contacts) { out.writeLn(BEGIN_VCARD) out.writeLn(VERSION_2_1) - out.writeLn("$N${contact.surname};${contact.firstName};${contact.middleName};;") + out.writeLn("$N:${contact.surname};${contact.firstName};${contact.middleName};;") contact.phoneNumbers.forEach { out.writeLn("$TEL;${getPhoneNumberLabel(it.type)}:${it.value}") diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt index d42f7fbd..6a5d8ee1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt @@ -82,11 +82,13 @@ class VcfImporter(val activity: SimpleActivity) { } private fun parseNames(names: String) { - val nameParts = names.split(";") - curSurname = nameParts[0] - curFirstName = nameParts[1] + val parts = names.split(":") + val isANSI = parts.first().toUpperCase().contains("QUOTED-PRINTABLE") + val nameParts = parts[1].split(";") + curSurname = if (isANSI) QuotedPrintable.decode(nameParts[0]) else nameParts[0] + curFirstName = if (isANSI) QuotedPrintable.decode(nameParts[1]) else nameParts[1] if (nameParts.size > 2) { - curMiddleName = nameParts[2] + curMiddleName = if (isANSI) QuotedPrintable.decode(nameParts[2]) else nameParts[2] } }