#!/bin/sh

. /etc/control.d/functions
. alterator-service-functions

CONFIG="${CONFIG:-/etc/security/pam_pkcs11/pkcs11_eventmgr.conf}"

CA_INSERT="/usr/bin/card-inserted"
CA_REMOVE="/usr/bin/card-removed"
SERVICE="pkcs11-eventmgr"

new_summary "PKCS11 event actions"
new_help 'other' "User specified or package default actions"
new_help 'disabled' "Event monitring is disabled"
new_help 'card_actions' "Actions handled by the $CA_INSERT and $CA_REMOVE alternatives"

read_event_action() {
	local ev="$1"; shift
	sed -n -e "/^[[:space:]]*event[[:space:]]\\+$ev[[:space:]]*{/,/^[[:space:]]*}[#[:space:]]*\$/ {
		/^[[:space:]]*action[[:space:]]*=/,/;[[:space:]]*\$/ {
			H;
			/;[[:space:]]*\$/! d;
			g;
			s/^[[:space:]]*action[[:space:]]*=[[:space:]]*//;
			s/\\n/ /g;
			s/\",[[:space:]]\\+\"/\", \"/g;
			s/\",[[:space:]]\\+;/\",;/;
			s/;[[:space:]]*\$//p;
			s/^.*\$//; h;
		}
	}" -- "$CONFIG"
}

comment_event_action() {
	local ev="$1"; shift
	sed -i -e "/^[[:space:]]*event[[:space:]]\\+$ev[[:space:]]*{/,/^[[:space:]]*}[#[:space:]]*\$/ {
		/^[[:space:]]*\\(#[[:space:]]*\\)*action[[:space:]]*=/,/;[[:space:]]*\$/ {
			/^[[:space:]]*}[#[:space:]]*\$/ { p; d };
			s/^[#[:space:]]*/\\t\\t/;
			H;
			/;[[:space:]]*\$/! d;
			g;
			s/^[[:space:]]*\\(#[[:space:]]*\\)*action[[:space:]]*=[[:space:]]*/\\t\\t#action = /;
			s/\\n/ /g;
			s/\",[[:space:]]\\+\"/\", \"/g;
			s/\",[[:space:]]\\+;/\",;/;
			x; s/^.*\$//; x;
		}
	}" -- "$CONFIG"
}

add_event_action() {
	local ev="$1"; shift
	local act="$1"; shift
	act="$(echo "$act" | sed -e 's,/,\\/,g')"
	comment_event_action "$ev"
	sed -i -e "/^[[:space:]]*event[[:space:]]\\+$ev[[:space:]]*{/,/^[[:space:]]*}[#[:space:]]*\$/ {
		/^[[:space:]]*}[#[:space:]]*\$/ {
			s/^.*}\\([^}]*\\)\$/\\t\\taction = \"$act\";\\n\\t}\\1/;
		}
	}" -- "$CONFIG"
}

delete_event_action() {
	local ev="$1"; shift
	comment_event_action "$ev"
	sed -i -e "/^[[:space:]]*event[[:space:]]\\+$ev[[:space:]]*{/,/^[[:space:]]*}[#[:space:]]*\$/ {
		/^[[:space:]]*\\#action[[:space:]]*=/ {
			x; /^.\\+\$/ p; d;
		}
	}" -- "$CONFIG"
}

restore_event_action() {
	local ev="$1"; shift
	comment_event_action "$ev"
	sed -i -e "/^[[:space:]]*event[[:space:]]\\+$ev[[:space:]]*{/,/^[[:space:]]*}[#[:space:]]*\$/ {
		/^[[:space:]]*\\#action[[:space:]]*=/ {
			x; /^.\\+\$/ p; d;
		}
		/^[[:space:]]*}[#[:space:]]*\$/ {
			x; s/#action/action/p; x;
		}
	}" -- "$CONFIG"
}

## Main

REQUEST="$*"

action_command() {
	local act="$1"; shift
	act="${act#\"}"
	act="${act%%\",*}"
	act="${act%\"}"
	act="${act%% *}"
	echo "$act"
}

read_oninsert() {
	oninsert="$(action_command "$(read_event_action 'card_insert')")"
	if [ -z "$oninsert" ]; then
		return 1
	elif [ ! -x "$oninsert" ]; then
		echo "Warning: $oninsert is configured for 'insert' but isn't available!" >&2
		return 2
	fi
}

read_onremove() {
	onremove="$(action_command "$(read_event_action 'card_remove')")"
	if [ -z "$onremove" ]; then
		return 1
	elif [ ! -x "$onremove" ]; then
		echo "Warning: $onremove is configured for 'remove' but isn't available!" >&2
		return 2
	fi
}

is_enabled() {
    if sd_service_exists "$SERVICE" && \
            ! sd_service_control "$SERVICE" 'is-enabled'
    then
        return 1
    fi
    
    if sysv_service_exists "$SERVICE" && \
            ! sysv_service_control "$SERVICE" 'is-enabled'
    then
        return 1
    fi

    return 0
}

ret=0; startstop=

case "$REQUEST" in
	help|'help '*)
		control_help "${REQUEST#help}"
		;;
	list)
		control_list
		;;
	summary)
		control_summary
		;;
	status)
		if is_enabled; then
			read_oninsert ||:
			read_onremove ||:
			if [ "$oninsert" = "$CA_INSERT" -a "$onremove" = "$CA_REMOVE" ]
			then
				echo "card_actions"
			else
				echo "other"
			fi
		else
			echo "disabled"
		fi
		;;
	card_actions)
		startstop="$SERVICE"
		if [ -x "$CA_INSERT" ]; then
			if [ "$oninsert" != "$CA_INSERT" ]; then
				add_event_action 'card_insert' "$CA_INSERT"
			fi
		else
			echo "Error: $CA_INSERT is not available!" >&2
			ret=1
		fi
		if [ -x "$CA_REMOVE" ]; then
			if [ "$onremove" != "$CA_REMOVE" ]; then
				add_event_action 'card_remove' "$CA_REMOVE"
			fi
		else
			echo "Error: $CA_REMOVE is not available!" >&2
			ret=1
		fi
		;;
	other)
		startstop="$SERVICE"
		if [ "$oninsert" != "$CA_INSERT" ]; then
			delete_event_action 'card_insert'
			restore_event_action 'card_insert'
			read_oninsert || ret=$?
		fi
		if [ "$onremove" != "$CA_INSERT" ]; then
			delete_event_action 'card_remove'
			restore_event_action 'card_remove'
			read_onremove || ret=$?
		fi
		;;
	disabled)
		service_control "$SERVICE" 'disable'
		;;
esac

if [ -n "$startstop" ]; then
	sact=
	if [ $ret -eq 0 ]; then
		sact='enable'
	else
		sact='disable'
	fi
	for name in $startstop; do
		service_control "$name" "$sact"
	done
fi
