# Copyright (C) 2005, 2006, 2008, 2009  Martin Michlmayr <tbm@cyrius.com>
# Copyright (C) 2008  Matthew Palmer <mpalmer@debian.org>
# Copyright (C) 2009  Stephen Gran <sgran@debian.org>

# This code is covered by the GNU General Public License (version 2
# or higher)

# Reading

# Check if a file exists and exit if it doesn't
# $1 = file
check_file() {
	if [ ! -e $1 ]; then
		log "$1 does not exist"
		exit
	fi
}

# Returns the mtd device with the specified name (without leading /dev)
# $1 = name of mtd device
get_mtd() {
	grep "\b$1\b\"*$" /proc/mtd | cut -d : -f 1
}

# Returns the mtd block device with the specified name (without leading /dev)
# $1 = name of mtd device
get_mtdblock() {
	echo $(get_mtd "$1") | sed 's/mtd/mtdblock/'
}

# Parsing

# Parse a standard Unix tree (i.e. configs found in /etc)
# $1 = root path
parse_unix_tree() {
	log "Parsing Unix tree at $1"
	ETC=$1/etc
	if [ -e $ETC/network/interfaces ]; then
		parse_network_interfaces $ETC/network/interfaces "eth0"
	fi
	if [ -e $ETC/resolv.conf ]; then
		for i in $(grep "^nameserver" $ETC/resolv.conf | sed 's/^.* //'); do
			var_add NAMESERVERS "$i"
		done
	fi
	if [ -e $ETC/hostname ]; then
		HOSTNAME=$(cat $ETC/hostname | cut -d . -f 1)
	fi
	if [ -e $ETC/domainname ]; then
		DOMAIN=$(cat $ETC/domainname)
	fi
}

# LEAF is a distro based on LRP (Linux Router Project)
# $1 = root path
parse_leaf_tree() {
	log "Parsing LEAF tree at $1"
	ETC=$1/etc
	if [ -e $ETC/resolv.static1 ]; then
		var_add NAMESERVERS "$(grep "^nameserver" $ETC/resolv.static1 | sed 's/^.* //' | head -n 1)"
	fi
	if [ -e $ETC/resolv.static2 ]; then
		var_add NAMESERVERS "$(grep "^nameserver" $ETC/resolv.static2 | sed 's/^.* //' | head -n 1)"
	fi
}

# Parse a /etc/network/interfaces file
# $1 = file
# $2 = interface
parse_network_interfaces() {
	log "Parsing $1 to find network interface $2"

	# Find the interface we're interested in
	if ! $(grep -q "^iface $2\b" $1); then
		return
	fi
	iface=$(grep -n "^iface $2\b" $1)
	if $(echo "$iface" | grep -q "inet static"); then
		n=$(echo "$iface" | cut -d : -f 1) # line number
		NET_CONFIG=static
		stanza=$(tail -n +$(($n+1)) $1)
		# Find the next interface and ignore lines from there on
		n=$(echo "$stanza" | grep -n "^iface\b" | cut -d : -f 1)
		if [ $n ]; then
			stanza=$(echo "$stanza" | head -n $(($n-1)))
		fi
		INTERFACE=$2
		IPADDRESS=$(echo "$stanza" | grep "address" | sed 's/.*address //')
		GATEWAY=$(echo "$stanza" | grep "gateway" | sed 's/.*gateway //')
	fi
}

# Parse a set of ifconfig/route/etc commands
# $1 = ifconfig et al. commands
parse_ifconfig() {
	# UGH!
	IPADDRESS=$(grep "ifconfig [-[:alpha:][:digit:]]* [[:digit:].]" $1 | sed 's/.*ifconfig [-[:alpha:][:digit:]]* \([.[:digit:]]*\) .*/\1/')
	NETMASK=$(grep '\bnetmask\b' $1 | sed 's/.*netmask\s*//' | sed 's/\s.*//')
	GATEWAY=$(grep "route add default gw" $1 | sed 's/.*gw\s*//')
}

# Get the value from a string in the form of var=value
# $1 = string
# $2 = var
get_var() {
	echo "$1" | grep -a "^$2=" | sed "s/^$2=//"
}

# Get the value from a string in the form of var = "value" from a file.
# Named for the sib.conf file on the D-Link DNS-323 that this function
# was originally written for.
# $1 = file to read
# $2 = var to read
get_sib_var() {
	grep "^$2[[:space:]]*=" $1 | sed "s/^$2[[:space:]]*=[[:space:]]*\"\(.*\)\"[[:space:]]*$/\1/"
}

# Add a string to a variable; deals with the fact when a string is empty
# $1 = variable name
# $2 = string
var_add() {
	if [ -n "$2" ]; then
		value="$(eval echo \"$`echo $1`\")"
		if [ -n "$value" ]; then
			x="$value $2"
		else
			x="$2"
		fi
		eval "`echo $1`=\"$x\""
	fi
}

# Return the value of a XML/HTML like <foo>value</foo> staetment.
remove_xml() {
	echo "$1" | sed 's/[^>]*> *//' | sed 's/ *<.*//'
}

