#!/bin/sh /etc/rc.common
# Copyright (c) 2016-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.

# set (s)hellcheck exceptions
# shellcheck disable=all

START=25
USE_PROCD=1

extra_command "scan" "[<radio>|<ifname>] Scan for available nearby uplinks"
extra_command "setup" "[<iface>] [<zone>] [<metric>] Setup the travelmate uplink interface, by default 'trm_wwan' with firewall zone 'wan' and metric '100'"

trm_init="/etc/init.d/travelmate"
trm_service="/usr/bin/travelmate-service.sh"
trm_funlib="/usr/lib/travelmate-functions.sh"

if [ -z "${IPKG_INSTROOT}" ]; then
	if [ "${action}" = "boot" ] && "${trm_init}" running; then
		exit 0
	fi
	. "${trm_funlib}"
fi

boot() {
	if [ -s "${trm_pidfile}" ]; then
		: >"${trm_pidfile}"
	fi
	rc_procd start_service
}

start_service() {
	if "${trm_init}" enabled; then
		if [ "${action}" = "boot" ]; then
			return 0
		fi
		procd_open_instance "travelmate"
		procd_set_param command "${trm_service}" "${@:-"${action}"}"
		procd_set_param pidfile "${trm_pidfile}"
		procd_set_param nice "$(uci_get travelmate global trm_nice "0")"
		procd_set_param stdout 0
		procd_set_param stderr 1
		procd_close_instance
	else
		f_log "err" "travelmate service autostart is disabled"
	fi
}

reload_service() {
	f_rmpid
}

stop_service() {
	rc_procd "${trm_service}" stop
}

status_service() {
	f_getstatus
}

scan() {
	local result radio="${1:-radio0}"

	case "${radio}" in
	*[!a-z0-9]*) return 1 ;;
	esac

	result="$(f_scan "${radio}" full)"
	if [ -z "${result}" ]; then
		: >"${trm_tmpfile}"
		mv -f "${trm_tmpfile}" "${trm_scanfile}"
		return 0
	fi

	printf "%s\n" "${result}" | "${trm_awkcmd}" '
	{
		quality = $1
		channel = $2
		bssid   = $3
		rsn     = $4
		cipher  = $5
		auth    = $6
		ssid = ""
		for (i=7; i<=NF; i++) {
			ssid = ssid $i " "
		}
		sub(/[ \t]+$/, "", ssid)
		printf "%3s %3s %17s %-12s %-10s %-10s %s\n",
			quality, channel, bssid, rsn, cipher, auth, ssid
	}' | "${trm_sortcmd}" -rn >"${trm_tmpfile}"

	mv -f "${trm_tmpfile}" "${trm_scanfile}"
}

setup() {
	local rc cnt net iface input="${1:-"trm_wwan"}" zone="${2:-"wan"}" metric="${3:-"100"}"

	input="${input//[!a-zA-Z0-9_]/}"
	zone="${zone//[!a-zA-Z0-9_]/}"
	metric="${metric//[!0-9]/}"
	iface="$(uci_get travelmate global trm_iface)"

	if [ -z "${input}" ] || { [ -n "${iface}" ] && [ "${iface}" = "${input}" ]; }; then
		return 1
	fi

	if [ -n "$(uci_get network ${input})" ]; then
		uci -q batch <<-EOC
			set travelmate.global.trm_enabled="1"
			set travelmate.global.trm_iface="${input}"
			commit travelmate
		EOC
		rc="0"
	else
		uci -q batch <<-EOC
			set travelmate.global.trm_enabled="1"
			set travelmate.global.trm_iface="${input}"
			set network.${input}="interface"
			set network.${input}.proto="dhcp"
			set network.${input}.metric="${metric}"
			set network.${input}6="interface"
			set network.${input}6.device="@${input}"
			set network.${input}6.proto="dhcpv6"
			commit travelmate
			commit network
		EOC
		rc="0"
	fi

	cnt="0"
	zone_name="$(uci_get firewall @zone[${cnt}] name)"
	while [ -n "${zone_name}" ]; do
		if [ "${zone_name}" = "${zone}" ]; then
			net="$(uci_get firewall @zone[${cnt}] network)"
			case " ${net} " in
			*" ${input} "*) ;;
			*) uci -q add_list firewall.@zone[${cnt}].network="${input}" ;;
			esac
			case " ${net} " in
			*" ${input}6 "*) ;;
			*) uci -q add_list firewall.@zone[${cnt}].network="${input}6" ;;
			esac
			[ -n "$(uci -q changes "firewall")" ] && uci_commit firewall
			break
		fi
		cnt="$((cnt + 1))"
		zone_name="$(uci_get firewall @zone[${cnt}] name)"
	done

	cnt="0"
	while uci -q show wireless.@wifi-iface[${cnt}] >/dev/null 2>&1; do
		if uci -q show wireless.@wifi-iface[${cnt}] | grep -qE "^wireless.trm_uplink[0-9]+="; then
			uci_set wireless @wifi-iface[${cnt}] network "${input}"
		fi
		cnt="$((cnt + 1))"
	done
	[ -n "$(uci -q changes "wireless")" ] && uci_commit wireless

	/etc/init.d/network reload >/dev/null 2>&1
	/etc/init.d/firewall reload >/dev/null 2>&1
	"${trm_init}" restart
	return "${rc}"
}

service_triggers() {
	local iface delay

	iface="$(uci_get travelmate global trm_iface)"
	delay="$(uci_get travelmate global trm_triggerdelay "5")"
	PROCD_RELOAD_DELAY=$((delay * 1000))

	if [ -n "${iface}" ]; then
		procd_add_interface_trigger "interface.*.down" "${iface}" "${trm_init}" reload
	fi
	procd_add_raw_trigger "interface.*.up" "${PROCD_RELOAD_DELAY}" "${trm_init}" start
	procd_add_config_trigger "config.change" "travelmate" "${trm_init}" restart
}
