]> git.plutz.net Git - lobster/commitdiff
merge from confetti
authorPaul Hänsch <paul@plutz.net>
Sat, 6 Feb 2021 22:40:32 +0000 (23:40 +0100)
committerPaul Hänsch <paul@plutz.net>
Sat, 6 Feb 2021 22:40:32 +0000 (23:40 +0100)
1  2 
cards/edit_card.sh
cards/index.cgi
cards/l10n.sh
cards/list.sh
cards/update_card.sh
cards/widgets.sh
index.cgi
pdiread.sh

Simple merge
diff --cc cards/index.cgi
index 43f949c3a7fd256bec436c61b46988970c6958e2,934c19ac3bf2499b3aee9adf0440188739a6e3f2..0bb4f827c26cf53b7c934039d5260f3a88abe739
@@@ -29,10 -17,9 +22,9 @@@ list_hi_companies()
  { w_filter_diag
    printf '
    [form class="newcard" action="/cards/new_card.sh" method="POST"
 +    [a href="#top" . %s]
      [button type="submit" %s]
 -    [input name="seed" placeholder="%s"]
 -  ]' "$(l10n newcard)" "$(l10n vcf_seed_label)"
 +  ]' "$(l10n top)" "$(l10n newcard)"
    [ "$edit" ] && edit_card "$edit"
    list_cards
- } | yield_page cards /cards/cards.css
+ } | yield_page cards #/cards/cards.css
diff --cc cards/l10n.sh
index f10007e92212e92286cad4992780043acc45355a,2d9dc06362d250a5719f378aa0e9ef8a61867bee..f991e4fddb901c95fa7ed02039c691075a5e6632
@@@ -82,60 -29,16 +29,18 @@@ l10n()
      hi_status) printf %s "Ver&shy;sich&shy;er&shy;ten&shy;sta&shy;tus";;
      X-HEALTH-INSURANCE-NOCONTRIB) printf %s "Zu&shy;zahl&shy;ungs&shy;be&shy;frei&shy;ung";;
      X-CLIENT-REFERRAL) printf %s "Empfehl&shy;ung durch";;
-     prescriptions) printf %s "Verordnungen";;
-     new_prescription) printf %s "Neue Verordnung";;
+     prescriptions) printf %s "Verord&shy;nungen";;
+     new_prescription) printf %s "Neue Verord&shy;nung";;
      no_icd) printf %s "Kein ICD Code";;
 +    therapy) printf %s "Therapie";;
 +    therapies) printf %s "Therapien";;
    
-     X-ZACK-JOINDATE)  printf %s "An&shy;mel&shy;de&shy;da&shy;tum";;
-     X-ZACK-LEAVEDATE) printf %s "Ab&shy;mel&shy;de&shy;da&shy;tum";;
+     X-ZACK-JOINDATE)  printf %s "Anmelde&shy;datum";;
+     X-ZACK-LEAVEDATE) printf %s "Abmelde&shy;datum";;
      X-ZACK-JOINDATE_short)  printf %s "Anm.";;
      X-ZACK-LEAVEDATE_short) printf %s "Abm.";;
