#!/bin/sh
#
# Dieses Skript enthaelt Funktionen, die fuer Updates altes Firmware-Versionen notwendig sind.
# Alle Funktionen muessen idempotent sein.
#
# Dieses Skript wird nach jedem Booten ausgeführt.
# Damit ermöglichen wir das Laden eines alten Backups auf eine neue Firmware.
# Ausserdem wird dieses Skript als Teil des uci-defaults-Konzepts beim ersten Booten nach einer
# Aktualisierung ausgefuehrt. Dies ist erforderlich, um alle notwendigen Vorbereitungen fuer
# die erste Ausfuehrung des "on-core"-Init-Skripts zu treffen (z.B. crontab-Einrichtung).
#


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


# wandele Leerzeichen-getrennte "option"-Eintraege in "list"-Eintraege um
_convert_uci_option_to_list() {
	trap 'error_trap _convert_uci_option_to_list "$*"' EXIT
	local config="$1"
	local optname="$2"
	local filename="/etc/config/$config"
	# Zeilen der Form "  option $optname 'foo bar'" werden in mehrere "  option $optname '$ITEM'"-Zeilen verwandelt
	# Wir korrigieren dabei sowohl "option"- als auch "list"-Elemente sofern ihr Inhalt Leerzeichen enthält.
	# Dies ist notwendig, da schon vor dem Ausführen dieses Migrationsskripts beim Booten "uci add_list" angewandt
	# wird - dies verwandelt die Leerzeichen-separierte alte "option" in eine unveränderte "list". Also müssen wir
	# leider blind nachkorrigieren :(
	awk '{
		if ((($1 == "option") || ($1 == "list")) && ($2 == "'"$optname"'")) {
			i = 3
			while (i <= NF) {
				gsub(/'\''/, "", $i)
				printf "	list %s '"'%s'"'\n", $2, $i
				i++
			}
		} else {
			print $0
		}}' "$filename" | update_file_if_changed "$filename" && apply_changes "$config"
	true
}


# Gelegentlich ändert openwrt die Definition einzelner Variablen. Dies müssen wir via Migration nachbereiten.
migrate_uci_definition_changes() {
	trap 'error_trap migrate_uci_definition_changes "$*"' EXIT
	# vor Barrier Breaker war "firewall.ZONE.network" eine "option" - anschliessed wurde es zur "list"
	# TODO insert your migrations here
	#   e.g. _convert_uci_option_to_list "firewall" "network"
}


## @fn remove_wifidog_config()
## @brief Lösche die nicht mehr verwendete Konfiguration von "wifidog" und "on-wifidog".
## @details Die Konfiguration enthält keine relevanten Inhalte mehr, die zu übertragen wären.
remove_wifidog_config() {
	trap 'error_trap remove_wifidog_config "$*"' EXIT
	rm -f /etc/config/on-wifidog
	uci_delete luci.flash_keep.wifidog
	rm -f /etc/wifidog.conf
}


## @fn enable_uhttpd_redirect()
## @brief Aktiviere die automatische https-Weiterleitung
## @details Bei einer Aktualisierung von v0.5.1 auf v0.5.2 fehlt diese Einstellung andernfalls, da
##   zuvor keine https-Unterstützung in der Firmware aktiviert war.
enable_uhttpd_redirect() {
	trap 'error_trap enable_uhttpd_redirect "$*"' EXIT
	local uci_key="uhttpd.main.redirect_https"
	[ -n "$(uci_get "$uci_key")" ] && return 0
	uci set "$uci_key=1"
	uci commit uhttpd
	reload_config
}


## @fn guess_previously_used_modules()
## @brief Versuche nach der Aktualisierung von einer Version vor v0.5.2 die zuvor verwendeten Module zu erraten.
## @details Die Firmware-Versionen vor v0.5.2 enthielten alle Module vorinstalliert. Ab v0.5.2 werden Module bei
##   Bedarf nachinstalliert. Beim Übergang von Komplett- zu Bedarfsinstallation versuchen wir die vorherige
##   Nutzungsform zu erraten und die dazu passende Modulliste zu speichern.
guess_previously_used_modules() {
	trap 'error_trap guess_previously_used_modules "$*"' EXIT
	local module
	# falls bereits etwas in der uci-Sektion gespeichert wurde, ist keine Nachbereitung noetig
	[ -n "$(uci -q show "on-core.modules")" ] && return 0
	# Zweig anlegen
	uci set "on-core.modules=modules"
	# prüfe ob relevante Dateien vorhanden sind, die die jeweiligen Module benutzen würden
	[ -e "/etc/openvpn/opennet_user/on_aps.crt" ] \
		&& uci_add_list "on-core.modules.installed" "on-openvpn"
	[ -e "/etc/openvpn/opennet_ugw/on_aps.crt" ] \
		&& uci_add_list "on-core.modules.installed" "on-usergw"
	[ -e "/etc/wifidog.conf" ] \
		&& uci_add_list "on-core.modules.installed" "on-captive-portal"
	[ -e "/etc/xinetd.d/munin" ] \
		&& uci_add_list "on-core.modules.installed" "on-monitoring"
	# enable default modules
	for module in $DEFAULT_MODULES_ENABLED; do
		enable_on_module "$module"
	done
}


