#!/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"


# bis Version v0.4-5: openvpn.opennet_user.comp_lzo=1
# seit Version v0.5 muss die Einstellung einen der folgenden Werte haben: yes/no/adaptive
# bzw. seit Version v0.5 gibt es Sektion nicht mehr (openvpn.opennet_user)
# Status in v0.4-5:
#   ~# uci show | grep lzo
#   on-usergw.opennet_ugw.comp_lzo=1
#   openvpn.opennet_user.comp_lzo=1
#   openvpn.opennet_ugw_erina_on_i_de.comp_lzo=1
#   openvpn.opennet_ugw_subaru_on_i_de.comp_lzo=1
coerce_openvpn_comp_lzo() {
	trap 'error_trap coerce_openvpn_comp_lzo "$*"' EXIT
	local new_value
	local key
	# wir wissen nicht genau, ob on-usergw und openvpn existiert - also lieber vorsichtig fragen
	(uci -q show openvpn; uci -q show on-usergw) | grep '\.comp_lzo=[01]$' | while read -r line; do
		new_value=no
		echo "$line" | grep -q "1$" && new_value=yes
		key=$(echo "$line" | cut -f 1 -d =)
		uci set "$key=$new_value"
	done
	if [ -n "$(uci -q changes openvpn)" ] || uci changes | grep -q '^on-usergw\.'; then
		msg_info "MIGRATION: coerce_openvpn_comp_lzo"
		uci changes | grep -q '^on-usergw\.' && uci commit on-usergw
		apply_changes openvpn
	fi
}


# bis Version v0.4-5: die Opennet-Firmware hat die /etc/passwd durch einen Symlink auf /etc/etc_preset/passwd ersetzt
# Bei einem Update wird das symlink-Ziel ersetzt und somit gibt es keine Nutzerdatenbank mehr.
# Dies verhindert jeden telnet/ssh-Login-Versuch. Lediglich das Web-Interface ist nutzbar.
fix_passwd_broken_symlink() {
	trap 'error_trap fix_passwd_broken_symlink "$*"' EXIT
	local target=/etc/passwd
	if [ -h "$target" ] && [ ! -e "$target" ]; then
		msg_info "MIGRATION: fix_passwd_broken_symlink"
		rm "$target"
		# ein huebscheres here-Document mit Tabulator-Bereinigung ("<<-") funktioniert leider nicht mit busybox
		cat >"$target" << EOF
root:x:0:0:root:/root:/bin/ash
daemon:*:1:1:daemon:/var:/bin/false
ftp:*:55:55:ftp:/home/ftp:/bin/false
network:*:101:101:network:/var:/bin/false
nobody:*:65534:65534:nobody:/var:/bin/false
EOF
		# Ein paar Dienste schlugen aufgrund der fehlenden Nutzerdatenbank fehl.
		# Ein reboot waere schoen - aber kann zukuenftig eventuell irgendwann zu einer Schleife fuehren.
		# Also: manuell einzelne Dienste neu starten.
		/etc/init.d/dnsmasq restart
	fi
}


# bis Version v0.4-5 war /etc/rc.local ein Symlink nach /etc/etc_presets/rc.local
# In den folgenden Versionen gibt es kein /etc/etc_presets/ mehr.
# Der Symlink kann dann durch den ueblichen Kommentar-Text ersetzt werden.
fix_rclocal_broken_symlink() {
	trap 'error_trap fix_rclocal_broken_symlink "$*"' EXIT
	local target=/etc/rc.local
	# die Datei existiert, bzw. der Symlink zeigt nicht ins Leere
	[ -e "$target" ] && return 0
	# falls die Datei kein Symlink ist, dann fassen wir sie lieber nicht an
	[ -h "$target" ] || return 0
	# die Datei ist ein kaputter Symlink - wir ersetzen sie
	rm -f "$target"
	# ein huebscheres here-Document mit Tabulator-Bereinigung ("<<-") funktioniert leider nicht mit busybox
	cat >"$target" << EOF
# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.

exit 0
EOF
	chmod 644 "$target"
}



# 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"
	_convert_uci_option_to_list "firewall" "network"
}


