#!/bin/sh /etc/rc.common
# Copyright (C) 2017 Michael Heimpold

START=99
STOP=10

USE_PROCD=1
PROG=/usr/sbin/ser2net

STATICCFGFILE="/etc/ser2net.yaml"
DYNAMICCFGFILE="/tmp/ser2net.yaml"

list_cb_append() {
	local var="$2"
	local value="$1"
	local sep="${3:-,}"

	eval "export ${NO_EXPORT:+-n} -- \"$var=\${$var:+\${$var}\${value:+\$sep}}\$value\""
}

ser2net_default() {
	local cfg="$1"
	local key val
	local baudrate parity databits stopbits

	config_get baudrate "$cfg" speed
	if [ -n "$baudrate" ]; then
		config_get parity "$cfg" parity
		case "$parity" in
			[Nn]one) parity=n ;;
			[Oo]dd) parity=o ;;
			[Ee]ven) parity=e ;;
			"") ;;
			*) return 1
		esac

		if [ -n "$parity" ]; then
			config_get databits "$cfg" databits 8
			[ "$databits" -ge 5 ] && [ "$databits" -le 9 ] || return 1

			config_get stopbits "$cfg" stopbits 1
			case "$stopbits" in
				1) ;;
				2) ;;
				*) return 1
			esac
		fi

		echo "default:"
		echo "  name: speed"
		echo "  value: $baudrate${parity:+$parity$databits$stopbits}"
	fi

	for key in chardelay_scale chardelay_min; do
		config_get val "$cfg" "$key"
		[ -n "$val" ] || continue
		key=`echo "$key" | tr '_' '-'`
		echo "default:"
		echo "  name: $key"
		echo "  value: $val"
	done

	for key in chardelay deassert_CTS_DCD_DSR_on_connect hangup_when_done kickolduser \
	           local nobreak remctl rtscts telnet_brk_on_sync xonxoff; do
		case "$key" in
			remctl) key=rfc2217 ;;
		esac
		config_get_bool val "$cfg" "$key"
		[ -n "$val" ] || continue
		key=`echo "$key" | tr '_' '-'`
		[ "$val" -eq 0 ] && val="false" || val="true"
		echo "default:"
		echo "  name: $key"
		echo "  value: $val"
	done

	echo
}

ser2net_controlport() {
	local cfg="$1"
	local enabled host port

	config_get_bool enabled "$cfg" enabled 0
	[ "$enabled" -eq 0 ] && return 0

	config_get host "$cfg" host
	config_get port "$cfg" port
	[ "$port" -ge 1 ] && [ "$port" -le 65535 ] || return 1

	echo "admin:"
	echo "  accepter: tcp,${host:+$host,}$port"

	echo
}

ser2net_led() {
	local cfg="$1"
	local driver device state duration

	config_get driver "$cfg" driver sysfs
	config_get device "$cfg" device
	[ -z "$device" ] && return 1
	config_get duration "$cfg" duration
	config_get state "$cfg" state

	echo "led: &$cfg"
	echo "  driver: $driver"
	echo "  options:"
	echo "    device: \"$device\""
	[ -n "$duration" ] && echo "    duration: $duration"
	[ -n "$state" ] && echo "    state: $state"

	echo
}

ser2net_proxy() {
	local cfg="$1"
	local enabled port protocol timeout device baudrate databits parity stopbits
	local key boolval options custom_options
	local echo_options=1

	config_get_bool enabled "$cfg" enabled 0

	config_get device "$cfg" device
	[ -z "$device" ] && return 1

	config_get port "$cfg" port
	[ "$port" -ge 1 ] && [ "$port" -le 65535 ] || return 1

	config_get protocol "$cfg" protocol
	case "$protocol" in
		raw)
			protocol="tcp"
			;;
		rawlp)
			protocol="tcp"
			options="wronly"
			;;
		telnet)
			protocol="telnet,tcp"

			config_get_bool boolval "$cfg" remctl 0
			[ "$boolval" -eq 1 ] && protocol="telnet(rfc2217),tcp"
			;;
		off)
			enabled=0
			;;
		*) return 1
	esac

	config_get baudrate "$cfg" baudrate
	if [ -n "$baudrate" ]; then
		config_get parity "$cfg" parity
		case "$parity" in
			[Nn]one) parity=n ;;
			[Oo]dd) parity=o ;;
			[Ee]ven) parity=e ;;
			"") ;;
			*) return 1
		esac

		if [ -n "$parity" ]; then
			config_get databits "$cfg" databits 8
			[ "$databits" -ge 5 ] && [ "$databits" -le 9 ] || return 1

			config_get stopbits "$cfg" stopbits 1
			case "$stopbits" in
				1) ;;
				2) ;;
				*) return 1
			esac
		fi
	fi

	config_get timeout "$cfg" timeout 0

	for key in rtscts local xonxoff nobreak hangup_when_done; do
		config_get_bool boolval "$cfg" "$key"
		[ -n "$boolval" ] || continue
		key=`echo "$key" | tr '_' '-'`
		options="${options:+$options,}$key"
		[ "$boolval" -eq 0 ] && options="$options=false"
	done

	config_list_foreach "$cfg" options list_cb_append custom_options

	echo "connection: &$cfg"
	echo "  accepter: $protocol,$port"
	echo "  timeout: $timeout"
	[ "$enabled" -eq 0 ] && echo "  enable: off"
	echo "  connector: serialdev,$device${baudrate:+,$baudrate${parity:+$parity$databits$stopbits}}${options:+,$options}${custom_options:+,$custom_options}"

	for key in led_tx led_rx; do
		config_get val "$cfg" "$key"
		[ -n "$val" ] || continue
		[ "$echo_options" -eq 1 ] && echo "  options:" && echo_options=0
		key=`echo "$key" | tr '_' '-'`
		echo "    $key: *$val"
	done

	for key in chardelay telnet_brk_on_sync kickolduser; do
		config_get_bool boolval "$cfg" "$key"
		[ -n "$boolval" ] || continue
		[ "$echo_options" -eq 1 ] && echo "  options:" && echo_options=0
		key=`echo "$key" | tr '_' '-'`
		echo "    $key: $boolval"
	done

	echo
}

start_service() {
	local enabled

	config_load ser2net

	config_get_bool enabled global enabled 0
	[ "$enabled" -gt 0 ] || return 0

	cat "$STATICCFGFILE" - 2>/dev/null <<-EOF > "$DYNAMICCFGFILE"

	#
	# Following part is auto-generated from UCI settings in /etc/config/ser2net
	#
	EOF

	config_foreach ser2net_default default >> "$DYNAMICCFGFILE"
	config_foreach ser2net_led led >> "$DYNAMICCFGFILE"
	config_foreach ser2net_controlport controlport >> "$DYNAMICCFGFILE"
	config_foreach ser2net_proxy proxy >> "$DYNAMICCFGFILE"

	procd_open_instance
	procd_set_param command "$PROG" -n -c "$DYNAMICCFGFILE"
	procd_set_param file "$DYNAMICCFGFILE"
	procd_close_instance
}

service_triggers() {
	procd_add_reload_trigger "ser2net"
}
