diff options
-rwxr-xr-x | alpine-to-carddav | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/alpine-to-carddav b/alpine-to-carddav new file mode 100755 index 0000000..a0fe779 --- /dev/null +++ b/alpine-to-carddav @@ -0,0 +1,160 @@ +#!/bin/bash + +. "${0%/*}/common" + +if [ -z "$(git -C "${git_dir}" diff)" ]; then + exit +fi + +find_vcs \ +| while read -r file; do + if [ ! -f "${file}" ]; then + >&2 printf 'File "%s" is in git, but not in the worktree.\n' "${file##*/}" + exit 1 + fi + if ! git -C "${git_dir}" archive HEAD -- "${file##*/}" >/dev/null; then + >&2 printf 'File "%s" is in the worktree but not in git.\n' "${file##*/}" + exit 1 + fi + if ! git -C "${git_dir}" archive HEAD -- "${file##*/}" \ + | tar -Ox \ + | diff -q - "${file}"; then + >&2 printf 'File "%s" was changed relative to git.\n' "${file##*/}" + exit 1 + fi +done + +print_cnt() { + printf 'BEGIN:VCARD\n' + printf 'VERSION:3.0\n' + for key in "${keys[@]}"; do + eval 'value="${'"$1${key}"'}"' + if [ -n "${value}" ]; then + printf '%s:%s\n' "${key}" "${value}" + fi + done + printf 'END:VCARD\n' +} + +read_line() { + read -r line + for key in "${alpine_keys[@]}"; do + eval "${1}${key}"'="${line%%'"$(printf '\t')"'*}"' + eval 'line="${line#${'"${1}${key}"'}}"' + line="${line#$(printf '\t')}" + done +} + +sed -i ' + /^#/d +' "${git_dir}"'/addressbook' + +last_uids=() +git -C "${git_dir}" diff -U0 -- addressbook \ +| sed ' + 1,/^+++/d + $ s#$#\n@@ # +' \ +| while read line; do + case "${line}" in + '@@ '*) + for last_uid in "${last_uids[@]}"; do + sed -i '/^'"${last_uid}"'\s/d' "${git_dir}/uids" + rm "${git_dir}/${last_uid}.vcs" + done + last_uids=() + removals=false + ;; + '+'*) + last_uid="${last_uids[${#last_uids[@]}]}" + mapfile -t last_uids < <( + printf '%s\n' "${last_uids[@]}" \ + | sed '$d' + ) + read_line 'new' < <( + printf '%s\n' "${line#+}" + ) + newREV=$( + date -u -Iseconds \ + | sed 's@+00:00$@Z@' + ) + if [ -z "${last_uid}" ]; then + if ${removals}; then + >&2 printf 'There were more addresses added than removed.\n' + exit 1 + fi + last_uid=$(uuidgen) + printf '%s\t%s\n' "${last_uid}" "${line#+}" \ + >> "${git_dir}/uids" + print_cnt 'new' > "${git_dir}/${last_uid}.vcs" + else + read_line 'old' < <( + sed ' + s/^'"${last_uid}"'\t// + t + d + ' "${git_dir}/uids" + ) + sed -i ' + /^'"${last_uid}"'\t/ { + i '"${last_uid}$(printf '\t')${line#+}"' + d + } + ' "${git_dir}/uids" + for key in "${alpine_keys[@]}"; do + if eval '[ "${old'"${key}"'}" != "${new'"${key}"'}" ]'; then + for insert in "${key}:" 'VERSION:' 'BEGIN:VCARD$' ''; do + if [ -z "${insert}" ]; then + >&2 printf 'Cannot find any place to insert into "%s".\n' "${uid}.vcs" + exit 1 + fi + if ! grep -q '^'"${insert}" "${git_dir}/${uid}.vcs"; then + continue + fi + if [ "${insert}" = "${key}:" ]; then + delete_command='d' + else + delete_command='' + fi + eval 'value="${new'"${key}"'}"' + if [ -z "${value}" ]; then + insert_command='' + else + insert_command='a '"${key}"':'"${value}" + fi + sed -i ' + /^'"${key}"'/ { + '"${insert_command}"' + '"${delete_command}"' + } + ' "${git_dir}/${uid}.vcs" + break + done + fi + done + fi + ;; + '-'*) + removals=true + if num=$( + sed 's@^\S\+ @@' "${git_dir}/uids" \ + | grep -nxF "${line#-}" + ); then + last_uid=$( + sed -n ' + '"${num}"' { + s@\s.*$@@ + p + }' + ) + else + >&2 printf 'cannot find line "%s" for removal\n' "${line#-}" + exit 1 + fi + last_uids=( + "${last_uids[@]}" + "${last_uid}" + ) + ;; + esac +done |