-   
-     top) printf 'Seitenanfang';;
-     edit) printf %s "Bearbeiten";;
-     edit_categories) printf %s "Kategorien Bearbeiten";;
-     vcf_export) printf %s "Vcard Exportieren";;
-     control) printf %s "Aktionen";;
-     edit_update) printf %s "Daten übernehmen";;
-     edit_cancel) printf %s "Abbrechen";;
-     edit_delete) printf %s "Eintrag löschen";;
-     edit_addfieldtext) printf %s "Neues Feld";;
-     edit_addfield) printf %s "+";;
-     edit_deletefield) printf %s "X";;
-     filter_label) printf %s "Filter";;
-     filter_placeholder) printf %s "Begriffe zur Eingrenzung eingeben";;
-     filter_type) printf %s "Filtertyp";;
-     filter_order) printf %s "Sortierung";;
-     filter_any) printf %s "Alles";;
-     filter_name) printf %s "Name";;
-     filter_firstname) printf %s "Vorname";;
-     filter_lastname) printf %s "Nachname";;
-     filter_street) printf %s "Straße";;
-     filter_zip) printf %s "PLZ.";;
-     filter_TEL) printf %s "Telefon";;
-     filter_BDAY) printf %s "Geburtsjahr";;
-     filter_bdate) printf %s "Geburtsdatum";;
-     filter_course) printf %s "Kurs";;
-     filter_CATEGORIES) printf %s "Kategorien";;
-     filter_apply) printf %s "Filtern";;
-     filter_cancel) printf %s "Filter löschen";;
-     newcard) printf %s "Neuen Eintrag anlegen";;
-     course_attendance) printf %s "Kursteilnahme";;
-   
-     gender_none) printf %s "keine Angabe";;
-     gender_female) printf %s "Weiblich";;
-     gender_male) printf %s "Männlich";;
-     gender_other) printf %s "Sonstiges";;
-   
-     female) printf %s "&#x2640;";;
-     male) printf %s "&#x2642;";;
-     other) printf %s "&#x26A5;";;
-     none) printf %s "&#x26AA;";;
  
-     *) printf %s "$1";;
+     *) l10n_global "$word";;
    esac
  }
  