# bis Version v0.4-5: "firewall reload" fuehrte auch die "include"-Dateien aus (z.B. /etc/firewall.opennet)
# Ab Version v0.5 verwenden wir diese Datei nicht mehr.
# Beispiel (v0.4-5):
#  ~# uci show firewall | grep @include
#  firewall.@include[0]=include
#  firewall.@include[0].path=/etc/firewall.opennet
#  firewall.@include[1]=include
#  firewall.@include[1].path=/etc/firewall.user
fix_firewall_reload() {
	trap 'error_trap fix_firewall_reload "$*"' EXIT
	local filename=/etc/firewall.opennet
	local uci_prefix
	for uci_prefix in $(find_all_uci_sections "firewall" "include"); do
		if [ "$(uci_get "${uci_prefix}.path")" = "$filename" ]; then
			# gesamte "include"-Abzweigung loeschen
			uci_delete "$uci_prefix"
			apply_changes "firewall"
			rm -f "$filename"
			break
		fi
	done
	return 0
}


# bis Version 0.4-5 sind die folgenden beiden Firewall-Einstellungen gesetzt:
#   firewall.zone_on_vpn.forward=ACCEPT
#   firewall.zone_on_mesh.forward=ACCEPT
# Diese erlauben die Paketweiterleitung aus unerwuenschten Netzen heraus.
disable_unwanted_forward() {
	trap 'error_trap disable_unwanted_forward "$*"' EXIT
	local zone_name
	local uci_prefix
	local changed=0
	for uci_prefix in $(find_all_uci_sections firewall zone "forward=ACCEPT"); do
		zone_name=$(uci_get "${uci_prefix}.name")
		# eventuell ist ZONE_TUNNEL nicht definiert (falls on-openvpn nicht installiert ist)
		if [ "$zone_name" = "$ZONE_MESH" ] || [ "$zone_name" = "${ZONE_TUNNEL:-on_vpn}" ]; then
			uci set "${uci_prefix}.forward=REJECT"
			changed=1
		fi
	done
	if [ "$changed" = "1" ]; then
		# sicherstellen, dass die als Ersatz fuer "forward=ACCEPT" noetige Weiterleitung existiert
		add_zone_forward "$ZONE_MESH" "$ZONE_MESH"
		apply_changes "firewall"
	fi
}


# bis Version 0.4-5 wurden die folgenden Einstellungen fuer die Reihenfolge der VPN-Gateways verwendet:
# * on-openvpn.gateways.vpn_sort_criteria=metric|etx
# * on-openvpn.gateways.autosearch=on|off
# Die darauffolgenden Firrmware-Versionen verwenden stattdessen die Einstellung 'on-core.settings.service_sorting'.
transfer_vpn_sort_criteria_and_autosearch() {
	trap 'error_trap transfer_vpn_sort_criteria_and_autosearch "$*"' EXIT
	local sort_criteria
	local autosearch
	local result
	sort_criteria=$(uci_get on-openvpn.gateways.vpn_sort_criteria)
	autosearch=$(uci_get on-openvpn.gateways.autosearch)
	if [ -z "$autosearch" ] && [ -z "$sort_criteria" ]; then
		# die Einstellungen wurden bereits uebertragen
		return 0
	elif [ "$autosearch" = "off" ]; then
		result=manual
	elif [ "$sort_criteria" = "metric" ]; then
		result=hop
	else
		result=etx
	fi
	uci set "on-core.settings.service_sorting=$result"
}


# bis Version 0.4-5 verwendeten wir vollstaendige uci-Sektionen fuer die VPN-Server
# z.B. openvpn.opennet_user
remove_tunnel_openvpn_settings() {
	trap 'error_trap remove_tunnel_openvpn_settings "$*"' EXIT
	local uci_prefix=openvpn.opennet_user
	# Abbruch falls die Einstellungen bereits entfernt wurden
	[ -z "$(uci_get "$uci_prefix")" ] && return
	uci delete "$uci_prefix"
	uci commit openvpn
}


# bis Version 0.4-5 wurde folgende Zeile ausgefuehrt:
#   lua -e "require('luci.model.opennet.on_usergw') upgrade()" 2>/dev/null
# Dadurch wurden openvpn-uci-Konfigurationen (z.B. openvpn.opennet_ugw_erina_on_i_de) nach on-usergw.opennet_ugw* übertragen.
# Da die openvpn-Konfigurationen nun ein anderes Namensformat haben, loeschen wir sie.
remove_usergw_openvpn_configs() {
	trap 'error_trap remove_usergw_openvpn_configs "$*"' EXIT
	local uci_prefix
	for uci_prefix in $(find_all_uci_sections "openvpn" "openvpn" | grep '^openvpn\.opennet_ugw_'); do
		uci delete "$uci_prefix"
	done
	return 0
}