## @fn auto_enable_on_free_network()
## @brief In v0.5.2 wurde das on-free-Netzwerk als auto=0 konfiguriert. Darauffolgende Versionen
##        erwarten auto=1.
auto_enable_on_free_network() {
	[ -z "${ZONE_FREE:-}" ] && return 0
	local uci_prefix="network.$NETWORK_FREE"
	[ -n "$(uci_get "$uci_prefix")" ] && uci set "${uci_prefix}.auto=1"
	apply_changes network
}


## @fn rename_gpio_switch_poe_passthrough
## @brief Im Dezember 2015 (siehe 67e1c8701215724dcee9fabcbd7a397ea76e1a9d) wurde im openwrt-
##        Repository das Config-Sektions-Präfix 'gpio_switch_' von steuerbaren GPIO-Signalen
##        entfernt. Somit wollen wir auf Geräten mit alten Einstellungen diese über die neu
##        generierten Vorgabeeinstellungen schreiben.
rename_gpio_switch_poe_passthrough() {
	# keine alten Einstellungen? Nichts zu tun ...
	[ -z "$(uci_get "system.gpio_switch_poe_passthrough")" ] && return 0
	# sicherheitshalber neu generierten Zustand loeschen (der Schaltzustand wird "aus" sein)
	uci_delete "system.poe_passthrough"
	# alte Einstellungen an neue Stelle schreiben
	uci rename system.gpio_switch_poe_passthrough=poe_passthrough
	uci commit system
	reload_config
}


## @fn rename_tun_to_tun_on_user
## @brief Vor v0.5.4 wurde das Netzwerk-Interface des Nutzer-VPN durch openvpn mit dem automatisch
##        vergebenen Namen "tun0" bezeichnet.
##        Aufgrund potentieller Uneindeutigkeit durch Timing-Probleme heißt das Interface seit
##        v0.5.4 "tun-on-user".
rename_tun_to_tun_on_user() {
	[ "$(uci_get "network.on_vpn.device")" = "tun0" ] || return 0
	uci set "network.on_vpn.device=tun-on-user"
	uci commit network
	reload_config
}


## @fn update_olsrd_plugin_versions()
## @brief Aktualisiere die in der olsrd-Konfigurationsdatei angegebenen Versionen der Plugins.
## @details Leider verwendet olsrd ein starres Konzept der Plugin-Referenzierung
##   (inkl. so-Version). Dies benoetigt manuelle Anpassungen.
update_olsrd_plugin_versions() {
	trap 'error_trap update_olsrd_plugin_versions "$*"' EXIT
	local uci_prefix
	local configured_library
	for uci_prefix in $(find_all_uci_sections "olsrd" "LoadPlugin"); do
		configured_library=$(uci_get "${uci_prefix}.library")
		while read -r library_name library_version; do
			echo "$configured_library" | grep -q "^$library_name"'\.so\.' || continue
			[ "$configured_library" = "$library_name.so.$library_version" ] && continue
			uci set "${uci_prefix}.library=$library_name.so.$library_version"
		done <<EOF
			olsrd_jsoninfo 1.1
			olsrd_nameservice 0.4
			olsrd_txtinfo 1.1
EOF
	done
	apply_changes olsrd
}


## @fn update_uhttpd_configuration()
## @brief Setze fehlende Einstellungen in /etc/config/uhttpd.
## @details Seit v0.5.5 sind in der Upstream-Konfiguration die beiden Einstellungen
##     "uhttpd.main.lua_prefix" und "uhttpd.main.lua_handler" gesetzt. Bei der Aktualisierung von
##     einer älteren Firmware fehlen diese Einstellungen naturgemäß.
##     Ohne diese Einstellungen wird ein HTTP-Request des root-Pfads ("/") mit einer Umleitung nach
##     /luci beantwortet, obwohl uhttpd (per default) auf /cgi-bin/luci lauscht.
update_uhttpd_configuration() {
	trap 'error_trap update_uhttpd_configuration "$*"' EXIT
	[ -e "/etc/config/uhttpd" ] || return 0
	[ -z "$(uci_get "uhttpd.main.lua_prefix")" ] || return 0
	[ -z "$(uci_get "uhttpd.main.lua_handler")" ] || return 0
	uci set "uhttpd.main.lua_prefix=/luci"
	uci set "uhttpd.main.lua_handler=/usr/lib/lua/luci/sgi/uhttpd.lua"
	uci commit uhttpd
	reload_config
}


migrate_uci_definition_changes
# die Pruefung muss vor der Loeschung der wifidog-Konfiguration stattfinden
guess_previously_used_modules
remove_wifidog_config
enable_uhttpd_redirect
auto_enable_on_free_network
rename_gpio_switch_poe_passthrough
rename_tun_to_tun_on_user
update_olsrd_plugin_versions
update_uhttpd_configuration
