From e898a0dec6d087216914590bbac57b8086f5cad3 Mon Sep 17 00:00:00 2001
From: Jo-Philipp Wich <jow@openwrt.org>
Date: Sat, 13 Sep 2008 01:00:11 +0000
Subject: [PATCH] * luci/app-olsr: first round of olsr improvements: 	-
 implement new uci config format 	- moved hna announcements and plugins
 to separate pages 	- made all sections dynamic 	- added all known
 plugin options as additional fields

---
 .../luci-olsr/luasrc/controller/olsr.lua      | 101 +++++-----
 .../luci-olsr/luasrc/model/cbi/olsr/olsrd.lua |  77 ++++----
 .../luasrc/model/cbi/olsr/olsrdhna.lua        |  27 +++
 .../luasrc/model/cbi/olsr/olsrdplugins.lua    | 174 ++++++++++++++++++
 4 files changed, 295 insertions(+), 84 deletions(-)
 create mode 100644 applications/luci-olsr/luasrc/model/cbi/olsr/olsrdhna.lua
 create mode 100644 applications/luci-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua

diff --git a/applications/luci-olsr/luasrc/controller/olsr.lua b/applications/luci-olsr/luasrc/controller/olsr.lua
index 96226d83e..f7a8ec106 100644
--- a/applications/luci-olsr/luasrc/controller/olsr.lua
+++ b/applications/luci-olsr/luasrc/controller/olsr.lua
@@ -1,145 +1,158 @@
 module("luci.controller.olsr", package.seeall)
 
 function index()
-	if not luci.fs.isfile("/etc/config/olsr") then
+	if not luci.fs.isfile("/etc/config/olsrd") then
 		return
 	end
-	
+
 	require("luci.i18n").loadc("olsr")
 	local i18n = luci.i18n.translate
-	
+
 	local page  = node("admin", "status", "olsr")
 	page.target = call("action_index")
 	page.title  = "OLSR"
 	page.i18n   = "olsr"
-	
+
 	local page  = node("admin", "status", "olsr", "routes")
 	page.target = call("action_routes")
 	page.title  = i18n("olsr_routes", "Routen")
 	page.order  = 10
-	
+
 	local page  = node("admin", "status", "olsr", "topology")
 	page.target = call("action_topology")
 	page.title  = i18n("olsr_topology", "Topologie")
 	page.order  = 20
-	
+
 	local page  = node("admin", "status", "olsr", "hna")
 	page.target = call("action_hna")
 	page.title  = "HNA"
 	page.order  = 30
-	
+
 	local page  = node("admin", "status", "olsr", "mid")
 	page.target = call("action_mid")
 	page.title  = "MID"
 	page.order  = 50
 
-	entry({"admin", "services", "olsrd"}, cbi("olsr/olsrd"), "OLSR").i18n = "olsr"
+	entry(
+		{"admin", "services", "olsrd"},
+		cbi("olsr/olsrd"), "OLSR"
+	).i18n = "olsr"
+
+	entry(
+		{"admin", "services", "olsrd", "hna"},
+		cbi("olsr/olsrdhna"), "HNA Announcements"
+	).i18n = "olsr"
+
+	entry(
+		{"admin", "services", "olsrd", "plugins"},
+		cbi("olsr/olsrdplugins"), "Plugins"
+	).i18n = "olsr"
 end
 
 function action_index()
 	local data = fetch_txtinfo("links")
-	
+
 	if not data or not data.Links then
 		luci.template.render("status-olsr/error_olsr")
 		return nil
 	end
-	
+
 	local function compare(a, b)
 		local c = tonumber(a.ETX)
 		local d = tonumber(b.ETX)
-		
+
 		if not c or c == 0 then
 			return false
 		end
-		
+
 		if not d or d == 0 then
 			return true
 		end
-		
+
 		return c < d
 	end
-	
+
 	table.sort(data.Links, compare)
-	
+
 	luci.template.render("status-olsr/index", {links=data.Links})
 end
 
 function action_routes()
 	local data = fetch_txtinfo("routes")
