From 9dc225d3e45a355854e5d7a8944b2bf86049d433 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Mon, 10 Nov 2025 00:13:53 +0100 Subject: [PATCH] Export/VCard: Add Escape method --- Elwig/Helpers/Export/VCard.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Elwig/Helpers/Export/VCard.cs b/Elwig/Helpers/Export/VCard.cs index 03c2e70..cb84024 100644 --- a/Elwig/Helpers/Export/VCard.cs +++ b/Elwig/Helpers/Export/VCard.cs @@ -34,20 +34,20 @@ namespace Elwig.Helpers.Export { int count = data.Count() + 1, i = 0; foreach (var row in data) { - var billingAddr = row.BillingAddress != null ? $"ADR;TYPE=work;LANGUAGE=de;LABEL=\"{row.BillingAddress.FullName}\\n{row.BillingAddress.Address}\\n{row.BillingAddress.PostalDest.AtPlz?.Plz} {row.BillingAddress.PostalDest.AtPlz?.Ort.Name}\\nÖsterreich\":;;{row.BillingAddress.Address};{row.BillingAddress.PostalDest.AtPlz?.Ort.Name};;{row.BillingAddress.PostalDest.AtPlz?.Plz};Österreich\r\n" : null; + var billingAddr = row.BillingAddress != null ? $"ADR;TYPE=work;LANGUAGE=de;LABEL=\"{Escape(row.BillingAddress.FullName)}\\n{Escape(row.BillingAddress.Address)}\\n{row.BillingAddress.PostalDest.AtPlz?.Plz} {Escape(row.BillingAddress.PostalDest.AtPlz?.Ort.Name)}\\nÖsterreich\":;;{Escape(row.BillingAddress.Address)};{Escape(row.BillingAddress.PostalDest.AtPlz?.Ort.Name)};;{row.BillingAddress.PostalDest.AtPlz?.Plz};Österreich\r\n" : null; var tel = string.Join("", row.TelephoneNumbers .Where(n => n.Type != "fax") - .Select(n => $"TEL;TYPE={(n.Type == "mobile" ? "cell" : "voice")}:{n.Number}\r\n")); - var email = string.Join("", row.EmailAddresses.Select(a => $"EMAIL:{a.Address}\r\n")); + .Select(n => $"TEL;TYPE={(n.Type == "mobile" ? "cell" : "voice")}:{Escape(n.Number)}\r\n")); + var email = string.Join("", row.EmailAddresses.Select(a => $"EMAIL:{Escape(a.Address)}\r\n")); await _writer.WriteLineAsync($""" BEGIN:VCARD VERSION:4.0 UID:mg{row.MgNr}@{App.Client.NameToken.ToLower()}.elwig.at NOTE:MgNr. {row.MgNr} - FN:{row.AdministrativeName} - N:{row.Name};{row.GivenName};{row.MiddleName};{row.Prefix};{row.Suffix} + FN:{Escape(row.AdministrativeName)} + N:{Escape(row.Name)};{Escape(row.GivenName)};{Escape(row.MiddleName)};{Escape(row.Prefix)};{Escape(row.Suffix)} KIND:{(row.IsJuridicalPerson ? "org" : "individual")} - ADR{(billingAddr == null ? "" : ";TYPE=home")};LANGUAGE=de;LABEL="{row.Address}\n{row.PostalDest.AtPlz?.Plz} {row.PostalDest.AtPlz?.Ort.Name}\nÖsterreich":;;{row.Address};{row.PostalDest.AtPlz?.Ort.Name};;{row.PostalDest.AtPlz?.Plz};Österreich + ADR{(billingAddr == null ? "" : ";TYPE=home")};LANGUAGE=de;LABEL="{Escape(row.Address)}\n{row.PostalDest.AtPlz?.Plz} {Escape(row.PostalDest.AtPlz?.Ort.Name)}\nÖsterreich":;;{Escape(row.Address)};{Escape(row.PostalDest.AtPlz?.Ort.Name)};;{row.PostalDest.AtPlz?.Plz};Österreich {billingAddr}{tel}{email}REV:{row.ModifiedAt.ToUniversalTime():yyyyMMdd\THHmmss\Z} END:VCARD """); @@ -61,5 +61,9 @@ namespace Elwig.Helpers.Export { public void Export(IEnumerable data, IProgress? progress = null) { ExportAsync(data, progress).GetAwaiter().GetResult(); } + + private static string? Escape(string? text) { + return text?.Replace("\\", "\\\\").Replace(",", "\\,").Replace(";", "\\;").Replace("\n", "\\n").Replace("\r", ""); + } } }