#!/bin/bash
###############################################################################
#                                                                             #
# IPFire.org - A linux based firewall                                         #
# Copyright (C) 2010  Michael Tremer & Christian Schmidt                      #
#                                                                             #
# This program is free software: you can redistribute it and/or modify        #
# it under the terms of the GNU General Public License as published by        #
# the Free Software Foundation, either version 3 of the License, or           #
# (at your option) any later version.                                         #
#                                                                             #
# This program is distributed in the hope that it will be useful,             #
# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
# GNU General Public License for more details.                                #
#                                                                             #
# You should have received a copy of the GNU General Public License           #
# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
#                                                                             #
###############################################################################

hook_info() {
	echo "HOOK=\"${HOOK}\""
}

hook_hotplug() {
	# If the hook does not handle the hotplug event, it
	# must return EXIT_NOT_HANDLED.
	exit ${EXIT_NOT_HANDLED}
}

hook_new() {
	local zone="${1}"
	assert isset zone
	shift

	if ! hook_parse_cmdline "$@"; then
		return ${EXIT_ERROR}
	fi

	if ! zone_settings_write "${zone}"; then
		log ERROR "Could not write settings for zone ${zone}"
		return ${EXIT_ERROR}
	fi

	exit ${EXIT_OK}
}

hook_edit() {
	local zone="${1}"
	assert isset zone
	shift

	if ! zone_settings_read "${zone}"; then
		log ERROR "Could not read settings for zone ${zone}"
		return ${EXIT_ERROR}
	fi

	if ! hook_parse_cmdline "$@"; then
		return ${EXIT_ERROR}
	fi

	if ! zone_settings_write "${zone}"; then
		log ERROR "Could not write settings for zone ${zone}"
		return ${EXIT_ERROR}
	fi

	exit ${EXIT_OK}

}

hook_remove() {
	cmd_not_implemented
}

hook_status() {
	local zone="${1}"
	assert isset zone

	if device_is_up ${zone}; then
		exit ${STATUS_UP}
	fi

	exit ${STATUS_DOWN}
}

hook_up() {
	cmd_not_implemented
}

hook_down() {
	cmd_not_implemented
}

hook_discover() {
	# This hook does not support a discovery
	exit ${DISCOVER_NOT_SUPPORTED}
}

# Do nothing
hook_parse_cmdline() {
	return ${EXIT_OK}
}

hook_port() {
	local zone="${1}"
	assert isset zone

	local action="${2}"
	shift 2

	local ret
	case "${action}" in
		add|create|edit|rem|show)
			hook_port_${action} "${zone}" "$@"
			ret=$?
			;;
		*)
			error "Unrecognized argument: '${action}'"
			exit ${EXIT_ERROR}
			;;
	esac

	exit ${ret}
}

hook_port_attach() {
	return ${EXIT_NOT_SUPPORTED}
}

hook_port_detach() {
	return ${EXIT_NOT_SUPPORTED}
}

hook_port_edit() {
	return ${EXIT_NOT_SUPPORTED}
}

hook_port_status() {
	return ${EXIT_NOT_SUPPORTED}
}

hook_default_port_create() {
	assert [ $# -ge 2 ]

	local zone="${1}"
	local port="${2}"

	port_create "${port}"
}

hook_port_create() {
	hook_default_port_create "$@"
}

hook_default_port_remove() {
	assert [ $# -ge 2 ]

	local zone="${1}"
	local port="${2}"

	port_remove "${port}"
}

hook_port_remove() {
	hook_default_port_remove "$@"
}

hook_port_up() {
	cmd_not_implemented
}

hook_port_down() {
	cmd_not_implemented
}

hook_config() {
	local zone="${1}"
	assert isset zone

	local action="${2}"
	assert isset action
	shift 2

	local ret
	case "${action}" in
		new|destroy|edit|show)
			hook_config_${action} "${zone}" "$@"
			exit $?
			;;
		*)
			error "Unrecognized argument: '${action}'"
			exit ${EXIT_ERROR}
			;;
	esac
}

