summaryrefslogtreecommitdiff
path: root/alpine-to-carddav
diff options
context:
space:
mode:
Diffstat (limited to 'alpine-to-carddav')
-rwxr-xr-xalpine-to-carddav160
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