#!/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/>.       #
#                                                                             #
###############################################################################
#
# Notes:
#   - All functions in this scope must start with an underline (_) to not
#     conflict with any functions that were defined somewhere else.
#

. /lib/network/functions

HOOK=$(basename ${0})

while [ $# -gt 0 ]; do
	case "${1}" in
		-*)
			error "Unrecognized option: ${1}"
			exit ${EXIT_ERROR}
			;;
		*)
			action=${1}
			;;
	esac
	shift

	# If action argument was given, we will exit.
	[ -n "${action}" ] && break
done

# _notimplemented
#   Returns a soft error if a function was not implemented, yet.
#
function _notimplemented() {
	warning "'$@' was not implemented."
	exit ${EXIT_CONF_ERROR}
}

function _info() {
	echo "HOOK=\"${HOOK}\""
}

function _create() {
	local zone=${1}
	shift

	config_read $(zone_dir ${zone})/settings

	_parse_cmdline $@

	config_write $(zone_dir ${zone})/settings ${HOOK_SETTINGS}

	exit ${EXIT_OK}
}

function _edit() {
	_create $@
}

function _rem() {
	_notimplemented _rem
}

function _status() {
	local zone=${1}

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

	exit ${STATUS_DOWN}
}

function _up() {
	_notimplemented _up
}

function _down() {
	_notimplemented _down
}

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

# Do nothing
function _parse_cmdline() {
	return ${EXIT_OK}
}

function _port() {
	local zone=${1}
	local action=${2}
	shift 2

	local ret

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

	exit ${ret}
}

function _port_add() {
	_port_cmd add $@
}

function _port_edit() {
	_port_cmd edit $@
}

function _port_rem() {
	_port_cmd rem $@
}

function _port_show() {
	_notimplemented _port_show
}

function _port_status() {
	_port_cmd status $@
}

function _port_cmd() {
	local cmd=${1}
	local zone=${2}
	local port=${3}
	shift 3

	assert isset cmd
	assert isset zone
	assert isset port

	local hook_zone=$(zone_get_hook ${zone})
	local hook_port=$(port_get_hook ${port})

	assert isset hook_zone
	assert isset hook_port

	if ! listmatch ${hook_port} $(zone_get_supported_port_hooks ${zone}); then
		error_log "Zone '${zone}' does not support port of type '${hook_port}'."
		exit ${EXIT_ERROR}
	fi

	hook_zone_port_exec ${hook_zone} ${hook_port} ${cmd} ${zone} ${port} $@

	exit $?
}

function _port_up() {
	_port_cmd up $@
}

function _port_down() {
	_port_cmd down $@
}

function _config() {
	local zone=${1}
	local action=${2}
	shift 2

	local ret

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

	exit ${ret}
}

# This function is not a public one
function __configcmd() {
	local cmd=${1}
	local zone=${2}
	local hook_config=${3}
	shift 3

	local hook_zone=$(zone_get_hook ${zone})

	if ! hook_zone_exists ${hook_zone}; then
		error "Hook '${hook}' does not exist."
		exit ${EXIT_ERROR}
	fi

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

	hook_zone_config_exec ${hook_zone} ${hook_config} ${cmd} ${zone} $@
}

function _config_create() {
	local zone=${1}
	local hook_config=${2}
	shift 2

	assert isset zone
	assert isset hook_config
	assert zone_exists ${zone}

	if ! listmatch ${hook_config} $(zone_get_supported_config_hooks ${zone}); then
		error_log "Zone '${zone}' does not support configuration of type '${hook_config}'."
		exit ${EXIT_ERROR}
	fi

	local hook_zone=$(zone_get_hook ${zone})
	assert isset hook_zone

	hook_zone_config_exec ${hook_zone} ${hook_config} create ${zone} $@

	exit $?
}

function _config_edit() {
	__configcmd edit $@
}

function _config_rem() {
	_notimplemented _config_rem
}

function _config_show() {
	_notimplemented _config_show
}

function _ppp-ip-pre-up() {
	local zone=${1}
	shift

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

	ppp_common_ip_pre_up ${zone} $@

	exit $?
}

function _ppp-ip-up() {
	local zone=${1}
	shift

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

	ppp_common_ip_up ${zone} $@

	exit $?
}

function _ppp-ip-down() {
	local zone=${1}
	shift

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

	ppp_common_ip_down ${zone} $@

	exit $?
}

function _ppp-ipv6-up() {
	local zone=${1}
	shift

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

	ppp_common_ipv6_up ${zone} $@

	exit $?
}

function _ppp-ipv6-down() {
	local zone=${1}
	shift

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

	ppp_common_ipv6_down ${zone} $@

	exit $?
}

function run() {
	# Replace all dashes by an underscore
	#action=${action//-/_}

	case "${action}" in
		# Main functions
		create|discover|down|edit|info|rem|status|up)
			_${action} $@
			;;

		# Port callbacks
		port_add|port_rem|port_up|port_down|port_status)
			_${action} $@
			;;

		# Configuration callbacks
		config_create)
			_${action} $@
			;;

		# ppp daemon callbacks
		ppp-ip-pre-up|ppp-ip-up|ppp-ip-down|ppp-ipv6-up|ppp-ipv6-down)
			_${action} $@
			;;

		*)
			error "Unknown action: ${action}"
			;;		
	esac

	error "Hook did not exit properly."
	exit ${EXIT_ERROR}
}
