CalDAV: HTML-Entities in Terminfeldern dekodieren
Manche Kalender speichern SUMMARY/LOCATION/DESCRIPTION mit wörtlichen HTML-Entities (z. B. "Vorstellungsgespräch – dot.haus"). Diese wurden roh angezeigt. Beim Parsen werden sie jetzt in echte Zeichen dekodiert. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+18
-3
@@ -122,6 +122,21 @@ function unescapeText(s) {
|
||||
.replace(/\\\\/g, '\\');
|
||||
}
|
||||
|
||||
// Some clients store SUMMARY/LOCATION/DESCRIPTION with HTML entities baked in
|
||||
// (e.g. "Vorstellungsgespräch – dot.haus"). iCal text is plain, so
|
||||
// decode them back to real characters before we hand the value on.
|
||||
function decodeHtmlEntities(s) {
|
||||
return String(s == null ? '' : s)
|
||||
.replace(/&#(\d+);/g, (_, n) => String.fromCodePoint(parseInt(n, 10)))
|
||||
.replace(/&#x([0-9a-fA-F]+);/g, (_, n) => String.fromCodePoint(parseInt(n, 16)))
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, "'")
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/&/g, '&');
|
||||
}
|
||||
|
||||
// Fold a content line to <=75 octets per RFC 5545 (CRLF + single space).
|
||||
function fold(line) {
|
||||
if (Buffer.byteLength(line, 'utf8') <= 75) return line;
|
||||
@@ -204,9 +219,9 @@ function parseVEvent(ics) {
|
||||
paramParts.forEach((p) => { const [k, v] = p.split('='); if (k) params[k.toUpperCase()] = v; });
|
||||
const key = name.toUpperCase();
|
||||
if (key === 'UID') ev.uid = value.trim();
|
||||
else if (key === 'SUMMARY') ev.summary = unescapeText(value);
|
||||
else if (key === 'LOCATION') ev.location = unescapeText(value);
|
||||
else if (key === 'DESCRIPTION') ev.description = unescapeText(value);
|
||||
else if (key === 'SUMMARY') ev.summary = decodeHtmlEntities(unescapeText(value));
|
||||
else if (key === 'LOCATION') ev.location = decodeHtmlEntities(unescapeText(value));
|
||||
else if (key === 'DESCRIPTION') ev.description = decodeHtmlEntities(unescapeText(value));
|
||||
else if (key === 'DTSTART') { const r = icsToDate(value, params); ev.start = r.date; ev.allDay = r.allDay; }
|
||||
else if (key === 'DTEND') { const r = icsToDate(value, params); ev.end = r.date; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user