+#!/bin/sh
+
+_EXEC="$(realpath "${0%/*}")"
+. "$_EXEC/cgilite/cgilite.sh"
+. "$_EXEC/cgilite/storage.sh"
+
+debug(){
+ if [ $# = 0 ]; then
+ tee /dev/stderr
+ else
+ printf %s\\n "$*" >/dev/stderr
+ fi
+}
+
+timeid(){
+ # generate time based ID
+ # Fixme: Unix time stamps assumed to be 32bit always
+ d=$(date +%s)
+ { printf $(
+ while [ "$d" -gt 0 ]; do
+ printf \\%o\\n $((d % 256))
+ d=$((d / 256))
+ done |tac |tr -d \\n
+ )
+ head -c5 /dev/urandom
+ } \
+ | uuencode -m - \
+ | sed -n '2{y;+/;:_;;p}'
+}
+
+checkid(){
+ grep -m 1 -xE '[0-9a-zA-Z:_]{12}';
+}
+
+yield_page(){
+printf 'Content-Type: text/html; charset=utf-8\r\n\r\n'
+./cgilite/html-sh.sed <<EOF
+[html [head
+ [meta name="viewport" content="width=device-width"]
+ [link rel="stylesheet" type="text/css" href="invoices.css"]
+ [title Invoices]
+] [body class="$1"
+ [div #menu
+ [a "/invoices/" Invoices]
+ [a "/clients/" Clients]
+ [a "/senders/" Senders]
+ ]
+ $(cat)
+] ]
+EOF
+}
+
+edit_client(){
+ id="$1"
+ if [ -f "clients/$id" ]; then
+ read -r address hourly <"clients/$id"
+ fi
+ [ "$address" ] || address="address="
+ [ "$hourly" ] || hourly="hourly="
+ printf '
+ [form method="POST" action="/update_client"
+ [hidden "id" "%s"]
+ <textarea name="address" placeholder="address">
+%s</textarea>
+ [label for=hourly Hourly Rate:]
+ [input #hourly type=number name=hourly value="%s"]
+ [submit "update" "update" Update]
+ ]' \
+ "$(HTML $id)" \
+ "$(UNSTRING "${address#address=}" |HTML)" \
+ "$(UNSTRING "${hourly#hourly=}" |grep -xE '[0-9]+')"
+}
+
+edit_sender(){
+ id="$1"
+ if [ -f "senders/$id" ]; then
+ address="$(cat "senders/$id")"
+ fi
+ [ "$address" ] || address="Name
+Street
+City
+
+Phone:
+000 000000
+
+Tax no.
+xxx / 000 / ###
+"
+ printf '
+ [form method="POST" action="/update_sender"
+ [hidden "id" "%s"]
+ <textarea name="address" placeholder="address">%s</textarea>
+ [submit "update" "update" Update]
+ ]' \
+ "$(HTML $id)" \
+ "$(HTML "${address}")"
+}
+
+list_clients(){
+ [ -d clients/ ] && for c in clients/*; do
+ read -r address hourly <"$c"
+ address="$(UNSTRING "${address#address=}")"
+ [ "$address" ] || address="(no address)"
+ printf '[div .client .address <!--
+ -->%s[a href="/clients/%s" Edit]]
+ ' "$(HTML "$address")" "$(HTML "${c#clients/}")"
+ done
+}
+
+list_senders(){
+ [ -d senders/ ] && for s in senders/*; do
+ address=$(cat "$s")
+ [ "$address" ] || address="(no address)"
+ printf '[div .sender .address <!--
+ -->%s[a href="/senders/%s" Edit]]
+ ' "$(HTML "$address")" "$(HTML "${s#senders/}")"
+ done
+}
+
+list_invoices(){
+ [ -d invoices/ ] && for i in invoices/*; do
+ read -r sender client date number vat<<-EOF
+ sed q "$i"
+ EOF
+ [ -f "senders/${sender#sender=}" ] \
+ && sender="$(sed q "senders/${sender#sender=}")" \
+ || sender="(unset)"
+ [ -f "clients/${client#client=}" ] \
+ && client="$(sed q "client/${client#client=}")" \
+ || client="(unset)"
+ [ "$date" -gt 0 ] \
+ && date="$(date -d @$date +%x)" \
+ || date="(unset)"
+
+ printf '[div .invoice
+ [h2
+ %s]
+ [label From:] %s [label To:] %s [label on] %s
+ [a href="/invoices/%s" Edit]
+ ]' "$(HTML "$number")" "$(HTML "$sender")" \
+ "$(HTML "$client")" "$(HTML "$date")"
+ done
+}
+
+info="$(PATH "${PATH_INFO}")"
+
+case $info in
+ /invoices.css)
+ . "$_EXEC/cgilite/file.sh"
+ FILE "$_EXEC/invoices.css"
+ ;;
+ /clients)
+ { list_clients
+ printf '[a .new href="/clients/%s" New]' "$(timeid)"
+ } | yield_page clients
+ ;;
+ /clients/*)
+ edit_client "${info#/clients/}" |yield_page client
+ ;;
+ /update_client)
+ id="$(POST id |checkid)"
+ if [ "$(POST update)" = update -a "$id" ]; then
+ mkdir -p clients
+ printf 'address=%s hourly=%s' \
+ "$(POST address |STRING)" "$(POST hourly |STRING)" \
+ >"clients/$id"
+ else
+ echo Invalid Data "$(POST id)" "$(POST update)" >&2
+ fi
+ REDIRECT /clients/
+ ;;
+ /senders)
+ { list_senders
+ printf '[a .new href="/senders/%s" New]' "$(timeid)"
+ } | yield_page senders
+ ;;
+ /senders/*)
+ edit_sender "${info#/senders/}" |yield_page sender
+ ;;
+ /update_sender)
+ id="$(POST id |checkid)"
+ if [ "$(POST update)" = update -a "$id" ]; then
+ mkdir -p senders
+ POST address >"senders/$id"
+ fi
+ REDIRECT /senders/
+ ;;
+ /invoices)
+ { list_invoices
+ printf '[a href="/invoices/%s" New]' "$(timeid)"
+ } | yield_page invoices
+ ;;
+ /invoice/*)
+ edit_invoice "${info#/invoices/}" |yield_page invoice
+ ;;
+ *) REDIRECT /invoices
+ ;;
+esac