# init script functions library for macos

ZAPRET_BASE=${ZAPRET_BASE:-/opt/zapret}
ZAPRET_RW=${ZAPRET_RW:-"$ZAPRET_BASE"}
ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"}
. "$ZAPRET_CONFIG"
. "$ZAPRET_BASE/common/base.sh"
. "$ZAPRET_BASE/common/pf.sh"
. "$ZAPRET_BASE/common/list.sh"
. "$ZAPRET_BASE/common/custom.sh"
CUSTOM_DIR="$ZAPRET_RW/init.d/macos"

IPSET_DIR=$ZAPRET_BASE/ipset
. "$IPSET_DIR/def.sh"

PIDDIR=/var/run
[ -n "$TPPORT" ] || TPPORT=988
[ -n "$TPPORT_SOCKS" ] || TPPORT=987
[ -n "$WS_USER" ] || WS_USER=daemon
TPWS_WAIT="--bind-wait-ifup=30 --bind-wait-ip=30"
TPWS_WAIT_SOCKS6="$TPWS_WAIT --bind-wait-ip-linklocal=30"
[ -n "$TPWS" ] || TPWS="$ZAPRET_BASE/tpws/tpws"

CUSTOM_SCRIPT="$ZAPRET_BASE/init.d/macos/custom"
[ -f "$CUSTOM_SCRIPT" ] && . "$CUSTOM_SCRIPT"

run_daemon()
{
	# $1 - daemon number : 1,2,3,...
	# $2 - daemon
	# $3 - daemon args
	# use $PIDDIR/$DAEMONBASE$1.pid as pidfile
	local DAEMONBASE="$(basename "$2")"
	local PIDFILE="$PIDDIR/$DAEMONBASE$1.pid"
	local ARGS="--daemon --pidfile=$PIDFILE $3"
	[ -f "$PIDFILE" ] && pgrep -qF "$PIDFILE" && {
		echo Already running $1: $2
		return 0
	}
	echo "Starting daemon $1: $2 $ARGS"
	"$2" $ARGS
}
stop_daemon()
{
	# $1 - daemon number : 1,2,3,...
	# $2 - daemon
	# use $PIDDIR/$DAEMONBASE$1.pid as pidfile

	local PID
	local DAEMONBASE="$(basename "$2")"
	local PIDFILE="$PIDDIR/$DAEMONBASE$1.pid"
	[ -f "$PIDFILE" ] && read PID <"$PIDFILE"
	[ -n "$PID" ] && {
		echo "Stopping daemon $1: $2 (PID=$PID)"
		kill $PID
		rm -f "$PIDFILE"
	}
	return 0
}
do_daemon()
{
	# $1 - 1 - run, 0 - stop
	on_off_function run_daemon stop_daemon "$@"
}

tpws_apply_binds()
{
	local o
	[ "$DISABLE_IPV4" = "1" ] || o="--bind-addr=127.0.0.1"
	[ "$DISABLE_IPV6" = "1" ] || {
		for i in lo0 $IFACE_LAN; do
			o="$o --bind-iface6=$i --bind-linklocal=force $TPWS_WAIT"
		done
	}
	eval $1="\"\$$1 $o\""
}
tpws_apply_socks_binds()
{
	local o

	[ "$DISABLE_IPV4" = "1" ] || o="--bind-addr=127.0.0.1"
	[ "$DISABLE_IPV6" = "1" ] || o="$o --bind-addr=::1"
	
	for lan in $IFACE_LAN; do
	    [ "$DISABLE_IPV4" = "1" ] || o="$o --bind-iface4=$lan $TPWS_WAIT"
	    [ "$DISABLE_IPV6" = "1" ] || o="$o --bind-iface6=$lan --bind-linklocal=unwanted $TPWS_WAIT_SOCKS6"
	done
	eval $1="\"\$$1 $o\""
}

wait_interface_ll()
{
	echo waiting for an ipv6 link local address on $1 ...
	"$TPWS" --bind-wait-only --bind-iface6=$1 --bind-linklocal=force $TPWS_WAIT
}
wait_lan_ll()
{
	[ "$DISABLE_IPV6" != "1" ] && {
		for lan in $IFACE_LAN; do
			wait_interface_ll $lan >&2 || {
				echo "wait interface failed on $lan"
				return 1
			}
		done
	}
	return 0
}
get_ipv6_linklocal()
{
	ifconfig $1 | sed -nEe 's/^.*inet6 (fe80:[a-f0-9:]+).*/\1/p'
}


zapret_do_firewall()
{
	# $1 - 1 - add, 0 - del

	[ "$1" = 1 -a -n "$INIT_FW_PRE_UP_HOOK" ] && $INIT_FW_PRE_UP_HOOK
	[ "$1" = 0 -a -n "$INIT_FW_PRE_DOWN_HOOK" ] && $INIT_FW_PRE_DOWN_HOOK

	if [ "$1" = "1" ] ; then
		pf_anchor_root || return 1
		pf_anchors_create
		pf_anchors_load || return 1
		pf_enable
	else
		pf_anchors_clear
	fi

	[ "$1" = 1 -a -n "$INIT_FW_POST_UP_HOOK" ] && $INIT_FW_POST_UP_HOOK
	[ "$1" = 0 -a -n "$INIT_FW_POST_DOWN_HOOK" ] && $INIT_FW_POST_DOWN_HOOK

	return 0
}
zapret_apply_firewall()
{
	zapret_do_firewall 1 "$@"
}
zapret_unapply_firewall()
{
	zapret_do_firewall 0 "$@"
}
zapret_restart_firewall()
{
	zapret_unapply_firewall "$@"
	zapret_apply_firewall "$@"
}


standard_mode_daemons()
{
	local opt

	if [ "$1" = "1" ] && [ "$DISABLE_IPV4" = "1" ] && [ "$DISABLE_IPV6" = "1" ] ; then
		echo "both ipv4 and ipv6 are disabled. nothing to do"
	else
		[ "$TPWS_ENABLE" = 1 ] && check_bad_ws_options $1 "$TPWS_OPT" && {
			opt="--user=root --port=$TPPORT"
			tpws_apply_binds opt
			opt="$opt $TPWS_OPT"
			filter_apply_hostlist_target opt
			do_daemon $1 1 "$TPWS" "$opt"
		}
		[ "$TPWS_SOCKS_ENABLE" = 1 ] && {
			opt="--socks --user=$WS_USER --port=$TPPORT_SOCKS"
			tpws_apply_socks_binds opt
			opt="$opt $TPWS_SOCKS_OPT"
			filter_apply_hostlist_target opt
			do_daemon $1 2 "$TPWS" "$opt"
		}
	fi
}

zapret_do_daemons()
{
	# $1 - 1 - run, 0 - stop

	standard_mode_daemons $1
	custom_runner zapret_custom_daemons $1

	return 0
}
zapret_run_daemons()
{
	zapret_do_daemons 1 "$@"
}
zapret_stop_daemons()
{
	zapret_do_daemons 0 "$@"
}
zapret_restart_daemons()
{
	zapret_stop_daemons "$@"
	zapret_run_daemons "$@"
}