-	
+
 	if not data or not data.Routes then
 		luci.template.render("status-olsr/error_olsr")
 		return nil
 	end
-	
+
 	local function compare(a, b)
 		local c = tonumber(a.ETX)
 		local d = tonumber(b.ETX)
-		
+
 		if not c or c == 0 then
 			return false
 		end
-		
+
 		if not d or d == 0 then
 			return true
 		end
-		
+
 		return c < d
 	end
-	
+
 	table.sort(data.Routes, compare)
-	
+
 	luci.template.render("status-olsr/routes", {routes=data.Routes})
 end
 
 function action_topology()
 	local data = fetch_txtinfo("topology")
-	
+
 	if not data or not data.Topology then
 		luci.template.render("status-olsr/error_olsr")
 		return nil
 	end
-	
+
 	local function compare(a, b)
 		return a["Destination IP"] < b["Destination IP"]
 	end
-	
+
 	table.sort(data.Topology, compare)
-	
+
 	luci.template.render("status-olsr/topology", {routes=data.Topology})
 end
 
 function action_hna()
 	local data = fetch_txtinfo("hna")
-	
+
 	if not data or not data.HNA then
 		luci.template.render("status-olsr/error_olsr")
 		return nil
 	end
-	
+
 	local function compare(a, b)
 		return a.Network < b.Network
 	end
-	
+
 	table.sort(data.HNA, compare)
-	
+
 	luci.template.render("status-olsr/hna", {routes=data.HNA})
 end
 
 function action_mid()
 	local data = fetch_txtinfo("mid")
-	
+
 	if not data or not data.MID then
 		luci.template.render("status-olsr/error_olsr")
 		return nil
 	end
-	
+
 	local function compare(a, b)
 		return a.IP < b.IP
 	end
-	
+
 	table.sort(data.MID, compare)
-	
+
 	luci.template.render("status-olsr/mid", {mids=data.MID})
 end
 
@@ -149,39 +162,39 @@ function fetch_txtinfo(otable)
 	require("luci.sys")
 	otable = otable or ""
 	local rawdata = luci.sys.httpget("http://127.0.0.1:2006/"..otable)
-	
+
 	if #rawdata == 0 then
 		return nil
 	end
-	
+
 	local data = {}
-	
+
 	local tables = luci.util.split(luci.util.trim(rawdata), "\r?\n\r?\n", nil, true)
-	
+
 
 	for i, tbl in ipairs(tables) do
 		local lines = luci.util.split(tbl, "\r?\n", nil, true)
 		local name  = table.remove(lines, 1):sub(8)
 		local keys  = luci.util.split(table.remove(lines, 1), "\t")
 		local split = #keys - 1
-		
+
 		data[name] = {}
-		
+
 		for j, line in ipairs(lines) do
 			local fields = luci.util.split(line, "\t", split)
 			data[name][j] = {}
 			for k, key in pairs(keys) do
-				data[name][j][key] = fields[k] 
+				data[name][j][key] = fields[k]
 			end
-			
+
 			if data[name][j].Linkcost then
 				data[name][j].LinkQuality,
 				data[name][j].NLQ,
 				data[name][j].ETX =
-				 data[name][j].Linkcost:match("([%w.]+)/([%w.]+)[%s]+([%w.]+)")
+				data[name][j].Linkcost:match("([%w.]+)/([%w.]+)[%s]+([%w.]+)")
 			end
 		end
 	end
-	
+
 	return data
 end
diff --git a/applications/luci-olsr/luasrc/model/cbi/olsr/olsrd.lua b/applications/luci-olsr/luasrc/model/cbi/olsr/olsrd.lua
index 80fe53ccd..7e134cc6d 100644
--- a/applications/luci-olsr/luasrc/model/cbi/olsr/olsrd.lua
+++ b/applications/luci-olsr/luasrc/model/cbi/olsr/olsrd.lua
@@ -14,14 +14,17 @@ $Id$
 require("luci.tools.webadmin")
 require("luci.fs")
 
-m = Map("olsr", "OLSR")
+m = Map("olsrd", "OLSR")
 