diff --cc cards/list.sh
index 9d5457ce2bdd5429259f34eaba4f78684f0e10bf,cd0d21f1e320aa958839b8fdbe75dec051286da9..03fa97340bd546d83cdccc36f35b9c2ed90401ab
@@@ -21,28 -20,55 +21,33 @@@ edit_card()
            [ "$(pdi_count "$card" NICKNAME)" -gt 0 ] \
            && edit_item "$card" NICKNAME
            edit_item "$card" BDAY
 -          edit_item "$card" X-ZACK-JOINDATE
 -          [ "$(pdi_count "$card" X-ZACK-LEAVEDATE)" -gt 0 ] \
 -          && edit_item "$card" X-ZACK-LEAVEDATE
            card_item "$card" SOUND PHOTO LOGO
          )]
 -        [div .section .phone   $(edit_item "$card" TEL)]
 -        [div .section .message $(
 -          edit_item "$card" EMAIL
 -          [ $(pdi_count "$card" IMPP) -gt 0 ] && edit_item "$card" IMPP
 -          [ $(pdi_count "$card" URL ) -gt 0 ] && edit_item "$card" URL
 -        )]
 +        [div .section .phone   $(
 +            edit_item "$card" TEL EMAIL
 +          [ $(pdi_count "$card" IMPP) -gt 0 ] \
 +            && edit_item "$card" IMPP
 +          [ $(pdi_count "$card" URL ) -gt 0 ] \
 +            && edit_item "$card" URL
 +          )]
          [div .section .address $(edit_item "$card" ADR)]
 -        [div .section .note    $(edit_item "$card" NOTE)]
 -        [div .section .attendance
 -          [h3 $(l10n course_attendance) ] $(
 -          for course in "$_DATA"/ical/*.ics; do
 -            printf '[label [input type="checkbox" name="attendance" value="%s" %s] %s]' \
 -                   "${course##*/}" \
 -                   "$(grep -qF "${course##*/} ${cardfile##*/}" "$_DATA/mappings/attendance" \
 -                      && printf 'checked="checked"'
 -                     )" \
 -                   "$(pdi_value "$(pdi_load "$course")" SUMMARY || l10n "(unnamed course)" |unescape |HTML)"
 -          done)
 -          [h3 $(l10n CATEGORIES) ] $(
 -          grep -xE '[^ ]+' "$_DATA"/mappings/categories |while read -r cat; do
 -            printf '[label [input type="checkbox" name="CATEGORIES" value="%s" %s] %s]' \
 -                   "$(HTML "$cat")" \
 -                   "$(seq 1 $(pdi_count "$card" CATEGORIES) |while read c; do
 -                     pdi_value "$card" CATEGORIES $c |grep -qxF "$cat" \
 -                     && printf 'checked="checked"' && break
 -                   done)" \
 -                   "$(HTML "$cat")"
 -          done)
 -        ]
 +        [div .section .insurance $(edit_item "$card" X-HEALTH-INSURANCE)]
 +        [div .section .note    $(edit_item "$card" NOTE X-CLIENT-REFERRAL)]
          [div .control
-           [select .item name="newfield"
-             [option value="" disabled="disabled" selected="selected" $(l10n edit_addfieldtext)]
-             $(for f in NICKNAME EMAIL TEL IMPP ADR URL NOTE; do
-               printf '[option value="%s" %s] ' "$f" "$(l10n "$f")"
-             done)
-          ][button .item type="submit" name="action" value="addfield" $(l10n edit_addfield)]
+           [div .item .delete label="$(l10n edit_delete)"
+               [input type="checkbox" #delete]
+               [label for="delete" $(l10n edit_delete)]
+             [button type="submit" name="action" value="delete" $(l10n edit_delete)]
+             ]
+             [div .item .newfield
+               [select name="newfield"
+               [option value="" disabled="disabled" selected="selected" $(l10n edit_addfieldtext)]
+               $(for f in NICKNAME EMAIL TEL IMPP ADR URL NOTE; do
+                 printf '[option value="%s" %s] ' "$f" "$(l10n "$f")"
+               done)
+             ][button type="submit" name="action" value="addfield" $(l10n edit_addfield)]
+             ]
            [button .item type="submit" name="action" value="update"   $(l10n edit_update)]
-           [input type="checkbox" #delete] [label .item for="delete" $(l10n edit_delete)]
-             [button .item type="submit" name="action" value="delete"]
            [button .item type="submit" name="action" value="cancel"   $(l10n edit_cancel)]
          ]
          [input type="hidden" name="UID" value="$(pdi_value "$card" UID |HTML)"]
  print_card(){
    local cardfile="$1"
    local card="$(pdi_load "$cardfile")"
 +  local N1 N2 N3 N4 N5
 +  IFS=\; read N1 N2 N3 N4 N5 <<-EOF
 +      $(pdi_value "$card" N |pdi_unescape |HTML)
 +      EOF
 +
    cat <<-EOF
-     [span .card-anchor #${cardfile##*/}]
-     [div .card
+     [div .card #${cardfile##*/}
 -      [div .section .basic . $(
 -        card_item "$card" FN GENDER NICKNAME BDAY X-ZACK-JOINDATE X-ZACK-LEAVEDATE SOUND PHOTO LOGO
 +      [div .section .basic
 +      [h2 .item .FN . $N4 $N1 $N5]
 +      [span .item .firstname . $N2 $N3]
 +      $(
 +        card_item "$card" GENDER NICKNAME BDAY X-ZACK-JOINDATE X-ZACK-LEAVEDATE SOUND PHOTO LOGO
        )]
 -      [div .section .phone   . $(card_item "$card" TEL)]
 -      [div .section .message . $(card_item "$card" EMAIL IMPP URL)]
 -      [div .section .address . $(card_item "$card" ADR)]
 -      [div .section .note    . $(card_item "$card" NOTE)]
 -      [div .section .attendance [h3 $(l10n course_attendance) ] [ul
 -        $(grep -F "   ${cardfile##*/}" "$_DATA/mappings/attendance" |while read each discard; do
 -          printf '[li [a .item .attendance href="/courses#%s" . %s]]' \
 -                 "$each" \
 -                 "$(pdi_value "$(pdi_load "$_DATA/ical/$each")" SUMMARY || l10n "(unnamed course)" |unescape |HTML)"
 -        done)]
 -        $(card_item "$card" CATEGORIES)
 -      ]
 +      [div .section .address   $(card_item "$card" ADR)]
 +      [div .section .phone     $(card_item "$card" TEL EMAL IMPP URL)]
 +      [div .section .insurance $(card_item "$card" X-HEALTH-INSURANCE)]
 +      [div .section .note      $(card_item "$card" NOTE X-CLIENT-REFERRAL)]
 +      [div .section .therapies $(card_item "$card" therapies)]
        [div .control
          [a .item href="/cards/edit_card.sh?card=${cardfile##*/}" $(l10n edit)]
          [a .item href="/cards/export_card.sh?card=${cardfile##*/}" $(l10n vcf_export)]
@@@ -109,13 -159,15 +113,13 @@@ filter_cards()
      case $f in
        '') break
          ;;
-       ANY:*) fex="/\n.*(\;[^:]*)?:.*(${f#*:}).*\r?\n/{${fex}}"
 -      COURSE:*) fatt="${fatt}${fatt:+ }${f#*:}"
 -        ;;
+       ANY:*) fex="/\n.*(\;[^:]*)?:[^\n]*(${f#*:})[^\n]*\r?\n/{${fex}}"
          ;;
-       NAME:*) fex="/\n(N|FN|NICKNAME)(\;[^:]*)?:[^\n]*(${f#*:}).*\r?\n/{${fex}}"
+       NAME:*) fex="/\n(N|FN|NICKNAME)(\;[^:]*)?:[^\n]*(${f#*:})[^\n]*\r?\n/{${fex}}"
          ;;
-       STREET:*|ZIP:*) fex="/\nADR(\;[^:]*)?:[^\n]*(${f#*:}).*\r?\n/{${fex}}"
+       STREET:*|ZIP:*) fex="/\nADR(\;[^:]*)?:[^\n]*(${f#*:})[^\n]*\r?\n/{${fex}}"
          ;;
-       *) fex="/\n${f%%:*}(\;[^:]*)?:[^\n]*(${f#*:}).*\r?\n/{${fex}}"
+       *) fex="/\n${f%%:*}(\;[^:]*)?:[^\n]*(${f#*:})[^\n]*\r?\n/{${fex}}"
          ;;
      esac
    done