# Die uci-Sektion on-core.defaults und on-core.openssl wurde nur bis v0.4-5 verwendet.
# Anschliessend wanderten diese Einstellungen nach /usr/share/opennet/core.defaults.
# Ausserdem sind die folgenden Schluessel nach v0.4-5 nicht mehr in Verwendung:
#   on-openvpn.gateways.searchmask
#   on-openvpn.gateways.gw_dns
#   on-openvpn.gateways.gw_ntp
#   on-openvpn.gateways.better_gw
#   on-openvpn.gateways.autosearch
#   on-openvpn.gateways.vpn_nonworking_timeout
#   on-openvpn.gateways.vpn_bettergateway_timeout
#   on-openvpn.gateways.vpn_sort_criteria
#   on-openvpn.gateways.vpn_recheck_age
remove_obsolete_on_core_settings() {
	trap 'error_trap remove_obsolete_on_core_settings "$*"' EXIT
	local key
	for key in \
			on-core.defaults \
			on-core.openssl \
			on-openvpn.gateways.gateways.searchmask \
			on-openvpn.gateways.gateways.gw_dns \
			on-openvpn.gateways.gateways.gw_ntp \
			on-openvpn.gateways.gateways.better_gw \
			on-openvpn.gateways.gateways.autosearch \
			on-openvpn.gateways.gateways.vpn_nonworking_timeout \
			on-openvpn.gateways.gateways.vpn_bettergateway_timeout \
			on-openvpn.gateways.gateways.vpn_sort_criteria \
			on-openvpn.gateways.gateways.vpn_recheck_age; do
		if [ -n "$(uci_get "$key")" ]; then
			uci_delete "$key"
		fi
	done
}


# bis Version 0.4-5 wurde die Variable "on-usergw.ugwng_hna_mask" verwendet.
remove_obsolete_usergw_settings() {
	trap 'error_trap remove_obsolete_usergw_settings "$*"' EXIT
	[ -n "$(uci_get "on-usergw.ugwng_hna_mask")" ] && uci delete "on-usergw.ugwng_hna_mask"
	return 0
}


# Die uci-Einstellungen "on-openvpn.gate_XY.*" waren bis Version 0.4-5 in Verwendung.
# In den darauffolgenden Firmware-Versionen werden diese Informationen im Dateisystem gespeichert.
# Im Zweifelsfall (z.B. falls gerade keine Verbindung zum mesh existiert), werden die
# zu uebertragenden Informationen (die Offsets der Gateways oder ihre manuelle Reihenfolge) verworfen.
transfer_gateway_uci_settings() {
	trap 'error_trap transfer_gateway_uci_settings "$*"' EXIT
	local uci_prefix
	local host
	local offset
	local rank
	local service_name
	for uci_prefix in $(find_all_uci_sections "on-openvpn" "gateway"); do
		host=$(uci_get "${uci_prefix}.ipaddr")
		offset=$(uci_get "${uci_prefix}.etx_offset")
		rank="${uci_prefix#on-openvpn.gate_}"
		# ermittle alle passenden Dienste dieses Hosts (es koennen mehrere Dienste pro Host vorhanden sein)
		for service_name in $(get_services "gw" | filter_services_by_value "host" "$host"); do
			# Offset fuer automatische Sortierung uebertragen
			[ -n "$offset" ] && set_service_value "$service_name" "offset" "$offset"
			# Rang fuer manuelle Sortierung uebertragen
			[ -n "$rank" ] && [ "$rank" != "$uci_prefix" ] && set_service_value "$service_name" "rank" "$rank"
			true
		done
		uci_delete "$uci_prefix"
	done
	uci_delete on-openvpn.gateways
}


# Bis Version 0.4-5 wurde die Datei /etc/crontabs/root einfach ueberschrieben (bzw. erzeugt).
# In Version 0.5 wurde die busybox-Funktion "run-parts" verwendet. Zugunsten der separaten
# Paketierung wollen wir dies nicht mehr verwenden.
# Fortan werden die Eintraege manuell hinzugefuegt (siehe /etc/uci-defaults/on-core-init).
remove_crontab_entries() {
	trap 'error_trap remove_crontab_entries "$*"' EXIT
	local crontab_file=/etc/crontabs/root
	[ -e "$crontab_file" ] || return 0
	# Verwendung des alten shell-Skripts
	sed -i '/\/usr\/bin\/run-parts\.sh/d' "$crontab_file"
	# Verwendung der busybox-Funktion
	sed -i '/\trun-parts /d' "$crontab_file"
}


