#!/bin/sh
#
# Opennet Firmware
#
# Copyright 2010 Rene Ejury <opennet@absorb.it>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# 	http://www.apache.org/licenses/LICENSE-2.0
#


# include helper functions
# shellcheck source=opennet/packages/on-core/files/usr/lib/opennet/on-helper.sh
. "${IPKG_INSTROOT:-}/usr/lib/opennet/on-helper.sh"


print_status() {
	local service_name
	local host_description
	local port
	local age
	local status
	local timestamp
	local active
	local offset
	local quality
	local now
	local sorting
	local format_string
	now=$(get_uptime_minutes)
	sorting=$(get_service_sorting)
	format_string='%6s %-34s %18s %7s %4s\n'

	# shellcheck disable=SC2059
	printf "$format_string" "active" "IP" "Quality" "VPN" "Age"
	get_services "gw" | sort_services_by_priority | while read -r service_name; do
		host_description=$(get_service_value "$service_name" "host")
		# haenge den Port an den Hostnamen, falls es nicht der Standard-Port ist
		port=$(get_service_value "$service_name" "port")
		[ "$port" != "$DEFAULT_MIG_PORT" ] && host_description="$host_description:$port"
		if uci_is_true "$(get_service_value "$service_name" "disabled" "false")"; then
			# der Dienst wird ignoriert
			# shellcheck disable=SC2059
			printf "$format_string" "" "$host_description" "disabled" "" ""
		elif [ -z "$(get_service_value "$service_name" "distance")" ]; then
			# der Dienst ist nicht erreichbar
			# shellcheck disable=SC2059
			printf "$format_string" "" "$host_description" "unreachable" "" ""
		else
			# der Dienst wurde nicht abgeschaltet
			timestamp=$(get_service_value "$service_name" "status_timestamp")
			if [ -n "$timestamp" ]; then
				age=$((now-timestamp))
			else
				age=
			fi
			status=$(get_service_value "$service_name" "status")
			if [ "$sorting" = "hop" ] || [ "$sorting" = "etx" ]; then
				offset=$(get_service_value "$service_name" "offset")
				quality=$(get_distance_with_offset "$service_name")
				if echo "$quality" | grep -q "^0"; then
					quality=$(printf "%.6f" "$quality")
				else
					quality=$(printf "%.1f" "$quality")
				fi
				[ -z "$offset" ] && offset=0
				[ "$offset" -gt 0 ] && offset="+$offset"
				[ "$offset" -ne 0 ] && quality="($offset) $quality"
			elif [ "$sorting" = "manual" ]; then
				quality=$(get_service_value "$service_name" "rank")
			fi
			# Begrenzung auf eine Nachkommastalle
			connection_state=$(get_openvpn_service_state "$service_name")
			if [ "$connection_state" = "active" ]; then
				active="*"
			elif [ "$connection_state" = "connecting" ]; then
				active="?"
			else
				active=""
			fi
			# shellcheck disable=SC2059
			printf "$format_string" "$active" "$host_description" "$quality" "$status" "$age"
		fi
	done
}


print_usage() {
	echo
	echo "*** vpn_status supports the following actions: ***"
	echo "add_gw IP [PORT]    - manually add a gateway"
	echo "move_top IP [PORT]  - move a gateway to the top of the priority list"
	echo "move_up IP [PORT]   - move a gateway one step up"
	echo "move_down IP [PORT] - move a gateway one step down"
	echo "status              - show all VPN gateways and their status"
	echo "start               - start the VPN tunnel"
	echo "stop                - stop the VPN tunnel"
	echo "restart             - restart the VPN tunnel"
}


_get_gateway_service_name() {
	local host="$1"
	local port="$2"
	get_services "gw" | if [ -n "$port" ]; then
		filter_services_by_value "host" "$host" "port" "$port"
	else
		filter_services_by_value "host" "$host"
	fi | tail -1
}


# Bewege ein Gateway in der Liste
move_top()	{ move_service_top	"$1" "gw"; }
move_up()	{ move_service_up	"$1" "gw"; }
move_down()	{ move_service_down	"$1" "gw"; }


add_gw() {
	# shellcheck disable=SC2086
	trap 'error_trap add_gw "$*"' EXIT
	local ipaddr="$1"
	local port="${2:-$DEFAULT_MIG_PORT}"
	notify_service "manual" "gw" "openvpn" "$ipaddr" "$port" "udp" "/" >/dev/null
}


ACTION=help
[ $# -ge 1 ] && ACTION=$1 && shift

case "$ACTION" in
	move_top|move_up|move_down)
		{ [ $# -lt 1 ] || [ $# -gt 2 ]; } && echo >&2 "ERROR: '$ACTION' requires one or two parameters" && exit 1
		host="$1"
		port="${2:-}"
		service_name=$(_get_gateway_service_name "$host" "$port")
		if [ -n "$service_name" ]; then
			"$ACTION" "$service_name"
		else
			echo >&2 "No gateway service related to host '$host' found."
		fi
	;;
	add_gw)
		{ [ $# -lt 1 ] || [ $# -gt 2 ]; } && echo >&2 "ERROR: '$ACTION' requires one or two parameters" && exit 1
		host="$1"
		port="${2:-}"
		"$ACTION" "$host" "$port"
	;;
	status)
		print_status
	;;
	start|stop|restart)
		# leider ist diese Funktion etwas grob: eventuell koennen mehr Instanzen beeinflusst werden, als gewollt
		/etc/init.d/openvpn "$ACTION"
	;;
	help|--help)
		print_usage
	;;
	*)
		print_usage >&2
		exit 1
	;;
esac

exit 0