index 84d9c7e9b310662d403a9eb495dd8248a5796f54,d942e9abdbc527aa5ff803bc8c0b4dd501355778..2ee69318c28da5c502d6e89a4c9b6364cebbe9c3
  
  . "$_EXEC/pdiread.sh"
  . "$_EXEC/session_lock.sh"
+ . "$_EXEC/cgilite/storage.sh"
  
  unset filter order card action newfield
--unset cardfile attfile tempfile
++unset cardfile tempfile
  unset vcf field cnt delete_key
  
  filter="$(REF f)"
  order="$(REF o)"
  
- card="$(POST card |PATH)"
- cardfile="$_DATA/vcard/${card##*/}"
- attfile="$_DATA/mappings/attendance"
+ card="$(POST card |PATH)"; card="${card##*/}"
+ cardfile="$_DATA/vcard/${card}"
 -attfile="$_DATA/mappings/attendance"
  
  action="$(POST action)"
  newfield="$(POST newfield |grep -m 1 -xE '[A-Z][A-Z0-9-]*')"
@@@ -49,16 -50,27 +49,19 @@@ elif [ "$(POST tid)" != "$(transid "$te
    exit 0
  fi
  
 -vcf_escape(){
 -  for each in "$@"; do
 -    printf %s\\n "$each" \
 -    | sed -E ':X;$!{N;bX}; s;\r\n;\n;g; s;([;,\\]);\\\1;g; s;\n;\\n;g;'
 -  done \
 -  | sed -E ':X;$!{N;bX}; s;\n;\;;g'
 -}
 -
  # [ "${_POST[hi_select]}" = "list" ] || _POST[hi_company]="${_POST[hi_other]}"
  # [ -n "${_POST[hi_company]}${_POST[hi_number]}${_POST[hi_status]}" ] \
 -# && _POST[X-HEALTH-INSURANCE]="$(vcf_escape "${_POST[hi_company]}" "${_POST[hi_number]}" "${_POST[hi_status]}")"
 +# && _POST[X-HEALTH-INSURANCE]="$(pdi_escape "${_POST[hi_company]}" "${_POST[hi_number]}" "${_POST[hi_status]}")"
  
- # vcf="$(pdi_load "$cardfile")"
  vcf="$(pdi_load "$tempfile")"
  
- vcf="$(pdi_update_value "$vcf" N 1 "$(pdi_escape "$(POST 1N)" "$(POST 2N)" "$(POST 3N)" "$(POST 4N)" "$(POST 5N)")")"
- vcf="$(pdi_update_value "$vcf" FN 1 "$(pdi_escape "$(POST 4N) $(POST 2N) $(POST 3N) $(POST 1N) $(POST 5N)" \
-                                        | sed -E 's;^ +;;; s; +$;;; s; +; ;g;')" )"
+ n1="$(POST 1N)" n2="$(POST 2N)" n3="$(POST 3N)" n4="$(POST 4N)" n5="$(POST 5N)"
+ # 3N (Middle Names) is not actually used
+ n3="${n2#${n2%% *}}"
+ vcf="$(pdi_update_value "$vcf"  N 1 "$(vcf_escape "$n1" "${n2%% *}" "${n3# }" "$n4" "$n5")")"
+ vcf="$(pdi_update_value "$vcf" FN 1 "$(vcf_escape "$n4 $n2 $n1 $n5" |sed -E 's;(^ +| +$);;g; s; +; ;g;')")"
+ vcf="$(printf '%s\n' "$vcf" |sed -E "/^CATEGORIES;[^:]*:.*$/d")"
  
  for field in $(POST_KEYS |grep -xE '[A-Z][A-Z0-9-]*'); do
    for cnt in $(seq 1 $(POST_COUNT "$field")); do
@@@ -107,27 -105,28 +110,12 @@@ printf '%s' "$vcf" | sed -E '/^$/d; s/^
  
  case "$action" in
    addfield)
 -    REDIRECT "/cards/?o=${order}&f=${filter}&e=${card}"
 +    REDIRECT "/cards/?o=${order}&f=${filter}&e=${card#/}"
      ;;
    update)