# Parse the sib.conf file, as found in the D-Link DNS-323
# $1 = path to sib.conf
parse_sib_conf() {
	if [ "$(get_sib_var "$1" "CF-IP-DHCP-ENABLE")" = "0" ]; then
		NET_CONFIG=static
	fi
	IPADDRESS="$(get_sib_var "$1" "CF-IP-STATIC-IP")"
	NETMASK="$(get_sib_var "$1" "CF-IP-STATIC-IP-NETMASK")"
	GATEWAY="$(get_sib_var "$1" "CF-IP-STATIC-IP-GATEWAY")"
	var_add NAMESERVERS "$(get_sib_var "$1" "CF-IP-DNS1")"
	var_add NAMESERVERS "$(get_sib_var "$1" "CF-IP-DNS2")"
	HOSTNAME="$(get_sib_var "$1" "CF-SYS-MODEL-STR")"
}

# Generating

# Output a variable to a preseed file if the variable has a value
# $1 = file name (stdout if this is empty)
# $2 = debconf variable name
# $3 = debconf variable type
# $4 = variable
add() {
	if [ -n "$4" -o "$3" = "note" ]; then
		if [ -n "$1" ]; then
			echo "d-i $2 $3 $4" | sed 's/ *$//' >> "$1"
		else
			echo "d-i $2 $3 $4" | sed 's/ *$//'
		fi
	fi
}

# Output a variable to a preseed file or, iv the variable is empty, mark
# the debconf variable as seen.
# $1 = file name (stdout if this is empty)
# $2 = debconf variable name
# $3 = debconf variable type
# $4 = variable
add_or_set_seen() {
	if [ -z "$4" -a "$NONINTERACTIVE" = "yes" ]; then
		add "$1" "$2" "seen" "true"
	else
		add "$1" "$2" "$3" "$4"
	fi
}

# Write a static network configuration to the preseed file
# $1 = file name (stdout if this is empty)
write_static_network() {
	add "$1" "netcfg/get_ipaddress" "string" "$IPADDRESS"
	add_or_set_seen "$1" "netcfg/get_netmask" "string" "$NETMASK"
	if [ -z "$GATEWAY" ]; then
		GATEWAY=none
	fi
	add "$1" "netcfg/get_gateway" "string" "$GATEWAY"
	add "$1" "netcfg/get_nameservers" "string" "$NAMESERVERS"
}

# Fall back to a static address if DHCP fails
# $1 = file name (stdout if this is empty)
dhcp_fallback() {
	add "$1" "netcfg/dhcp_failed" "note"
	add "$1" "netcfg/dhcp_options" "select" "Configure network manually"
	write_static_network "$1"
}

# Generate a preseed file
# $1 = filename
generate_preseed_file() {
	add "$1" "netcfg/choose_interface" "select" "$INTERFACE"
	if [ "$NET_CONFIG" = "static" ]; then
		write_static_network "$1"
		add "$1" "netcfg/confirm_static" "boolean" "true"
		add "$1" "netcfg/disable_autoconfig" "boolean" "true"
	else
		add "$1" "netcfg/use_dhcp" "boolean" "true"
	fi
	if [ "$NONINTERACTIVE" = "yes" -o "$HOSTNAME" != "$DEFAULT_HOSTNAME" ]; then
		if verify_hostname "$HOSTNAME"; then
			add "$1" "netcfg/get_hostname" "string" "$HOSTNAME"
		fi
	fi
	add "$1" "netcfg/get_domain" "string" "$DOMAIN"
}


# Misc

# Unset a variable if it has a particular value
# $1 = variable
# $2 = value
unset_matching_var() {
	if [ "$(eval echo $`echo $1`)" = "$2" ]; then
		unset $1
	fi
}


# Check the hostname for RFC 1123 compliance.
verify_hostname() {
	t=$(echo "$1" | tr -d 'a-zA-Z0-9.-')
	if [ -n "$t" ]; then
		return 1
	fi
	if echo "$1" | grep -q "^-"; then
		return 1
	fi
	if echo "$1" | grep -q -- "-$"; then
		return 1
	fi
	l=$(($(echo "$1" | wc -c) - 1))
	if [ $l -lt 2 -o $l -gt 63 ]; then
		return 1
	fi
	return 0
}

# Convert an IP address (like 127.0.0.1) to bits.
make_bit_address () {
	addr=$1

	first=$(( $(echo $addr | cut -d. -f1) << 24))
	second=$(( $(echo $addr | cut -d. -f2) << 16))
	third=$(( $(echo $addr | cut -d. -f3) << 8))
	fourth=$(echo $addr | cut -d. -f4)
	echo $(( $first + $second + $third + $fourth ))
}

# Check if two IP addresses are on the same network.
address_is_in () {
	addr=$1
	addr2=$2
	netmask=$3

	bitaddr=$(make_bit_address $addr)
	bitaddr2=$(make_bit_address $addr2)
	bitmask=$(make_bit_address $netmask)

	[ "$(( $bitaddr & $bitmask ))" = "$(( $bitaddr2 & $bitmask))" ]
}

# Sanity checks for static IP configuration
sanity_check_static_config() {
	# netcfg will prompt for an IP address and nameserver if they are
	# not set, so use DHCP in that case.
	if [ "$NONINTERACTIVE" = "yes" ] && [ -z "$IPADDRESS" -o -z "$NAMESERVERS" ]; then
		NET_CONFIG=dhcp
	fi
	# Replicate the "gateway is unreachable" check from netcfg.
	if [ -n "$IPADDRESS" -a -n "$GATEWAY" ]; then
		if [ -n "$NETMASK" ]; then
			LOCAL_NETMASK="$NETMASK"
		else
			# Use same default as netcfg.
			LOCAL_NETMASK=255.255.255.0
		fi
		if ! address_is_in "$IPADDRESS" "$GATEWAY" "$LOCAL_NETMASK"; then
			NET_CONFIG=dhcp
		fi
	fi
}

