From: Paul Hänsch Date: Mon, 22 Oct 2018 16:21:09 +0000 (+0200) Subject: common functions for pdi (vcf/ics) parsing X-Git-Url: https://git.plutz.net/?p=confetti;a=commitdiff_plain;h=da89c059ba413f8dbc01409aa883dfc1b4be1f9e;ds=sidebyside common functions for pdi (vcf/ics) parsing --- diff --git a/pdiread.sh b/pdiread.sh new file mode 100755 index 0000000..e01c71c --- /dev/null +++ b/pdiread.sh @@ -0,0 +1,107 @@ +#!/bin/zsh + +# Copyright 2014 - 2018 Paul Hänsch +# +# This file is part of Confetti. +# +# Confetti is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Confetti is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Confetti. If not, see . + +# This is a parsing library for the Personal Data Interchange format (PDI) +# PDI is the format for encoding VCard (.vcf) and iCalendar (.ics) files + +[ -n "$include_pdi" ] && return 0 +include_pdi="$0" + +BR=' +' + +pdi_load() { + sed -r ':X;N;$!bX; s;\r\n[ \t];;g; s;\r\n;\n;g;' "$1" \ + | sed -r ' + # === turn property names to upper case, strip group names === + h; s;^([^;:]+);;; + x; s;^([^;:\.]+\.)?([^;:]+).*$;\2;; + y;abcdefghijklmnopqrstuvwxyz;ABCDEFGHIJKLMNOPQRSTUVWXYZ; + G; s;\n;;; + + # === strip trailing CR (but keep CRs in property value) === + # s;\r$;;; # already done in in previous filter + + # unscramble aggregated fields + :disag + s;^([^:]+:)((.*[^\])?(\\\\)*),;\1\2\n\1;; + t disag; + + # === Normalise various known vendor properties === + s;^X-MS-CARDPICTURE(\;|:);PHOTO\1;; + s;^X-GENDER(\;|:);GENDER\1;; + s;^X-ANNIVERSARY(\;|:);ANNIVERSARY\1;; + s;^X-EVOLUTION-ANNIVERSARY(\;|:);ANNIVERSARY\1;; + s;^X-KADDRESSBOOK-X-ANNIVERSARY(\;|:);ANNIVERSARY\1;; + s;^X-EVOLUTION-BLOG-URL(\;|:);URL\1;; + s;^AGENT(\;|:);RELATED\;VALUE=text\;TYPE=agent\1;; + s;^X-ASSISTANT(\;|:);RELATED\;VALUE=text\;TYPE=assistant\1;; + s;^X-EVOLUTION-ASSISTANT(\;|:);RELATED\;VALUE=text\;TYPE=assistant\1;; + s;^X-KADDRESSBOOK-X-ASSISTANTSNAME(\;|:);RELATED\;VALUE=text\;TYPE=assistant\1;; + s;^X-MANAGER(\;|:);RELATED\;VALUE=text\;TYPE=manager\1;; + s;^X-EVOLUTION-MANAGER(\;|:);RELATED\;VALUE=text\;TYPE=manager\1;; + s;^X-KADDRESSBOOK-X-MANAGERSNAME(\;|:);RELATED\;VALUE=text\;TYPE=manager\1;; + s;^X-SPOUSE(\;|:);RELATED\;VALUE=text\;TYPE=spouse\1;; + s;^X-EVOLUTION-SPOUSE(\;|:);RELATED\;VALUE=text\;TYPE=spouse\1;; + s;^X-KADDRESSBOOK-X-SPOUSENAME(\;|:);RELATED\;VALUE=text\;TYPE=spouse\1;; + + # === Normalise obsolete vendor IM properties === + s;^X-AIM((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):;IMPP\1:aim:;; + s;^X-ICQ((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):;IMPP\1:aim:;; + s;^X-GOOGLE-TALK((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):;IMPP\1:xmpp:;; + s;^X-JABBER((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):;IMPP\1:xmpp:;; + s;^X-MSN((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):;IMPP\1:msn:;; + s;^X-YAHOO((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):;IMPP\1:ymsgr:;; + s;^X-SIP((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):(sip:)?;IMPP\1:sip:;; + + # === Update obsolete LABEL property === + s;^LABEL((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):(.*)$;ADR\1\;LABEL="\5":;; + + # === Insert empty attribute fields where no attributes are present === + s;^([^;:]+):;\1\;:;; + ' +} + +pdi_count(){ + local card="$1" name="$2" rc='' cnt=0 + while rc="${card#*${BR}${name};}"; do + [ "${rc}" != "${card}" ] || break + card="$rc" + cnt=$(($cnt + 1)) + done + printf %i\\n $cnt +} + +pdi_attrib(){ + local card=":$1" name="$2" cnt="${3:-1}" + while [ $cnt -gt 0 ]; do + card="${card#*${BR}${name};}" + cnt=$((cnt - 1)) + done + printf %s\\n "${card%%:*}" +} + +pdi_value(){ + local card="${BR}$1" name="$2" cnt="${3:-1}" + while [ $cnt -gt 0 ]; do + card="${card#*${BR}${name};*:}" + cnt=$((cnt - 1)) + done + printf %s\\n "${card%%${BR}*}" +}