--- /dev/null
+contacts
+README.html
--- /dev/null
+.password-*
+vdirsyncer-status
--- /dev/null
+Backup CardDAV vCards into git
+==============================
+
+Small script to backup address books stored a CardDAV server into
+a local git repository for backup purposes.
+Git commit messages contain the names of modified, added and deleted contacts
+so it's easy to find out when someone was modified, and thus easy to find
+lost contacts.
+
+Tested with vdirsyncer 0.19.2 and Nextcloud 23.
+
+
+Setup
+-----
+1. Install `vdirsyncer`__ 0.19.x
+2. Clone this repository
+3. Run ``./backup.sh``. Directory ``contacts`` will be created and a
+ sample sync configuration will be added
+4. In ``contacts`` directory adjust ``vdirsyncer-config``
+ and test it with::
+
+ vdirsyncer --config=vdirsyncer-config discover
+
+ Create all local collections when asked.
+5. In ``contacts`` run::
+
+ vdirsyncer --config=vdirsyncer-config metasync
+
+6. Run ``./backup.sh`` which should commit all contacts to git.
+7. Setup a cronjob on your home server to run ``backup.sh`` every night
+
+
+__ http://vdirsyncer.pimutils.org/en/stable/
+
+
+About
+-----
+This script was written by `Christian Weiske <https://cweiske.de/>`_
+and is licensed under the AGPL v3.
--- /dev/null
+#!/bin/sh
+# download vcard contacts into contacts/ and commit them to git
+set -e
+
+export GIT_AUTHOR_NAME="vcard backup"
+export GIT_COMMITTER_NAME="vcard backup"
+
+[ -d contacts ] || mkdir contacts
+
+cd contacts
+[ -d .git ] || git init
+[ -f .gitignore ] || cp ../.gitignore-contacts .gitignore
+
+if [ ! -f vdirsyncer-config ]; then
+ cp ../vdirsyncer-config.example vdirsyncer-config
+ echo "Adjust contacts/vdirsyncer-config first"
+ exit 1
+fi
+
+# commit configuration files if necessary
+conffiles=".gitignore vdirsyncer-config"
+metamod=$(git status --porcelain $conffiles)
+if [ -n "$metamod" ]; then
+ git add $conffiles
+ git commit $conffiles -m 'Update configuration'
+fi
+
+# sync and commit vcards
+vdirsyncer --config=vdirsyncer-config --verbosity WARNING sync
+numchanged=$(git status --porcelain | wc -l)
+if [ $numchanged -eq 0 ]; then
+ exit 0
+fi
+
+git add .
+../create-commit-message.sh > tmp-msg
+git commit --quiet --file=tmp-msg
+rm tmp-msg
--- /dev/null
+#!/bin/sh
+#create a nice commit message that contains the names
+# of all modified, added and deleted contacts
+# to make it easier to find changes in the git history
+set -e
+
+numadd=$(git status --porcelain -uno|grep ^A|wc -l)
+numdel=$(git status --porcelain -uno|grep ^D|wc -l)
+nummod=$(git status --porcelain -uno|grep ^M|wc -l)
+if [ "$numadd" -eq 0 -a "$numdel" -eq 0 -a "$nummod" -eq 0 ]; then
+ exit 0
+fi
+
+echo "Backup $(date +%F): ~$nummod +$numadd -$numdel"
+echo
+
+for addressbook in $(ls -1d */* | grep -v vdirsyncer-status/); do
+ user=$(echo $addressbook | cut -d/ -f1)
+ addressbookTitle=$(cat $addressbook/displayname)
+
+ added=$(git status --porcelain -uno\
+ | grep ^A.*$addressbook.*vcf$\
+ | cut -b 4-\
+ | xargs -L1 grep ^FN:\
+ | cut -b 4-\
+ | sort)
+ modified=$(git status --porcelain -uno\
+ | grep ^M.*$addressbook.*vcf$\
+ | cut -b 4-\
+ | xargs -L1 grep ^FN:\
+ | cut -b 4-\
+ | sort)
+ deleted=$(git status --porcelain -uno\
+ | grep ^D.*$addressbook.*vcf$\
+ | cut -b 4-\
+ | xargs --replace={} git diff --cached -- {}\
+ | grep ^-FN:\
+ | cut -b 5-\
+ | sort)
+
+ if [ -n "$added" -o -n "$modified" -o -n "$deleted" ]; then
+ echo "$user: $addressbookTitle"
+ echo "---------"
+
+ if [ -n "$added" ]; then
+ echo "Added:"
+ echo "$added" | sed 's/^/- /'
+ echo
+ fi
+
+ if [ -n "$modified" ]; then
+ echo "Modified:"
+ echo "$modified" | sed 's/^/- /'
+ echo
+ fi
+
+ if [ -n "$deleted" ]; then
+ echo "Deleted:"
+ echo "$deleted" | sed 's/^/- /'
+ echo
+ fi
+ fi
+done
--- /dev/null
+[general]
+status_path = "./vdirsyncer-status/"
+
+[pair anna]
+a = "remote__anna"
+b = "local__anna"
+#collections = ["from a", "from b"]
+#collections = ["from a"]
+collections = ["contacts", "geburtstagsliste"]
+conflict_resolution = "a wins"
+metadata = ["displayname"]
+
+
+[storage local__anna]
+type = "filesystem"
+path = "./anna/"
+fileext = ".vcf"
+
+
+[storage remote_anna]
+type = "carddav"
+url = "https://cloud.example.org/remote.php/carddav/"
+password.fetch = ["command", "cat", "./.password-anna"]
+read_only = true