-     # attendance=()
-     # for att in attendance attendance{0..100}; do
-     #   [ -n "${_POST[$att]}" ] && attendance+=("${_POST[$att]}")
-     # done
-     # sed -rn 's:^(.+)'$card'$:\1:p' "$attfile" |while read course; do
-     #   touch "$_DATA/ical/$course"
-     # done
-     # sed -i -r '/^(.+)\t'$card'$/d' "$attfile"
-     # for each in $attendance; do
-     #   echo "$each\t$card"
-     # done >>"$attfile"
-     # sed -rn 's:^(.+)'$card'$:\1:p' "$attfile" |while read course; do
-     #   touch "$_DATA/ical/$course"
-     # done
 -    if LOCK "$attfile"; then
 -      grep -F "       ${card}" "$attfile" |while read course junk; do
 -        touch "$_DATA/ical/${course}"
 -      done
 -      sed -i -E "/^.+ ${card}\$/d" "$attfile"
 -      seq 1 $(POST_COUNT attendance) |while read n; do
 -        printf '%s    %s\n' "$(POST attendance $n)" "$card"
 -      done >>"$attfile"
 -      grep -F "       ${card}" "$attfile" |while read course junk; do
 -        touch "$_DATA/ical/${course}"
 -      done
 -      RELEASE "$attfile"
 -    else
 -      SET_COOKIE 0 message="COULD NOT UPDATE COURSE MAPPINGS"
 -    fi
--
      cp "$tempfile" "$cardfile"
      RELEASE_SLOCK "$cardfile"
 -    REDIRECT "/cards/?o=${order}&f=${filter}#${card}"
 +    REDIRECT "/cards/?o=${order}&f=${filter}#${card#/}"
      ;;
    cancel)
      RELEASE_SLOCK "$cardfile"