# Bis Version 0.4-5 wurde der Port des httpinfo-Plugins mit der Variable "olsrd.@LoadPlugin[1].Port" festgelegt.
# uci-typisch sind jedoch Attribute mit Kleinbuchstaben.
rename_olsrd_port_to_port() {
	trap 'error_trap rename_olsrd_port_to_port "$*"' EXIT
	local uci_prefix
	local library
	for uci_prefix in $(find_all_uci_sections "olsrd" "LoadPlugin"); do
		library="$(uci_get "${uci_prefix}.library")"
		# falsche Bibliothek?
		[ "$library" != "${library#olsrd_httpinfo}" ] || continue
		if [ -n "$(uci_get "${uci_prefix}.Port")" ]; then
			# Wert von "Port" nach "port" uebertragen; "Port" loeschen
			uci set "${uci_prefix}.port=$(uci_get "${uci_prefix}.Port")"
			uci_delete "${uci_prefix}.Port"
		fi
	done
	apply_changes olsrd
}


# Bis Version 0.4-5 gab es anscheinend die veraltete "mtu_fix"-Option in firewall-Weiterleitungen.
# Seit OpenWRT 8.09.2 befindet sich diese Option jedoch nicht mehr in den Weiterleitungen, sondern in der Zielzone.
move_mtu_fix_to_target_zone() {
	trap 'error_trap move_mtu_fix_to_target_zone "$*"' EXIT
	local uci_prefix
	local mtu_value
	local target_zone
	local zone_uci_prefix
	for uci_prefix in $(find_all_uci_sections firewall forwarding); do
		mtu_value=$(uci_get "${uci_prefix}.mtu_fix")
		# leer? Es gibt nichts zu uebertragen ...
		[ -z "$mtu_value" ] && continue
		target_zone=$(uci_get "${uci_prefix}.dest")
		zone_uci_prefix=$(find_first_uci_section firewall zone "name=$target_zone")
		# mtu-Wert uebertragen
		[ -n "$zone_uci_prefix" ] && uci set "${zone_uci_prefix}.mtu_fix=$mtu_value"
		# alten Wert loeschen
		uci_delete "${uci_prefix}.mtu_fix"
	done
	apply_changes firewall
}


# Bis Version 0.4-5 verwendeten wir ntpclient anstelle des integrierten ntpd
# Die alten Einstellungen koennen also entfernt werden, da die Hosts automatisch gewaehlt werden.
remove_ntpclient_config() {
	trap 'error_trap remove_ntpclient_config "$*"' EXIT
	# keine config-Datei? Fertig ...
	[ -e /etc/config/ntpclient ] || return 0
	# ntpclient ist installiert? Konfiguration belassen ...
	is_package_installed "ntpclient" && return 0
	rm -f /etc/config/ntpclient
}


## @fn rename_firewall_zone()
## @brief Ändere den Namen einer Firewall-Zone (definiert im alten Barrier-Breaker-Stil).
## @param old_zone Bisheriger Name der Firewall-Zone
## @param new_zone Zukünftiger Name der Firewall-Zone
## @details Alle abhängigen Firewall-Regeln (offene Ports, Weiterleitungen, Umleitungen) werden auf die neue Zone umgelenkt.
##    Die Umbenennung ist auf alte "benannte" Firewll-Zonen ausgelegt. Die Zone wird in eine neue "unbenannte" verwandelt.
rename_firewall_zone() {
	trap 'error_trap rename_firewall_zone "$*"' EXIT
	local old_zone="$1"
	local new_zone="$2"
	local uci_prefix
	local key
	uci_prefix=$(find_first_uci_section firewall zone "name=$old_zone")
	# die Zone existiert nicht (mehr)
	[ -z "$uci_prefix" ] && return 0
	# "name"-Attribut der alten Zone neu setzen
	uci set "${uci_prefix}.name=$new_zone"
	# benannte Zone in eine unbenannte umwandeln
	sed -i "s/^config zone 'zone_$old_zone'$/config zone/g" /etc/config/firewall
	# aktualisiere alle Forwardings, Redirects und Regeln
	for section in "forwarding" "redirect" "rule"; do
		for key in "src" "dest"; do
			for uci_prefix in $(find_all_uci_sections firewall "$section" "${key}=$old_zone"); do
				uci set "${uci_prefix}.${key}=$new_zone"
			done
		done
	done
	apply_changes firewall
}


