#!/usr/bin/env bash
# bogomark - mark all files in a Maildir as ham or spam using bogofilter.

PATH="$HOME/code/bin:$PATH"

. lib.bash || exit
: ${XDG_RUNTIME_DIR:="$XDG_CACHE_HOME"}

mail_base="$HOME/Mail"
fs_layout=0

lock() {
	exec {lockfd}>"$XDG_RUNTIME_DIR/bogomark.lock"
	if ! flock -xn $lockfd; then
		die "another instance is running"
	fi
}

unlock() {
	exec {lockfd}>&-
	rm -f "$XDG_RUNTIME_DIR/bogomark.lock"
}

purge() {
	local max_age=$1 dir=$2
	find "$mail_base/$(maildir "$dir")/cur" -type f -mtime +$max_age -delete
}

maildir() {
	if (( fs_layout )); then
		echo "$1"
	else
		echo ".${1//'/'/'.'}"
	fi
}

mark() {
	local OPTION OPTIND OPTARG
	local mode= remove=false onlyseen=false changed=0
	while getopts ":knprsS" OPT; do
		case $OPT in
		n) mode="-n"; smode="mark-ham";;
		p) mode="-p"; smode="process";;
		r) remove=true;;
		s) mode="-s"; smode="mark-spam";;
		S) onlyseen=true;;
		*) lib:die_getopts;;
		esac
	done

	debug "mode is '$smode' [$mode]"

	dirs=()
	while [[ "${!OPTIND}" ]]; do
		dirs+=("${!OPTIND}")
		(( OPTIND++ ))
	done

	if (( ${#dirs[@]} == 0 )) || [[ -z "$mode" ]]; then
		usage
	fi

	local tag flags rest
	lock
	for dir in "${dirs[@]}"; do
		debug "marking '$dir'"
		dir=$(maildir "$dir")
		path="$mail_base/$dir"
		debug "... at '$path'"
		for file in "$path"/{cur,new}/*; do
			basename="${file##*/}"
			flags="${basename##*:}"
			flags="${flags##*,}"

			$onlyseen && [[ $flags != *S* ]] && continue

			echo "dir=$dir action=$smode file=${file#$path/} flags=$flags remove=$remove"

			if [ "$mode" == "-p" ]; then
				addheader "$path" "$file"
				(( changed++ ))
			elif bogofilter -e $mode < "$file"; then
				if $remove; then
					rm -f "$file"
				else
					addheader "$path" "$file"
					(( changed++ ))
				fi
			fi
		done

		#if (( changed > 0 )); then
		#	true > "$path/dovecot.index.cache"
		#fi
	done
	unlock
	true
}

# filter through bogofilter, adding X-Bogosity header (-p)
addheader() {
	local maildir="$1" file="$2"
	local temp="$maildir/tmp/${file##*/}"
	if bogofilter -ep < "$file" > "$temp" && [ -s "$temp" ]; then
		ln -f "$temp" "$file" && rm -f "$temp"
	fi
}

shopt -s nullglob

if [[ $1 ]]; then
	mark "$@"
else
	# -n	ham
	# -r	remove after filtering
	# -s	spam
	# -S	only Seen
	mark -sr Junk/Spam
	mark -nr Junk/Ham
	#purge 7 Trash
fi