index e1f659659ccec70221cad9fdc40cc9ba26f3ed26,c0c05946b1c594272d034a33081e351444873df9..9a71f198c4a9322ef6f465dba321290b5d6cc0f1
@@@ -44,17 -77,18 +44,18 @@@ w_filter_diag()
          w_filter_item "${fil%%:*}" "${fil#*:}" $n
          n=$((n + 1))
        done
-       w_filter_item any '' $n
+       [ "$n" -eq 0 -o "$(GET newfilter)" ] && w_filter_item any '' $n
      )
-   
+     [button type="submit" name="choice" value="new_filter" $(l10n filter_more)]
      [fieldset class="order"
        [legend $(l10n filter_order):]
 -      [label [radio "order" "firstname" $( [ "$order" = firstname ] && printf checked )] $(l10n filter_firstname)]
        [label [radio "order" "lastname"  $( [ "$order" = lastname  ] && printf checked )] $(l10n filter_lastname)]
 +      [label [radio "order" "firstname" $( [ "$order" = firstname ] && printf checked )] $(l10n filter_firstname)]
        [label [radio "order" "bdate"     $( [ "$order" = bdate     ] && printf checked )] $(l10n filter_bdate)]
      ]
-     [button type="submit" name="choice" value="new_filter" $(l10n filter_apply)]
+     [button type="submit" name="choice" value="filter" $(l10n filter_apply)]
      [button type="submit" name="choice" value="del_filter" $(l10n filter_cancel)]
+     [button type="submit" name="choice" value="export_csv" $(l10n export_csv)]
    ]
  EOF
  }
@@@ -113,47 -162,15 +114,47 @@@ card_item()
            [ "$teltype" ] \
            && printf '[span .item .TEL [span .type . %s:] %s]' \
                      "$(l10n "TYPE=$teltype" |HTML)" \
-                     "$(pdi_value "$card" TEL $c |pdi_unescape |HTML)" \
+                     "$(pdi_value "$card" TEL $c |unescape |HTML)" \
            || printf '[span .item .TEL . %s]' \
-                     "$(pdi_value "$card" TEL $c |pdi_unescape |HTML)"
+                     "$(pdi_value "$card" TEL $c |unescape |HTML)"
          done
          ;;
-                  ' "$(pdi_unescape "$hi_name" |HTML)" \
-                    "$(l10n hi_number)" "$(pdi_unescape "$hi_number" |HTML)" \
-                    "$(l10n hi_status)" "$(pdi_unescape "$hi_status" |HTML)"
 +      X-HEALTH-INSURANCE)
 +        [ $cnt -gt 0 ] && printf '[h3 %s]' "$(l10n X-HEALTH-INSURANCE)"
 +        seq 1 $cnt |while read c; do
 +          IFS=\; read -r hi_name hi_number hi_status <<-EOF
 +              $(pdi_value "$card" X-HEALTH-INSURANCE $c)
 +              EOF
 +          printf '[span .item .hi_company . %s]
 +                  [span .item .hi_number [label %s:] %s]
 +                  [span .item .hi_status [label %s:] %s]
++                 ' "$(unescape "$hi_name" |HTML)" \
++                   "$(l10n hi_number)" "$(unescape "$hi_number" |HTML)" \
++                   "$(l10n hi_status)" "$(unescape "$hi_status" |HTML)"
 +        done
 +        ;;
 +      therapies)
 +        client="$(pdi_value "$card" UID)"
 +        printf '[h3 %s]' "$(l10n therapies)"
 +        (cd "$_DATA/therapies/"; printf '%s\n' "${client}".*.tpy) \
 +        | while read tpyfile; do
 +          [ "$tpyfile" = "${client}.*.tpy" ] \
 +          && printf '[a .item .therapy href="/therapies/%s/new" . +]' "${client}" \
 +          && break
 +          tpy="${tpyfile%.tpy}";
 +          tpydates="$(sed -En 's;^session[0-9]+_date:;;p;' "$_DATA/therapies/$tpyfile" \
 +                      | sort \
 +                      | sed -E ':X;N;$!bX; s;^[\n ]+;;; s;[\n ]+$;;; s;(\n.*\n|\n); - ;;'
 +                     )"
 +          printf '[a .item .therapy href="/therapies/%s" . %s] ' \
 +                 "${tpy%.*}/${tpy#*.}" "$(HTML "${tpydates:--}")"
 +        done |sort -n
 +        ;;
        *)[ $cnt -gt 0 ] && printf '[h3 %s]' "$(l10n "$item")"
 +        shy="$(printf '\302\255')"
          seq 1 $cnt |while read c; do
            printf '[span .item .%s . %s]' "$item" \
