#!/bin/dash
# jamesbond 2015
# license: GNU GPL Version 3 or later.
#
# simple tester for mailcap
# programs: we only handle the common cases, %s and %t
# options: we only handle the common cases, "copiousoutput" and "test"
# line continuation in mailcap is not supported.
#
MIMES=$HOME/.mime.types:/etc/mime.types:/usr/share/etc/mime.types:/usr/local/etc/mime.types
MAILCAPS=$HOME/.mailcap:/etc/mailcap:/usr/share/etc/mailcap:/usr/local/etc/mailcap

# $1-file extension, out: mimetype
lookup_mimetype() {
	local ext="$1"
	OIFS="$IFS"; IFS=":"; set -- $MIMES; IFS="$OIFS"
	mimetype=$(echo "$@" | xargs cat 2>/dev/null | awk -v ext=" $ext" '$0 ~ ext { print $1; exit }')
}

# $1-file, out: encoding
guess_encoding() {
	case "$(file --mime-type -b $1)" in
		*gzip*)   encoding=gz ;;
		*bzip2*)  encoding=bzip2 ;;
		*xz*) encoding=xz ;;
		*) encoding=plain ;;
	esac
}

# $1-encoding, out: decoder
lookup_decoder() {
	case $1 in
		gzip) decoder="gunzip -c" ;;
		bzip2) decoder="bunzip2 -c" ;;
		xz) decoder="unxz -c" ;;
		*) decoder="cat" ;;
	esac
}

# $1-mime type, out: program options
lookup_mailcap() {
	local type="$1" line
	OIFS="$IFS"; IFS=":"; set -- $MAILCAPS; IFS="$OIFS"
	line=$(echo "$@" | xargs cat 2>/dev/null | awk -F";" -v type="$type" \
	'$1 == type { for (i=2;i<=NF;i++) {print $i ";"}; exit }')
	program=${line%%;*}
	options=${line#*;}
}

# $1-program $2-options $3-mimetype $4-decoder $5-file
process() {
	local mode=stdout program="$1" options"=$2" mimetype="$3" decoder="$4" file="$5"
	
	# program: process %s and %t
	case "$program" in
		*%s*) mode=file 
			  program=$(echo "$program" | sed "s;%s;\"$file\";")
			  ;;
	esac
	program=$(echo "$program" | sed "s;%t;$mimetype;")
	
	# options: process copiousoutput and test
	local pager=cat tester=true opt
	while [ "$options" ]; do
		opt=${options%%;*}; options=${options#*;}
		[ "$opt" = "$options" ] && options=""
		case "$opt" in
			*copiousoutput*) pager=less ;;
			*test*)
				tester=${opt#*test=}
				tester=$(echo "$tester" | sed "s;%s;\"$file\";")
				tester=$(echo "$tester" | sed "s;%t;$mimetype;")
				;;
		esac
	done
	
	# all done, now execute
	if eval "$tester"; then
		case $mode in
			file) eval $program ;;
			stdout) $decoder "$file" | $program
		esac
	fi
}


usage() {
cat << EOF
Usage: test-mailcap [MIME-TYPE:[ENCODING:]]FILE ...
  ENCODING is one of gzip, bzip2, xz, or plain
EOF
}

# $1-[MIME-TYPE:[ENCODING:]]FILE
run() {
	local p="$1" file encoding mimetype
	file="${p##*:}"; p="${p%:*}"; [ "$p" = "$file" ] && p=""; mimetype="$p"
	encoding="${p##*:}"; p="${p%:*}"; [ "$p" = "$encoding" ] && encoding="" || 
	mimetype="$p"
	ext="${file##*.}"; [ $file = $ext ] && ext=""
	[ -z "$mimetype" ] && lookup_mimetype "$ext"
	[ -z "$encoding" ] && guess_encoding "$file"
	lookup_mailcap "$mimetype"
	process "$program" "$options" "$mimetype" "$decoder" "$file"	
}

### main ###
case "$1" in
	""|--help|-h) usage; exit 1 ;;
esac
while [ "$1" ]; do
	run "$1"
	shift
done