## @fn move_wifidog_networks_to_captive_portal()
## @brief Änderung des Netzwerk-Namens für offene Zugangspunkte von "free" zu "on_free".
## @details Bis v0.4-5 hieß das wifidog-Netzwerk "free". Ab v0.5.2 heißt es "on_free".
move_wifidog_networks_to_captive_portal() {
	trap 'error_trap move_wifidog_networks_to_captive_portal "$*"' EXIT
	local old_name="free"
	local new_name="${NETWORK_FREE:-}"
	# das on-captive-portal-Paket ist nicht installiert - keine Aenderungen
	[ -z "$new_name" ] && return 0
	local old_interfaces
	local uci_prefix
	# das alte Interface existiert nicht? Weitermachen ...
	[ -z "$(uci_get "network.$old_name")" ] && return 0
	# neues Interface anlegen, falls es noch nicht existieren sollte
	# (das migrations-Skript wird vor dem on-captive-portal-Skript via uci-defaults ausgefuehrt)
	configure_free_network
	# die nicht-wifi-Netzwerke übertragen
	old_interfaces=$(uci_get "network.${old_name}.ifname")
	# das Interface muss immer angegeben sein (oder "none")
	uci set "network.${new_name}.ifname=${old_interfaces:-none}"
	# alle wifi-Interfaces verschieben
	for uci_prefix in $(find_all_uci_sections "wireless" "wifi-iface" "network=$old_name"); do
		uci set "${uci_prefix}.network=$new_name"
	done
	# fertig: wir ignorieren das Bridge-Attribute - es ist nicht mehr erforderlich (und selten noetig)
	uci_delete "network.$old_name"
	apply_changes network wireless
}


## @fn remove_wifidog_alias_interface()
## @brief Entferne ein Alias-Interface, das für das wifidog-Setup verwendet wurde.
## @details Bis Version 0.4-5 wurde wifidog mit einem lokalen Alias-Interface konfiguriert, um
##   die Umlenkung von Paketen via REDIRECT zu ermöglichen.
remove_wifidog_alias_interface() {
	trap 'error_trap remove_wifidog_alias_interface "$*"' EXIT
	local uci_prefix
	for uci_prefix in $(find_all_uci_sections "network" "alias" "interface=free"); do
		uci_delete "$uci_prefix"
	done
	apply_changes network
}


## @fn remove_opennet_ca_certificates_from_previous_location()
## @brief Löschung alter CA-Dateien an nicht mehr verwendeten Orten.
## @details Bis Version v0.5.1 wurden die CA-Zertifikate für die OpenVPN-Verbindungen
##   im openvpn-Verzeichnis neben den persönlichen Schlüsseln und Zertifikaten gespeichert.
##   Da diese Verzeichnisse jedoch von luci als zu erhaltender Bereich bei einem Upgrade
##   konfiguriert ist (luci.flash_keep.openvpn=/etc/openvpn), blieben diese Dateien bei einem
##   Upgrade der Firmware unverändert. Der Austausch eines CA-Zertifikats war somit nicht
##   möglich.
##   Mit der Verschiebung aller Opennet-Zertifikate an einen nicht-zu-sichernden Ort
##   (/etc/ssl/certs/opennet-initiative.de) können nun die alten CA-Zertifikate an ihrem ursprünglichen
##   Ort gelöscht werden.
##   Folgende Orte sind betroffen:
##     /etc/openvpn/opennet_user/opennet-ca.crt
##     /etc/openvpn/opennet_ugw/opennet-ca_ugws.crt
##     /etc/openvpn/opennet_vpntest/opennet-ca.crt
remove_opennet_ca_certificates_from_previous_location() {
	trap 'error_trap remove_opennet_ca_certificates_from_previous_location "$*"' EXIT
	rm -f /etc/openvpn/opennet_user/opennet-ca.crt
	rm -f /etc/openvpn/opennet_ugw/opennet-ca_ugws.crt
	rm -f /etc/openvpn/opennet_vpntest/opennet-ca.crt
}


## @fn remove_openvpn_vpntest_keydir()
## @brief Dieses Verzeichnis ist mindestens seit v0.5.2 nicht mehr in Nutzung.
remove_openvpn_vpntest_keydir() {
	trap 'error_trap remove_openvpn_vpntest_keydir "$*"' EXIT
	rm -rf /etc/openvpn/vpntest/
}