-s = m:section(NamedSection, "general", "olsr")
+s = m:section(TypedSection, "olsrd", translate("olsr_general"))
+s.dynamic = true
+s.anonymous = true
 
 debug = s:option(ListValue, "DebugLevel")
 for i=0, 9 do
 	debug:value(i)
 end
+debug.optional = true
 
 ipv = s:option(ListValue, "IpVersion")
 ipv:value("4", "IPv4")
@@ -30,20 +33,23 @@ ipv:value("6", "IPv6")
 noint = s:option(Flag, "AllowNoInt")
 noint.enabled = "yes"
 noint.disabled = "no"
+noint.optional = true
 
-s:option(Value, "Pollrate")
+s:option(Value, "Pollrate").optional = true
 
 tcr = s:option(ListValue, "TcRedundancy")
 tcr:value("0", translate("olsr_general_tcredundancy_0"))
 tcr:value("1", translate("olsr_general_tcredundancy_1"))
 tcr:value("2", translate("olsr_general_tcredundancy_2"))
+tcr.optional = true
 
-s:option(Value, "MprCoverage")
+s:option(Value, "MprCoverage").optional = true
 
 lql = s:option(ListValue, "LinkQualityLevel")
 lql:value("0", translate("disable"))
 lql:value("1", translate("olsr_general_linkqualitylevel_1"))
 lql:value("2", translate("olsr_general_linkqualitylevel_2"))
+lql.optional = true
 
 s:option(Value, "LinkQualityAging").optional = true
 
@@ -52,31 +58,37 @@ lqa.optional = true
 lqa:value("etx_fpm", translate("olsr_etx_fpm"))
 lqa:value("etx_float", translate("olsr_etx_float"))
 lqa:value("etx_ff", translate("olsr_etx_ff"))
+lqa.optional = true
 
 lqfish = s:option(Flag, "LinkQualityFishEye")
+lqfish.optional = true
 
-s:option(Value, "LinkQualityWinSize")
+s:option(Value, "LinkQualityWinSize").optional = true
 
-s:option(Value, "LinkQualityDijkstraLimit")
+s:option(Value, "LinkQualityDijkstraLimit").optional = true
 
 hyst = s:option(Flag, "UseHysteresis")
 hyst.enabled = "yes"
 hyst.disabled = "no"
+hyst.optional = true
 
 fib = s:option(ListValue, "FIBMetric")
 fib.optional = true
 fib:value("flat")
 fib:value("correct")
 fib:value("approx")
+fib.optional = true
 
 clrscr = s:option(Flag, "ClearScreen")
 clrscr.enabled = "yes"
 clrscr.disabled = "no"
+clrscr.optional = true
 
 willingness = s:option(ListValue, "Willingness")
 for i=0,7 do
 	willingness:value(i)
 end
+willingness.optional = true
 
 
 
@@ -85,42 +97,27 @@ i.anonymous = true
 i.addremove = true
 i.dynamic = true
 
-network = i:option(ListValue, "Interface", translate("network"))
-luci.tools.webadmin.cbi_add_networks(network)
-
-i:option(Value, "Ip4Broadcast")
-i:option(Value, "HelloInterval")
-i:option(Value, "HelloValidityTime")
-i:option(Value, "TcInterval")
-i:option(Value, "TcValidityTime")
-i:option(Value, "MidInterval")
-i:option(Value, "MidValidityTime")
-i:option(Value, "HnaInterval")
-i:option(Value, "HnaValidityTime")
-
-
-p = m:section(TypedSection, "LoadPlugin")
-p.addremove = true
-p.dynamic = true
-
-lib = p:option(ListValue, "Library", translate("library"))
-lib:value("")
-for k, v in pairs(luci.fs.dir("/usr/lib")) do
-	if v:sub(1, 6) == "olsrd_" then
-		lib:value(v)
-	end
-end
-
+ign = i:option(Flag, "ignore")
+ign.enabled  = "1"
+ign.disabled = "0"
 
