#!/bin/bash -efu
### This file is covered by the GNU General Public License,
### which should be included with libshell as the file LICENSE.
### All copyright information are listed in the COPYING.

#exec 2>/tmp/pinentry.log
#set -x

VERSION='1.0'
FLAVOR='bash'

############################### PATCH #################################
. ~/.config/bemenu/env.sh
#######################################################################

keyinfo=''
error=''
timeout=0
touch_file=''

readonly def_desc='Enter password for GPG key'
readonly def_prompt='Password:'
readonly def_title='GPG Key Credentials'
readonly def_repeat='Confirm password for GPG key'
readonly def_labelok='OK'
readonly def_labelnotok='Do not do this'
readonly def_labelcancel='Cancel'

# from /usr/include/gpg-error.h
readonly GPG_ERR_NO_ERROR=0
readonly GPG_ERR_TIMEOUT=62
readonly GPG_ERR_CANCELED=99
readonly GPG_ERR_NOT_CONFIRMED=114
readonly GPG_ERR_ASS_PARAMETER=280

strerror()
{
	case "$1" in
		$GPG_ERR_NO_ERROR)      echo "Success" ;;
		$GPG_ERR_TIMEOUT)       echo "Timeout" ;;
		$GPG_ERR_CANCELED)      echo "Operation cancelled" ;;
		$GPG_ERR_NOT_CONFIRMED) echo "Not confirmed" ;;
		$GPG_ERR_ASS_PARAMETER) echo "IPC parameter error" ;;
	esac
}

assuan_result()
{
	[ "$1" -gt 0 ] &&
		echo -n "ERR $(( 5 << 24 | $1 )) " ||
		echo -n "OK "
	strerror "$1"
}

cmd_settimeout()
{
	[ -n "${1##0*}" ] && [ -n "${1##*[!0-9]*}" ] && [ "$1" -gt 0 ] 2>/dev/null ||
		return 0
	timeout="$1"
	assuan_result $GPG_ERR_NO_ERROR
}

cmd_setkeyinfo()
{
	[ "$1" = "--clear" ] &&
		keyinfo="" ||
		keyinfo="$1"
	assuan_result $GPG_ERR_NO_ERROR
}

set_text_variable()
{
	printf -v "$1" "${2//%/\\x}"
	eval "set_$1=1"
	assuan_result $GPG_ERR_NO_ERROR
}

cmd_setoption()
{
	case "$1" in
		default-prompt=*) set_text_variable prompt "${1#*=}"      ;;
		default-ok=*)     set_text_variable labelok "${1#*=}"     ;;
		default-cancel=*) set_text_variable labelcancel "${1#*=}" ;;
		touch-file=*)
			touch_file="${1#*=}"
			assuan_result $GPG_ERR_NO_ERROR
			;;
		*)
			assuan_result $GPG_ERR_NO_ERROR
			;;
	esac
}

cmd_getinfo()
{
	case "$1" in
		version)
			echo "D $VERSION"
			assuan_result $GPG_ERR_NO_ERROR
			;;
		pid)
			echo "D $BASHPID"
			assuan_result $GPG_ERR_NO_ERROR
			;;
		flavor)
			echo "D $FLAVOR"
			assuan_result $GPG_ERR_NO_ERROR
			;;
		ttyinfo)
			echo "D - - - - $(id -u 2>/dev/null || echo 0)/$(id -g 2>/dev/null || echo 0) -"
			assuan_result $GPG_ERR_NO_ERROR
			;;
		*)
			assuan_result $GPG_ERR_ASS_PARAMETER
			;;
	esac
}

