From d89578254e17624b5eda86f27ff1b08226d754c2 Mon Sep 17 00:00:00 2001 From: faraz152 <38698072+faraz152@users.noreply.github.com> Date: Wed, 22 Apr 2026 13:30:58 +0500 Subject: [PATCH 1/2] fix: sanitize custom IM type label before using as IMPP URI scheme Custom IM type labels are used as the URI scheme when building IMPP properties (e.g. `a b:username`). URI schemes only allow the character set [a-zA-Z][a-zA-Z0-9+-.]*; a label containing spaces or other special characters caused ez-vcard's Impp constructor to throw an IllegalArgumentException, which silently aborted the export and left a 0-byte file on disk. Fix: replace any character outside the valid URI-scheme set with a hyphen before constructing the Impp object. Also guard against labels that start with a non-letter (prefix "x-") or are empty ("x-custom"). Fixes #499 --- .../org/fossify/contacts/helpers/VcfExporter.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/org/fossify/contacts/helpers/VcfExporter.kt b/app/src/main/kotlin/org/fossify/contacts/helpers/VcfExporter.kt index bfea1cccd..9b8bdbd52 100644 --- a/app/src/main/kotlin/org/fossify/contacts/helpers/VcfExporter.kt +++ b/app/src/main/kotlin/org/fossify/contacts/helpers/VcfExporter.kt @@ -156,7 +156,17 @@ class VcfExporter { Im.PROTOCOL_GOOGLE_TALK -> Impp(HANGOUTS, it.value) Im.PROTOCOL_QQ -> Impp(QQ, it.value) Im.PROTOCOL_JABBER -> Impp(JABBER, it.value) - else -> Impp(it.label, it.value) + else -> { + // IMPP URIs use the label as the URI scheme, which only allows + // [a-zA-Z][a-zA-Z0-9+-.]*. Replace any character outside that + // set with a hyphen so labels containing spaces (or other symbols) + // don't throw an IllegalArgumentException and corrupt the export. + val scheme = it.label + .replace(Regex("[^a-zA-Z0-9+\\-.]"), "-") + .let { s -> if (s.firstOrNull()?.isLetter() != true) "x-$s" else s } + .ifEmpty { "x-custom" } + Impp(scheme, it.value) + } } card.addImpp(impp) From 8c14355bb0f3e2228d8693a8f330b859b4ff3510 Mon Sep 17 00:00:00 2001 From: faraz152 <38698072+faraz152@users.noreply.github.com> Date: Mon, 11 May 2026 13:02:47 +0500 Subject: [PATCH 2/2] fix: handle empty label correctly in IMPP scheme sanitization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When it.label is empty, .replace() produces an empty string, then the .let block prefixes 'x-' yielding 'x-' — which is not empty, so .ifEmpty { 'x-custom' } never fires and 'x-' is used as the URI scheme, which is invalid. Replace the chained .let + .ifEmpty with a single when expression that checks isEmpty() first, so empty labels always produce 'x-custom'. --- .../kotlin/org/fossify/contacts/helpers/VcfExporter.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/contacts/helpers/VcfExporter.kt b/app/src/main/kotlin/org/fossify/contacts/helpers/VcfExporter.kt index 9b8bdbd52..979132984 100644 --- a/app/src/main/kotlin/org/fossify/contacts/helpers/VcfExporter.kt +++ b/app/src/main/kotlin/org/fossify/contacts/helpers/VcfExporter.kt @@ -163,8 +163,13 @@ class VcfExporter { // don't throw an IllegalArgumentException and corrupt the export. val scheme = it.label .replace(Regex("[^a-zA-Z0-9+\\-.]"), "-") - .let { s -> if (s.firstOrNull()?.isLetter() != true) "x-$s" else s } - .ifEmpty { "x-custom" } + .let { s -> + when { + s.isEmpty() -> "x-custom" + s.firstOrNull()?.isLetter() != true -> "x-$s" + else -> s + } + } Impp(scheme, it.value) } }