hook_config_cmd() {
	local cmd="${1}"
	assert isset cmd

	local zone="${2}"
	assert isset zone

	local hook_config="${3}"
	assert isset hook_config

	shift 3

	local hook_zone="$(zone_get_hook "${zone}")"
	if ! hook_zone_exists "${hook_zone}"; then
		log ERROR "Hook '${hook}' does not exist."
		exit ${EXIT_ERROR}
	fi

	#if ! hook_config_exists "${hook_zone}" "${hook_config}"; then
	#	log ERROR "Hook '${hook_config}' is not supported for zone '${zone}'."
	#	exit ${EXIT_ERROR}
	#fi

	hook_config_exec "${hook_config}" "${cmd}" "${zone}" "$@"
}

hook_config_new() {
	assert [ $# -ge 2 ]

	hook_config_cmd "new" "$@"
}

hook_config_destroy() {
	assert [ $# -eq 2 ]
	local zone=${1}
	# The id must be the id and not the hid.
	local id=${2}

	shift 2

	# Check if we get a valid id
	if ! zone_config_id_is_valid ${zone} ${id}; then
		log ERROR "ID: ${id} is not a valid id for zone ${zone}"
	fi

	local hook=$(zone_config_get_hook_from_id ${zone}  ${id})
	assert isset hook

	# First we bring the hook down
	hook_config_cmd "down" "${zone}" "${hook}" "${hook}.${id}"

	# If a hook_destroy function is implemented in the hook this function will be executed.
	# If not a empty defined in header-config is executed.
	if ! hook_config_cmd "destroy" "${zone}" "${hook}" "${hook}.${id}" "$@"; then

		# A better error message should printed inside the hook.
		# We will not bring the config up because we do not know if it is safe or if some parts are already destroyed.
		log ERROR "Could not destroy config with the follwoing id: ${id}"
		return ${EXIT_ERROR}
	fi

	# Now we delete the config of the zone
	zone_config_settings_destroy "${zone}" "${hook}.${id}"
}

hook_config_edit() {
	assert [ $# -ge 2 ]
	local zone=${1}
	# The id must be the id and not the hid.
	local id=${2}

	shift 2

	# Check if we get a valid id
	if ! zone_config_id_is_valid ${zone} ${id}; then
		log ERROR "ID: ${id} is not a valid id for zone ${zone}"
	fi

	local hook=$(zone_config_get_hook_from_id ${zone} ${id})
	assert isset hook

	hook_config_cmd "edit" "${zone}" "${hook}" "${hook}.${id}" "$@"
}

hook_config_show() {
	cmd_not_implemented
}

hook_ppp_write_config() {
	cmd_not_implemented

	# Arguments: <zone> <filename>
}

hook_ppp_ip_pre_up() {
	local zone="${1}"
	assert isset zone
	shift

	if ! zone_exists "${zone}"; then
		log ERROR "Zone '${zone}' does not exist."
		exit ${EXIT_ERROR}
	fi

	ppp_common_ip_pre_up "${zone}" "$@"
	exit $?
}

hook_ppp_ipv4_up() {
	local zone="${1}"
	assert isset zone
	shift

	if ! zone_exists "${zone}"; then
		log ERROR "Zone '${zone}' does not exist."
		exit ${EXIT_ERROR}
	fi

	ppp_common_ipv4_up "${zone}" "$@"
	exit $?
}

hook_ppp_ipv4_down() {
	local zone="${1}"
	assert isset zone
	shift

	if ! zone_exists "${zone}"; then
		log ERROR "Zone '${zone}' does not exist."
		exit ${EXIT_ERROR}
	fi

	ppp_common_ipv4_down "${zone}" "$@"
	exit $?
}

hook_ppp_ipv6_up() {
	local zone="${1}"
	assert isset zone
	shift

	if ! zone_exists "${zone}"; then
		error "Zone '${zone}' does not exist."
		exit ${EXIT_ERROR}
	fi

	ppp_common_ipv6_up "${zone}" "$@"
	exit $?
}

hook_ppp_ipv6_down() {
	local zone="${1}"
	assert isset zone
	shift

	if ! zone_exists "${zone}"; then
		error "Zone '${zone}' does not exist."
		exit ${EXIT_ERROR}
	fi

	ppp_common_ipv6_down "${zone}" "$@"
	exit $?
}