cmd_getpin()
{
	local ret=0 result output password=1 repeatpassword=3

	output="$(
		echo -n "|"
############################### PATCH #################################
		bemenu \
			--password indicator \
			--prompt "${prompt:-$def_prompt}" \
			</dev/null | tr -d '\n'
		ret=${PIPESTATUS[0]}
#		yad \
#			--splash \
#			--no-markup \
#			--title="${title:-$def_title}" \
#			--form \
#			--separator="\n" \
#			--field="${desc:-$def_desc}:LBL" \
#			--field="${prompt:-$def_prompt}:H" \
#			${set_repeat:+--field="${repeat:-$def_repeat}:LBL"} \
#			${set_repeat:+--field="${prompt-$def_prompt}:H"} \
#			${error:+--field="$error:LBL"} \
#			--button="${labelok:-$def_labelok}:0" \
#			--button="${labelcancel:-$def_labelcancel}:1" \
#			--timeout="${timeout:-0}" \
#			</dev/null || ret=$?
######################################################################
		echo -n "|"
		exit $ret
	)" || ret=$?

	set_error='' error=''

	case "$ret" in
		1)  assuan_result $GPG_ERR_CANCELED; return 0; ;;
		70) assuan_result $GPG_ERR_TIMEOUT;  return 0; ;;
	esac

	output="${output#|}"
	output="${output%|}"

############################### PATCH #################################
	declare -A result
	result[$password]="$output"
	result[$repeatpassword]="$output"
#	readarray -t result <<<"$output"
#	output=''
#
#######################################################################
	if [ -n "${set_repeat-}" ]; then
		set_repeat='' repeat=''

		if [ "${result[$password]}" != "${result[$repeatpassword]}" ]; then
			cmd_confirm --one-button "${repeaterror:-Error: Passwords did not match.}"
			assuan_result $GPG_ERR_NOT_CONFIRMED
			return
		fi
		echo "S PIN_REPEATED"
	fi

	[ -z "$touch_file" ] ||
		touch "$touch_file"

	echo "D ${result[$password]}"
	assuan_result $GPG_ERR_NO_ERROR
}

cmd_confirm()
{
	local ret=0 showmsg='' showcfm=1

	if [ "$1" = '--one-button' ]; then
		shift
		showmsg=1
		showcfm=
	fi

	yad \
		--splash \
		--no-markup \
		--title="${title:-$def_title}" \
		--text="${1:-${desc:-$def_desc}}" \
		${showmsg:+--button="${labelok:-$def_labelok}:0"} \
		${showcfm:+${error:+--field="$error:LBL"}} \
		--timeout="${timeout:-0}" \
		< /dev/null ||
		ret=$?

	set_error='' error=''

	case "$ret" in
		0)  assuan_result $GPG_ERR_NO_ERROR ;;
		1)  assuan_result $GPG_ERR_CANCELED ;;
		70) assuan_result $GPG_ERR_TIMEOUT ;;
		*)  assuan_result $GPG_ERR_NOT_CONFIRMED ;;
	esac
}

echo "OK Your orders please"

while :; do
	read -r cmd args 2>/dev/null ||
		continue

	#echo >&2 "$cmd: $args"

	case "$cmd" in
		BYE)
			echo "OK closing connection"
			exit 0
			;;
		GETPIN)         cmd_getpin ;;
		CONFIRM)        cmd_confirm "$args" ;;
		MESSAGE)        cmd_confirm --one-button ;;
		GETINFO)        cmd_getinfo "$args" ;;
		SETTIMEOUT)     cmd_settimeout "$args" ;;
		SETKEYINFO)     cmd_setkeyinfo "$args" ;;
		OPTION)         cmd_setoption "$args" ;;
		SETDESC)        set_text_variable desc "$args" ;;
		SETPROMPT)      set_text_variable prompt "$args" ;;
		SETTITLE)       set_text_variable title "$args" ;;
		SETOK)          set_text_variable labelok "$args" ;;
		SETCANCEL)      set_text_variable labelcancel "$args" ;;
		SETNOTOK)       set_text_variable labelnotok "$args" ;;
		SETERROR)       set_text_variable error "$args" ;;
		SETREPEAT)      set_text_variable repeat "$args" ;;
		SETREPEATERROR) set_text_variable repeaterror "$args" ;;
		*)
			assuan_result $GPG_ERR_NO_ERROR
			;;
	esac
done