-for i, sect in ipairs({ "Hna4", "Hna6" }) do
-	hna = m:section(TypedSection, sect)
-	hna.addremove = true
-	hna.anonymous = true
-	hna.template  = "cbi/tblsection"
+network = i:option(ListValue, "interface", translate("network"))
+luci.tools.webadmin.cbi_add_networks(network)
 
-	net = hna:option(Value, "NetAddr")
-	msk = hna:option(Value, "Prefix")
-end
+i:option(Value, "Ip4Broadcast").optional = true
+i:option(Value, "HelloInterval").optional = true
+i:option(Value, "HelloValidityTime").optional = true
+i:option(Value, "TcInterval").optional = true
+i:option(Value, "TcValidityTime").optional = true
+i:option(Value, "MidInterval").optional = true
+i:option(Value, "MidValidityTime").optional = true
+i:option(Value, "HnaInterval").optional = true
+i:option(Value, "HnaValidityTime").optional = true
+
+adc = i:option(Flag, "AutoDetectChanges")
+adc.enabled  = "yes"
+adc.disabled = "no"
+adc.optional = true
 
 
 ipc = m:section(NamedSection, "IpcConnect")
diff --git a/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdhna.lua b/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdhna.lua
new file mode 100644
index 000000000..b784ea143
--- /dev/null
+++ b/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdhna.lua
@@ -0,0 +1,27 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+mh = Map("olsrd", "OLSR - HNA Announcements")
+
+for i, sect in ipairs({ "Hna4", "Hna6" }) do
+	hna = mh:section(TypedSection, sect)
+	hna.addremove = true
+	hna.anonymous = true
+	hna.template  = "cbi/tblsection"
+
+	net = hna:option(Value, "NetAddr")
+	msk = hna:option(Value, "Prefix")
+end
+
+return mh
diff --git a/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua b/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua
new file mode 100644
index 000000000..83ed74ac9
--- /dev/null
+++ b/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua
@@ -0,0 +1,174 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+require("luci.fs")
+require("luci.ip")
+
+mp = Map("olsrd", "OLSR - Plugins")
+
+p = mp:section(TypedSection, "LoadPlugin")
+p.addremove = true
+p.dynamic = true
+p.anonymous = true
+
+ign = p:option(Flag, "ignore")
+ign.enabled  = "1"
+ign.disabled = "0"
+
+lib = p:option(ListValue, "library", translate("library"))
+lib:value("")
+for k, v in pairs(luci.fs.dir("/usr/lib")) do
+	if v:sub(1, 6) == "olsrd_" then
+		lib:value(v)
+	end
+end
+
+local function Range(x,y)
+	local t = {}
+	for i = x, y do t[#t+1] = i end
+	return t
+end
+
+local function Cidr2IpMask(val)
+	local cidr = luci.ip.IPv4(val) or luci.ip.IPv6(val)
+	if not cidr then return val else return cidr end
+end
+
+local function IpMask2Cidr(val)
+	local ip, mask = val:gmatch("([^%s+])%s+([^%s+])")
+	local cidr
+	if ip and mask and ip:match(":") then
+		cidr = luci.ip.IPv6(ip, mask)
+	elseif ip and mask then
+		cidr = luci.ip.IPv4(ip, mask)
+	end
+	if not cidr then return val else return cidr end
+end
+
+
+local knownPlParams = {
+	["olsrd_bmf.so.1.5.3"] = {
+		{ Value, 		"BmfInterface",			"bmf0" },
+		{ Value, 		"BmfInterfaceIp",		"10.10.10.234/24" },
+		{ Flag,  		"DoLocalBroadcast",		"no" },
+		{ Flag,  		"CapturePacketsOnOlsrInterfaces", "yes" },
+		{ ListValue, 	"BmfMechanism",			{ "UnicastPromiscuous", "Broadcast" } },
+		{ Value, 		"BroadcastRetransmitCount",	"2" },
+		{ Value, 		"FanOutLimit",			"4" },
+		{ DynamicList,	"NonOlsrIf",			"eth1" },
+	},
+
+	["olsrd_dyn_gw.so.0.4"] = {
+		{ Value,		"Interval",				"40" },
+		{ DynamicList,  "Ping",					"141.1.1.1" },
+		{ DynamicList,	"HNA",					"192.168.80.0/24", Cidr2IpMask, IpMask2Cidr }
+	},
+
+	["olsrd_httpinfo.so.0.1"] = {
+		{ Value,		"port",					"80" },
+		{ DynamicList,	"Host",					"163.24.87.3" },
+		{ DynamicList,	"Net",					"0.0.0.0/0", Cidr2IpMask, IpMask2Cidr },
+	},
+
+	["olsrd_nameservice.so.0.2"] = {
+		{ DynamicList,	"name",					"my-name.mesh" },
+		{ DynamicList,	"hosts",				"1.2.3.4 name-for-other-interface.mesh" },
+		{ Value,		"suffix",				".olsr" },
+		{ Value,		"hosts_file",			"/path/to/hosts_file" },
+		{ Value,		"add_hosts",			"/path/to/file" },
+		{ Value,		"dns_server",			"141.1.1.1" },
+		{ Value,		"resolv_file",			"/path/to/resolv.conf" },
+		{ Value,		"interval",				"120" },
+		{ Value,		"timeout",				"240" },
+		{ Value,		"lat",					"12.123" },
+		{ Value,		"lon",					"12.123" },
+		{ Value,		"latlon_file",			"/var/run/latlon.js" },
+		{ Value,		"latlon_infile",		"/var/run/gps.txt" },
+		{ Value,		"sighup_pid_file",		"/var/run/dnsmasq.pid" },
+		{ Value,		"name_change_script",	"/usr/local/bin/announce_new_hosts.sh" },
+		{ Value,		"services_change_script",	"/usr/local/bin/announce_new_services.sh" }
+	},
+
+	["olsrd_quagga.so.0.2.2"] = {
+		{ StaticList,	"redistribute",			{
+			"system", "kernel", "connect", "static", "rip", "ripng", "ospf",
+			"ospf6", "isis", "bgp", "hsls"
+		} },
+		{ ListValue,	"ExportRoutes",			{ "only", "both" } },
+		{ Flag,			"LocalPref",			"true" },
+		{ Value,		"Distance",				Range(0,255) }
+	},
+
+	["olsrd_secure.so.0.5"] = {
+		{ Value,		"Keyfile",				"/etc/private-olsr.key" }
+	},
+
+	["olsrd_txtinfo.so.0.1"] = {
+		{ Value,		"accept",				"10.247.200.4" }
+	}
+}
+
+
+-- build plugin options with dependencies
+for plugin, options in pairs(knownPlParams) do
+	for _, option in ipairs(options) do
+		local otype, name, default, uci2cbi, cbi2uci = unpack(option)
+		local values
+
+		if type(default) == "table" then
+			values  = default
+			default = default[1]
+		end
+
+		if otype == Flag then
+			local bool = p:option( Flag, name )
+			if default == "yes" or default == "no" then
+				bool.enabled  = "yes"
+				bool.disabled = "no"
+			elseif default == "on" or default == "off" then
+				bool.enabled  = "on"
+				bool.disabled = "off"
+			elseif default == "1" or default == "0" then
+				bool.enabled  = "1"
+				bool.disabled = "0"
+			else
+				bool.enabled  = "true"
+				bool.disabled = "false"
+			end
+			bool.default = default
+			bool:depends({ library = plugin })
+		else
+			local field = p:option( otype, name )
+			if values then
+				for _, value in ipairs(values) do
+					field:value( value )
+				end
+			end
+			if type(uci2cbi) == "function" then
+				function field.cfgvalue(self, section)
+					return uci2cbi(otype.cfgvalue(self, section))
+				end
+			end
+			if type(cbi2uci) == "function" then
+				function field.formvalue(self, section)
+					return cbi2uci(otype.formvalue(self, section))
+				end
+			end
+			field.default = default
+			field:depends({ library = plugin })
+		end
+	end
+end
+
+return mp
-- 
2.25.1