307 lines
7.5 KiB
Bash
Executable File
307 lines
7.5 KiB
Bash
Executable File
#!/bin/bash
|
|
help() {
|
|
printf '\ncontact is a command line contact manager\n\n'
|
|
help-short
|
|
printf '\n\nA typical contact looks like this:
|
|
|
|
name=John Doe
|
|
email=john.doe@doe-trading.com
|
|
mobile=1234567890
|
|
nick=Johnny
|
|
|
|
You can add any number of properties more: address, country, city, email2, url, xmpp or any custom property.
|
|
|
|
`contact mutt-aliases` will print all contacts with alias file syntax. It will read the "name", "nick", and "email" properties. You can run `contact mutt-aliases > ~/.mutt/aliases` to update your aliases file.
|
|
|
|
`contact vcf-export` will format the output in0 vCard syntax, which can then be imported into various other applications. It will read the "name", "email", "mobile", "work", "home", and "phone" properties. Create a .vcf file for importing with `contact vcf-export > ~/contacts.vcf`
|
|
'
|
|
}
|
|
help-short() {
|
|
printf 'Syntax:
|
|
contact [COMMAND] [NAME] [PROPERTY]
|
|
Commands:
|
|
No command: Interactive prompt
|
|
add: Add new contact
|
|
edit: Edit existing contact
|
|
delete: Delete contact
|
|
get: Get property of contact
|
|
getfiltered: start interactive prompt, but only list properties matching $2
|
|
git: Interact with the git repository directly
|
|
Example: `contact git status`
|
|
To enable the git repository features of contact you need to run:
|
|
`contact git init`
|
|
If you already have contacts you need to manually commit them:
|
|
`contact git add --all;contact git commit -m "Commit all existing contacts"`
|
|
help: Show this message
|
|
mutt-aliases: Export as mutt aliases.
|
|
vcf-export: Export as .vcf file.
|
|
rename-all: Rename all files to the correct name
|
|
rebuild: Rebuild the cache\n'
|
|
}
|
|
error() {
|
|
case $1 in
|
|
64)
|
|
msg="No matching contact"
|
|
;;
|
|
65)
|
|
msg="Please specify name (name=Max Muster)"
|
|
;;
|
|
66)
|
|
msg="Contact already exists"
|
|
;;
|
|
67)
|
|
msg="No contacts in storage. Add a contact first. Run \`contact help\` for more information"
|
|
;;
|
|
esac
|
|
echo >&2 "Error: $msg"
|
|
exit $1
|
|
}
|
|
rebuild() {
|
|
check-files
|
|
files=$(for f in *; do printf "%s: %s\n" "$f" "$(sed ':a;N;$!ba;s/\n/; /g' "$f")"; done)
|
|
mkdir -p "$HOME"/.cache
|
|
echo "$files" > "$HOME"/.cache/contact-cache
|
|
}
|
|
getcache() {
|
|
if [ ! -f "$HOME/.cache/contact-cache" ]; then
|
|
rebuild
|
|
fi
|
|
echo "$(< "$HOME"/.cache/contact-cache)"
|
|
}
|
|
getprop() {
|
|
if [ ! -f "$1" ]; then
|
|
error 64
|
|
fi
|
|
properties="$(< "$1")"
|
|
if [ -n "$3" ]; then
|
|
properties="$(echo "$properties" | grep "$3")"
|
|
fi
|
|
if [ -n "$2" ]; then
|
|
val=$(echo "$properties" | fzf -e -f "$2=")
|
|
else
|
|
val=$(echo "$properties" | fzf)
|
|
fi
|
|
val="$(echo "${val}" | sed 's/.*=//g')"
|
|
echo "$val"
|
|
}
|
|
getall() {
|
|
val="$(fzf -e -f "$2=" < "$1")"
|
|
list=""
|
|
while read -r line; do
|
|
list+="${line#*=}\n"
|
|
done <<< "$val"
|
|
echo -e "$list"
|
|
}
|
|
getfile() {
|
|
set -e
|
|
files="$(getcache)"
|
|
if [ -n "$1" ]; then
|
|
ret=$(echo "$files" | fzf -f "$1")
|
|
file=$(echo "$ret" | head -n1)
|
|
else
|
|
file=$(echo "$files" | fzf)
|
|
fi
|
|
file=$(echo "$file" | cut -d":" -f1)
|
|
if [ ! -f "$file" ]; then
|
|
error 64
|
|
fi
|
|
echo "$file"
|
|
}
|
|
edit() {
|
|
file="$1"
|
|
if [ -n "$EDITOR" ]; then
|
|
$EDITOR "$file"
|
|
else
|
|
vi "$file"
|
|
fi
|
|
filter "$file"
|
|
rename "$file"
|
|
}
|
|
filter() {
|
|
file="$1"
|
|
sed '/^$/d' "$file" > "$file.new"
|
|
mv "$file.new" "$file"
|
|
}
|
|
rename() {
|
|
file="$1"
|
|
filter "$file"
|
|
name=$(getprop "$file" "name")
|
|
if [ -z "$name" ]; then
|
|
error 65
|
|
fi
|
|
if [ "$cdir/$name" != "$file" ]; then
|
|
if [ -f "$name" ]; then
|
|
error 66
|
|
fi
|
|
mv "$file" "$name"
|
|
if [ -d ".git" ]; then
|
|
git rm "$file" > /dev/null 2>&1 || :
|
|
fi
|
|
fi
|
|
if [ -d ".git" ]; then
|
|
git add "$name" || :
|
|
git commit -m "Updated $name" > /dev/null 2>&1 || :
|
|
fi
|
|
rebuild
|
|
}
|
|
delete() {
|
|
file="$1"
|
|
rm "$file"
|
|
if [ -d ".git" ]; then
|
|
git rm "$file" > /dev/null || :
|
|
git commit -m "Deleted $file" > /dev/null 2>&1 || :
|
|
fi
|
|
rebuild
|
|
}
|
|
check-files() {
|
|
if [ -z "$(ls -A)" ]; then
|
|
error 67
|
|
fi
|
|
}
|
|
mutt-aliases() {
|
|
check-files
|
|
for f in *; do
|
|
name=$(getprop "$f" "name")
|
|
mails=$(getprop "$f" "email")
|
|
if [ -n "$mails" ]; then
|
|
count=0
|
|
echo "$mails" | while read mail; do
|
|
nick=$(getprop "$f" "nick")
|
|
if [ -z "$nick" ]; then
|
|
nick="$name"
|
|
fi
|
|
if [ "$count" -gt 0 ]; then
|
|
nick="${nick} $count"
|
|
fi
|
|
# Replace space with underscore
|
|
nick="${nick// /_}"
|
|
# Lowercase the string
|
|
nick="${nick,,}"
|
|
count=$((count + 1))
|
|
printf "alias %s %s <%s>\n" "$nick" "$name" "$mail"
|
|
done
|
|
fi
|
|
done
|
|
}
|
|
|
|
vcf-export() {
|
|
check-files
|
|
for f in *; do
|
|
name=$(getprop "$f" "name")
|
|
lastname=$(echo "$name" | rev | cut -d' ' -f1 | rev)
|
|
firstname=$(echo "$name" | cut -d' ' -f1)
|
|
if [ "$lastname" = "$firstname" ]; then
|
|
lastname=""
|
|
fi
|
|
nick=$(getall "$f" "nick")
|
|
mail=$(getall "$f" "email")
|
|
cell=$(getall "$f" "mobile")
|
|
work=$(getall "$f" "work")
|
|
home=$(getall "$f" "home")
|
|
phone=$(getall "$f" "phone")
|
|
address=$(getprop "$f" "address" | head -n1)
|
|
zip=$(getprop "$f" "zip" | head -n1)
|
|
city=$(getprop "$f" "city" | head -n1)
|
|
country=$(getprop "$f" "country" | head -n1)
|
|
birthday=$(getprop "$f" "birthday" | sed -e 's/\.//g' -e 's/-//g')
|
|
eol="\r\n"
|
|
out="BEGIN:VCARD${eol}"
|
|
out+="VERSION:3.0${eol}"
|
|
out+="N:$lastname;$firstname;;;${eol}"
|
|
out+="FN:$name${eol}"
|
|
if [ -n "$birthday" ]; then
|
|
out+="BDAY:$birthday${eol}"
|
|
fi
|
|
while read -r e; do
|
|
if [ -n "$e" ]; then
|
|
out+="TEL:$e${eol}"
|
|
fi
|
|
done <<< "$phone"
|
|
while read -r e; do
|
|
if [ -n "$e" ]; then
|
|
out+="TEL;TYPE=CELL:$e${eol}"
|
|
fi
|
|
done <<< "$cell"
|
|
while read -r e; do
|
|
if [ -n "$e" ]; then
|
|
out+="TEL;TYPE=WORK:$work${eol}"
|
|
fi
|
|
done <<< "$work"
|
|
while read -r e; do
|
|
if [ -n "$e" ]; then
|
|
out+="TEL;TYPE=HOME:$e${eol}"
|
|
fi
|
|
done <<< "$home"
|
|
if [ -n "$address" ] || [ -n "$city" ] || [ -n "$zip" ] || [ -n "$country" ]; then
|
|
out+="ADR;HOME:;;${address};${city};;${zip};$country${eol}"
|
|
fi
|
|
while read -r e; do
|
|
if [ -n "$e" ]; then
|
|
out+="EMAIL;TYPE=INTERNET;TYPE=PREF;TYPE=HOME:$e${eol}"
|
|
fi
|
|
done <<< "$mail"
|
|
while read -r e; do
|
|
if [ -n "$e" ]; then
|
|
out+="X-ANDROID-CUSTOM:vnd.android.cursor.item/nickname;$e;1;;;;;;;;;;;;;${eol}"
|
|
fi
|
|
done <<< "$nick"
|
|
out+="END:VCARD${eol}"
|
|
out+="${eol}"
|
|
echo -ne $out
|
|
done
|
|
}
|
|
template="name=
|
|
email=
|
|
mobile="
|
|
|
|
set -e
|
|
cdir="$HOME"/.contacts
|
|
mkdir -p "$cdir"
|
|
cd "$cdir"
|
|
command="$1"
|
|
if [ "$command" = "add" ]; then
|
|
tmp=$(mktemp)
|
|
echo "$template" > "$tmp"
|
|
edit "$tmp"
|
|
elif [ "$command" = "edit" ]; then
|
|
file=$(getfile "$2")
|
|
edit "$cdir/$file"
|
|
elif [ "$command" = "delete" ]; then
|
|
file=$(getfile "$2")
|
|
delete "$file"
|
|
elif [ "$command" = "getfile" ]; then
|
|
file=$(getfile "$2")
|
|
echo "$file"
|
|
elif [ "$command" = "rename-all" ]; then
|
|
for f in *; do
|
|
rename "$cdir/$f"
|
|
done
|
|
rebuild
|
|
elif [ "$command" = "rebuild" ]; then
|
|
rebuild
|
|
elif [ "$command" = "vcf-export" ]; then
|
|
vcf-export
|
|
elif [ "$command" = "mutt-aliases" ]; then
|
|
mutt-aliases
|
|
elif [ "$command" = "git" ]; then
|
|
"$@"
|
|
elif [ "$command" = "help" ]; then
|
|
help
|
|
elif [ "$command" = "get" ]; then
|
|
file=$(getfile "$2")
|
|
property=$(getprop "$file" "$3")
|
|
echo "$property"
|
|
elif [ "$command" = "getfiltered" ]; then
|
|
file=$(getfile)
|
|
property=$(getprop "$file" "" "$2")
|
|
echo "$property"
|
|
elif [ "$command" = "" ]; then
|
|
file=$(getfile)
|
|
property=$(getprop "$file")
|
|
echo "$property"
|
|
else
|
|
help-short >&2
|
|
printf >&2 '\nRun `contact help` for more information\n'
|
|
exit 100
|
|
fi
|