-                  "$(pdi_value "$card" "$item" $c |sed -r "s;(straße|weg|damm|allee|ufer);${shy}\1;g" |pdi_unescape |HTML)"
 -                 "$(pdi_value "$card" "$item" $c |unescape |HTML)"
++                 "$(pdi_value "$card" "$item" $c |sed -r "s;(straße|weg|damm|allee|ufer);${shy}\1;g" |unescape |HTML)"
          done
          ;;
      esac
diff --cc index.cgi
index 0d85c87a1c13949361965d54ae42c2154a5e5551,ee0d6f7200900df4e43ba1a2347da90fca72006b..40db42b99eb53288fb2494aa7faac2947ee47acd
+++ b/index.cgi
@@@ -3,23 -3,26 +3,37 @@@
  for n in "$@"; do case ${n%%=*} in
    data) _DATA="${n#data=}";;
    exec) _EXEC="${n#exec=}";;
-   noerr) exec 2>&-;;
+   debug) DEBUG="${n#debug=}";;
  esac; done
  
- [ -z "${_EXEC%/}" ] && _EXEC="$(realpath "${0%/*}")" || _EXEC="${_EXEC%/}"
- [ -z "${_DATA%/}" ] && _DATA=. || _DATA="${_DATA%/}"
+ [ ! "${_EXEC%/}" ] && _EXEC="$(realpath "${0%/*}")" || _EXEC="${_EXEC%/}"
+ [ ! "${_DATA%/}" ] && _DATA=. || _DATA="${_DATA%/}"
+ [ "$DEBUG" ] && exec 2>>"$DEBUG"
+ mkdir -p "${_DATA}/cache" "${_DATA}/mappings" "${_DATA}/export" "${_DATA}/lock" "${_DATA}/ical" "${_DATA}/vcard"
+ debug() {
+   local dbg=/dev/stderr
+   if [ ! "$DEBUG" ]; then
+     [ "$#" -gt 0 ] && : || cat;
+   elif [ "$#" -gt 0 ]; then
+     printf '%s\n' "$@" >>"$dbg"
+   else
+     tee -a "$dbg"
+   fi
+ }
  
 +debug() {
 +  local dbg=/dev/stderr
 +  if [ ! "$DEBUG" ]; then
 +    [ "$#" -gt 0 ] && : || cat;
 +  elif [ "$#" -gt 0 ]; then
 +    printf '%s\n' "$@" >>"$dbg"
 +  else
 +    tee -a "$dbg"
 +  fi
 +}
 +
  . "$_EXEC/cgilite/cgilite.sh"
  . "$_EXEC/cgilite/session.sh"
  
@@@ -65,17 -71,27 +82,27 @@@ yield_page() 
  topdir="${_PATH#/}"
  topdir="/${topdir%%/*}"
  
- if [ "${_PATH}" = / ]; then
-   REDIRECT /cards/
- elif   [   -d "${_EXEC}/${_PATH}" -a -x "${_EXEC}/${_PATH}/index.cgi" ]; then
-   . "${_EXEC}/${_PATH}/index.cgi"
- elif [ ! -d "${_EXEC}/${_PATH}" -a -x "${_EXEC}/${_PATH}" ]; then
-   . "${_EXEC}/${_PATH}"
- elif [ ! -x "${_EXEC}/${_PATH}" -a -r "${_EXEC}/${_PATH}" ]; then
-   . "$_EXEC/cgilite/file.sh"
-   FILE "${_EXEC}/${_PATH}"
- elif   [   -d "${_EXEC}/${topdir}" -a -x "${_EXEC}/${topdir}/index.cgi" ]; then
-   . "${_EXEC}/${topdir}/index.cgi"
- else
-   printf 'Status: 404 Not Found\r\nContent-Length: 0\r\n\r\n'
- fi
+ case ${_PATH} in
+   /) REDIRECT /cards/
+     ;;
 -  /export/*.pdf) . "$_EXEC/cgilite/file.sh"
 -    FILE "${_DATA}/${_PATH}" "application/pdf"
 -    ;;
 -  /export/*) . "$_EXEC/cgilite/file.sh"
 -    FILE "${_DATA}/${_PATH}"
 -    ;;
++#  /export/*.pdf) . "$_EXEC/cgilite/file.sh"
++#    FILE "${_DATA}/${_PATH}" "application/pdf"
++#    ;;
++#  /export/*) . "$_EXEC/cgilite/file.sh"
++#    FILE "${_DATA}/${_PATH}"
++#    ;;
+   *)
+     if   [ -d "${_EXEC}/${_PATH}" -a -x "${_EXEC}/${_PATH}/index.cgi" ]; then
+       . "${_EXEC}/${_PATH}/index.cgi"
+     elif [ -f "${_EXEC}/${_PATH}" -a -x "${_EXEC}/${_PATH}" ]; then
+       . "${_EXEC}/${_PATH}"
+     elif [ -f "${_EXEC}/${_PATH}" -a -r "${_EXEC}/${_PATH}" ]; then
+       . "$_EXEC/cgilite/file.sh"
+       FILE "${_EXEC}/${_PATH}"
+     elif [ -d "${_EXEC}/${topdir}" -a -x "${_EXEC}/${topdir}/index.cgi" ]; then
+       . "${_EXEC}/${topdir}/index.cgi"
+     else
+       printf '%s\r\n' 'Status: 404 Not Found' 'Content-Length: 0' ''
+     fi
+     ;;
+ esac
diff --cc pdiread.sh
index c2654b68798fdb250aca46c0336b3f9d29012303,08fbaec3fb373c2fbb6cdde7974caaa520b849e3..f547cb689c1857d4397e9d7565cedc4f3ba0000a
@@@ -100,36 -110,9 +110,36 @@@ pdi_load() 
      # === Update obsolete LABEL property ===
      s;\nLABEL((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):(.*)\n;\nADR\1\;LABEL="\5":\n;g;
  
-     p;' "$1"
+     p;' "$@"
  }
  
 +pdi_escape(){
 +  local in out=''
 +  for in in "$@"; do
 +    out="${out}${out:+;}"
 +    while [ "$in" ]; do case $in in
 +      \\*) out="${out}\\\\"; in="${in#\\}" ;;
 +      ,*) out="${out}\\,"; in="${in#,}" ;;
 +      \;*) out="${out}\\;"; in="${in#;}" ;;
 +      "$BR"*) out="${out}\\n"; in="${in#${BR}}" ;;
 +      *) out="${out}${in%%[\\,;${BR}]*}"; in="${in#"${in%%[\\,;${BR}]*}"}" ;;
 +    esac; done
 +  done
 +  printf '%s\n' "$out"
 +}
 +
 +pdi_unescape(){
 +  local in out=''
 +  [ $# -gt 0 ] && in="$*" || in="$(cat)"
 +  while [ "$in" ]; do case $in in
 +    \\\\*) out="${out}\\"; in="${in#\\\\}" ;;
 +    \\n*) out="${out}${BR}"; in="${in#\\n}" ;;
 +    \\*) in="${in#\\}" ;;
 +    *) out="${out}${in%%\\*}"; in="${in#"${in%%\\*}"}" ;;
 +  esac; done
 +  printf '%s\n' "$out"
 +}
 +
  pdi_count(){
    local card="$1" name="$2" rc='' cnt=0
    while rc="${card#*${BR}${name};}"; do