summary refs log tree commit diff
path: root/bin/mailsync
diff options
context:
space:
mode:
Diffstat (limited to 'bin/mailsync')
-rwxr-xr-xbin/mailsync157
1 files changed, 157 insertions, 0 deletions
diff --git a/bin/mailsync b/bin/mailsync
new file mode 100755
index 0000000..0fcb43b
--- /dev/null
+++ b/bin/mailsync
@@ -0,0 +1,157 @@
+#!/bin/bash
+
+set -e
+[ -n "$DEBUG" ] && set -x
+
+# check requirements
+for tool in mbsync notify-send python awk gdbus iconez; do
+	if ! command -v "$tool" >/dev/null; then
+		printf '%s: %s not installed but required\n' "$(basename "$0")" "$tool" >&2
+		exit 1
+	fi
+done
+
+maildir="${HOME}/mail"
+cachefile=${XDG_CACHE_HOME}/mailsync.lastrun
+
+accounts=(gnzler hu)
+list=
+verbose=
+while getopts a:lvh opt; do
+	case "${opt}" in
+	a) accounts=("${OPTARG}") ;;
+	l) list=1 ;;
+	v) verbose=1 ;;
+	h | ?)
+		printf "usage: %s [-h] [ACCOUNT...]\n" "$(basename "$0")"
+		printf "\n"
+		printf "  -a ACCOUNTS, accunts to sync (default: \"%s\")\n" "${accounts[@]}"
+		printf "  -l list mail\n"
+		printf "  -v be verbose"
+		printf "\n"
+		exit 2
+		;;
+	esac
+done
+shift $((OPTIND - 1))
+
+if [ -n "$1" ]; then
+	accounts=("$@")
+fi
+
+notifysend() {
+	local summary=$1
+	local body=$2
+	local ico
+	shift 2
+
+	if ! printf "%s" "$*" | grep -- "-i" >/dev/null; then
+		ico="📨 "
+	fi
+
+	# -i /usr/share/icons/mdi/scalable/email-plus.svg \
+	notify-send $@ \
+		-a mailsync \
+		-c audible \
+		"${ico:-}${summary}" "${body}"
+}
+
+decode() {
+	python -c 'import sys;import email.header;print(("".join(list(map(lambda s: s[0] if (type(s[0]) == str) else s[0].decode(s[1] or "utf-8"), email.header.decode_header(((sys.stdin.readlines() or [""])[0]).strip()))))))'
+}
+
+handle_msg() {
+	local msg=$1
+	local from
+	local subject
+	local listid
+	local ico
+
+	from=$(sed ':a; N; $!b a; s/\n\s\{1,\}/ /g' "${msg}" | awk '/^From:/{print}' | cut -d: -f2 | decode)
+	subject=$(sed ':a; N; $!b a; s/\n\s\{1,\}/ /g' "${msg}" | awk '/^Subject:/{print}' | cut -d: -f2 | decode)
+	listid=$(sed ':a; N; $!b a; s/\n\s\{1,\}/ /g' "${msg}" | awk '/^List-ID:/{print}' | cut -d: -f2 | decode)
+	if [ -n "${listid}" ]; then
+		subject="${subject}\n<span alpha='90%' size='small'>~> $(echo "${listid}" | sed -e 's|<|\&lt;|g' -e 's|>|\&gt;|g')</span>"
+		ico="$(iconez -sn email-multiple-outline)"
+	else
+		ico="$(iconez -sn email-receive-outline)"
+	fi
+	notifysend "${from}" "${subject}" -i "${ico}" -t 2000
+}
+
+list_msg() {
+	local acct=$2
+	local args=(-type f -not -name '\.*')
+	local cachefile="${cachefile}.${acct}"
+
+	find "${maildir}"/"${acct}"/{INBOX,lists}/new/ "${args[@]}" 2>/dev/null || true
+
+	# local cur_or_new=${1:-new}
+	# if [ "${cur_or_new}" = "new" ]; then
+	# 	find "${maildir}"/"${acct}"/{INBOX,lists}/"${cur_or_new}"/ "${args[@]}" 2>/dev/null || true
+	# else
+	# 	find "${maildir}"/"${acct}"/*/"${cur_or_new}"/ "${args[@]}" 2>/dev/null || true
+	# fi
+}
+
+run_notify() {
+	local acct=$1
+	local new_mail
+
+	new_mail=$(list_msg new "${acct}")
+	if [ -n "${new_mail}" ]; then
+		local num
+		num="$(echo "${new_mail}" | grep -c INBOX)"
+		# always print INBOX messages
+		for msg in $(echo "${new_mail}" | grep INBOX); do handle_msg "$msg"; done
+
+		# everything else, limit to 5, just print the count otherwise
+		num="$(echo "${new_mail}" | grep -c -v INBOX)"
+		notifysend "${acct}: new" "Found ${num} new mail" -i "$(iconez -sn email-receive-outline)"
+		[ "${num}" -gt 5 ] && return
+		for msg in $(echo "${new_mail}" | grep -v INBOX); do handle_msg "$msg"; done
+	fi
+}
+
+run_sync() {
+	local acct=$1
+
+	# exit if we're already running
+	pgrep mbsync >/dev/null && {
+		echo "mbsync is already running."
+		notifysend "mailsync stopped" "mbsync is already running" -i "$(iconez -sn email-off-outline)"
+		return
+	}
+
+	# persistent notification
+	id=$(notifysend "${acct}: fetching new mail..." "running mbsync" -i "$(iconez -sn email-sync-outline)" --print-id --expire-time=0)
+
+	mbsync_args=
+	[ -n "${verbose}" ] && mbsync_args="--verbose"
+	mbsync $mbsync_args --config="$HOME/.config/mbsyncrc" "$acct"
+	clear-notification "$id"
+	# create cachefile
+	touch "${cachefile}.${acct}"
+
+	# index new messages
+	command notmuch >/dev/null 2>&1 && notmuch new
+}
+
+# only list new mail, don't sync
+if [ -z "${accounts[*]}" ]; then
+	echo "no account specified" >&2
+	exit 1
+fi
+
+for acct in "${accounts[@]}"; do
+	(
+		if [ -n "${list}" ]; then
+			list_msg "${list}" "${acct}"
+			exit 0 # exit ()& subshell
+		fi
+		run_sync "${acct}"
+		run_notify "${acct}"
+	) &
+done
+
+wait