-- lib/network.lua
-- $Id: network.lua,v 1.2 2005/01/27 23:39:48 cpressey Exp $
-- Lua abstraction for the Network Interfaces of a system.

-- BEGIN lib/network.lua --

require "app"
require "cmdchain"

--[[------------------]]--
--[[ NetworkInterface ]]--
--[[------------------]]--

--
-- This class returns an object which represents one of the system's
-- network interfaces.
--
-- This class is not typically instantiated directly by client code.
-- Instead, the user should call NetworkInterface.all() to get a table
-- of all network interfaces present in the system, and choose one.
--
NetworkInterface = {}
NetworkInterface.new = function(name)
	local ni = {}			-- instance variable
	local up			-- internal state...
	local mtu
	local inet6, prefixlen, scopeid
	local inet, netmask, broadcast
	local ether

	local toboolean = function(x)
		if x then
			return true
		else
			return false
		end
	end

	--
	-- Probe this network interface for its current state.
	--
	-- dc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	-- inet6 fe80::250:bfff:fe96:cf68%dc0 prefixlen 64 scopeid 0x1 
	-- inet 10.0.0.19 netmask 0xffffff00 broadcast 10.0.0.255
	-- ether 00:50:bf:96:cf:68
	-- media: Ethernet autoselect (10baseT/UTP)
	--
	ni.probe = function(ni)
		local found, len, cap, flagstring

		up = nil
		mtu = nil
		inet6, prefixlen, scopeid = nil, nil, nil
		inet, netmask, broadcast = nil, nil, nil

		pipe = Pipe.open(App.expand("${root}${IFCONFIG} ${name}", { name = name }))
		if not pipe then
			return nil, "could not open pipe"
		end
		line = pipe:readline()
		while line do
			found, len, cap, flagstring =
			    string.find(line, "flags%s*=%s*(%d+)%s*%<([^%>]*)%>")
			if found then
				flagstring = "," .. flagstring .. ","
				up = toboolean(string.find(flagstring, ",UP,"))
			end

			found, len, cap = string.find(line, "mtu%s*(%d+)")
			if found then
				mtu = tonumber(cap)
			end
			found, len, cap = string.find(line, "inet6%s*([^%s]+)")
			if found then
				inet6 = cap
			end
			found, len, cap = string.find(line, "prefixlen%s*(%d+)")
			if found then
				prefixlen = tonumber(cap)
			end
			found, len, cap = string.find(line, "scopeid%s*0x(%x+)")
			if found then
				scopeid = cap
			end
			found, len, cap = string.find(line, "inet%s*(%d+%.%d+%.%d+%.%d+)")
			if found then
				inet = cap
			end
			found, len, cap = string.find(line, "netmask%s*0x(%x+)")
			if found then
				netmask = cap
			end
			found, len, cap = string.find(line, "broadcast%s*(%d+%.%d+%.%d+%.%d+)")
			if found then
				broadcast = cap
			end
			found, len, cap = string.find(line, "ether%s*(%x%x%:%x%x%:%x%x%:%x%x%:%x%x%:%x%x%)")
			if found then
				ether = cap
			end
			line = pipe:readline()
		end
		pipe:close()
	end

	--
	-- Accessor methods.
	--

	ni.is_up = function(ni)
		return up
	end

	ni.get_inet_addr = function(ni)
		return inet
	end

	ni.get_netmask = function(ni)
		return netmask
	end

	ni.get_broadcast_addr = function(ni)
		return broadcast
	end

	ni.get_ether_addr = function(ni)
		return ether
	end

	--
	-- CmdChain-creating methods.
	--

	ni.cmds_assign_inet_addr = function(ni, cmds, addr)
		cmds:add({
		    cmdline = "${root}${IFCONFIG} ${name} ${addr}",
		    replacements = {
			name = name,
			addr = addr
		    }
		})
	end

	ni.cmds_assign_netmask = function(ni, cmds, netmask)
		cmds:add({
		    cmdline = "${root}${IFCONFIG} ${name} netmask ${netmask}",
		    replacements = {
			name = name,
			netmask = netmask
		    }
		})
	end

	ni.cmds_dhcp_configure = function(ni, cmds)
		cmds:add(
		    {
			cmdline = "${root}${KILLALL} dhclient",
			failure_mode = CmdChain.FAILURE_IGNORE
		    },
		    {
			cmdline = "${root}${DHCLIENT} -1 ${name}",
			replacements = {
			    name = name
			}
		    }
		)
	end

	return ni
end

--
-- Return a table of all network interfaces present in the system.
--
NetworkInterface.all = function()
	local pipe, line, name, ni
	local iftab = {}

	pipe = Pipe.open(App.expand("${root}${IFCONFIG} -l"))
	if not pipe then
		return nil, "could not open pipe"
	end
	line = pipe:readline()
	pipe:close()

	for name in string.gfind(line, "%s*([^%s]+)%s*") do
		ni = NetworkInterface.new(name)
		ni:probe()
		iftab[name] = ni
	end

	return iftab
end

-- END of lib/network.lua --