## @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 remove_pre05_usergateway_olsr_announcement()
## @brief Entferne das veraltete UGW-Announcierungsformat von Firmware v0.4-x.
##   Beispiel:
##      olsrd.cfg0c4e54.service=http://192.168.0.42:8080|tcp|ugw upload:50 download:350 ping:27
remove_pre05_usergateway_olsr_announcement() {
	trap 'error_trap remove_pre05_usergateway_olsr_announcement "$*"' EXIT
	uci -X show olsrd | grep -q '^olsrd.cfg[^.]\+.service=http://.*:8080|tcp|ugw' || return 0
	sed -i '/option service .http:\/\/.*|tcp|ugw/d' /etc/config/olsrd
	/etc/init.d/olsrd restart || true
}


## @fn remove_pre05_usergateway_tap_interfaces()
## @brief Entferne alte "on_tapX"-Interfaces, die in dem UGW-Modul bis Firmware v0.4-5 verwendet wurden.
remove_pre05_usergateway_tap_interfaces() {
	trap 'error_trap remove_pre05_usergateway_tap_interfaces "$*"' EXIT
	local netnum
	for netnum in 0 1 2 3 4; do
		uci_delete "network.on_tap${netnum}"
	done
	apply_changes network
}


## @fn remove_pre05_on_usergw_settings()
## @brief Seit v0.5.2 verwendet das on-usergw-Modul keine uci-Einstellungen mehr.
remove_pre05_on_usergw_settings() {
	trap 'error_trap remove_pre05_on_usergw_settings "$*"' EXIT
	rm -f /etc/config/on-usergw
}


## @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.ifname")" = "tun0" ] || return 0
	uci set "network.on_vpn.ifname=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
}


coerce_openvpn_comp_lzo
fix_passwd_broken_symlink
fix_rclocal_broken_symlink
migrate_uci_definition_changes
fix_firewall_reload
transfer_vpn_sort_criteria_and_autosearch
remove_tunnel_openvpn_settings
remove_obsolete_on_core_settings
remove_obsolete_usergw_settings
remove_usergw_openvpn_configs
remove_crontab_entries
rename_olsrd_port_to_port
remove_ntpclient_config

# Bis Version 0.4-5 hiess die Opennet-Mesh-Firewall-Zone "opennet".
# Mit Version 0.5 wurde die Zone in "on_mesh" umbenannt.
rename_firewall_zone "opennet" "$ZONE_MESH"

# mit Version 0.5.2 wird wifidog durch on-captive-portal ersetzt
move_wifidog_networks_to_captive_portal
remove_wifidog_alias_interface
# Bis Version 0.4-5 hieß die wifidog-Zone "free".
# Mit Version 0.5.2 wurde die Zone in "on_free" umbenannt.
# Da die alte Zone falsch konfiguriert war ("FORWARD=yes"), werfen wir sie lieber einfach weg.
delete_firewall_zone "free"
apply_changes firewall

disable_unwanted_forward
move_mtu_fix_to_target_zone

# Bis Version 0.4-5 wurden ins lokale Netz eingehende Pakete (z.B. Portweiterleitungen) via SNAT maskiert.
# siehe https://dev.opennet-initiative.de/ticket/73
uci_delete firewall.zone_local.masq
apply_changes firewall

# Bis Version 0.4-5 hiess die lokale Zone "local" - bei barrier breaker heisst sie nun "lan"
rename_firewall_zone "local" "$ZONE_LOCAL"

# Diese Aktion startet mit 10 Minuten Verzoegerung im Hintergrund, um vorher ein Empfangen der
# olsrd-Announcements zu ermoeglichen. Falls keine alten Gateway-Definitionen vorhanden sind,
# ist dies nicht noetig.
[ -n "$(uci_get on-openvpn.gateway)" ] && run_delayed_in_background 600 transfer_gateway_uci_settings

remove_opennet_ca_certificates_from_previous_location
remove_openvpn_vpntest_keydir
# die Pruefung muss vor der Loeschung der wifidog-Konfiguration stattfinden
guess_previously_used_modules
remove_wifidog_config
enable_uhttpd_redirect
remove_pre05_usergateway_olsr_announcement
remove_pre05_usergateway_tap_interfaces
remove_pre05_on_usergw_settings
auto_enable_on_free_network
rename_gpio_switch_poe_passthrough
rename_tun_to_tun_on_user
update_olsrd_plugin_versions
update_uhttpd_configuration
