luci-app-travelmate: sync with travelmate 0.9.0

* add a wireless station manager to edit and delete existing
  interfaces or scan for new uplinks

Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
Dirk Brenken 2017-07-19 22:36:47 +02:00
parent 76b3af64c0
commit e900b892e8
8 changed files with 375 additions and 48 deletions

View file

@ -5,8 +5,8 @@ module("luci.controller.travelmate", package.seeall)
local fs = require("nixio.fs") local fs = require("nixio.fs")
local util = require("luci.util") local util = require("luci.util")
local template = require("luci.template")
local i18n = require("luci.i18n") local i18n = require("luci.i18n")
local templ = require("luci.template")
function index() function index()
if not nixio.fs.access("/etc/config/travelmate") then if not nixio.fs.access("/etc/config/travelmate") then
@ -14,15 +14,21 @@ function index()
end end
entry({"admin", "services", "travelmate"}, firstchild(), _("Travelmate"), 40).dependent = false entry({"admin", "services", "travelmate"}, firstchild(), _("Travelmate"), 40).dependent = false
entry({"admin", "services", "travelmate", "tab_from_cbi"}, cbi("travelmate/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true entry({"admin", "services", "travelmate", "tab_from_cbi"}, cbi("travelmate/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true
entry({"admin", "services", "travelmate", "logfile"}, call("logread"), _("View Logfile"), 20).leaf = true entry({"admin", "services", "travelmate", "stations"}, template("travelmate/stations"), _("Wireless Stations"), 20).leaf = true
entry({"admin", "services", "travelmate", "logfile"}, call("logread"), _("View Logfile"), 30).leaf = true
entry({"admin", "services", "travelmate", "advanced"}, firstchild(), _("Advanced"), 100) entry({"admin", "services", "travelmate", "advanced"}, firstchild(), _("Advanced"), 100)
entry({"admin", "services", "travelmate", "advanced", "configuration"}, cbi("travelmate/configuration_tab"), _("Edit Travelmate Configuration"), 110).leaf = true entry({"admin", "services", "travelmate", "advanced", "configuration"}, cbi("travelmate/configuration_tab"), _("Edit Travelmate Configuration"), 110).leaf = true
entry({"admin", "services", "travelmate", "advanced", "cfg_wireless"}, cbi("travelmate/cfg_wireless_tab"), _("Edit Wireless Configuration"), 120).leaf = true entry({"admin", "services", "travelmate", "advanced", "cfg_wireless"}, cbi("travelmate/cfg_wireless_tab"), _("Edit Wireless Configuration"), 120).leaf = true
entry({"admin", "services", "travelmate", "advanced", "cfg_network"}, cbi("travelmate/cfg_network_tab"), _("Edit Network Configuration"), 130).leaf = true entry({"admin", "services", "travelmate", "advanced", "cfg_network"}, cbi("travelmate/cfg_network_tab"), _("Edit Network Configuration"), 130).leaf = true
entry({"admin", "services", "travelmate", "advanced", "cfg_firewall"}, cbi("travelmate/cfg_firewall_tab"), _("Edit Firewall Configuration"), 140).leaf = true entry({"admin", "services", "travelmate", "advanced", "cfg_firewall"}, cbi("travelmate/cfg_firewall_tab"), _("Edit Firewall Configuration"), 140).leaf = true
entry({"admin", "services", "travelmate", "wifiscan"}, template("travelmate/wifi_scan")).leaf = true
entry({"admin", "services", "travelmate", "wifiadd"}, cbi("travelmate/wifi_add", {hideresetbtn=true, hidesavebtn=true})).leaf = true
entry({"admin", "services", "travelmate", "wifiedit"}, cbi("travelmate/wifi_edit", {hideresetbtn=true, hidesavebtn=true})).leaf = true
entry({"admin", "services", "travelmate", "wifidelete"}, cbi("travelmate/wifi_delete", {hideresetbtn=true, hidesavebtn=true})).leaf = true
end end
function logread() function logread()
local logfile = util.trim(util.exec("logread -e 'travelmate'")) local logfile = util.trim(util.exec("logread -e 'travelmate'"))
template.render("travelmate/logread", {title = i18n.translate("Travelmate Logfile"), content = logfile}) templ.render("travelmate/logread", {title = i18n.translate("Travelmate Logfile"), content = logfile})
end end

View file

@ -2,12 +2,13 @@
-- This is free software, licensed under the Apache License, Version 2.0 -- This is free software, licensed under the Apache License, Version 2.0
local fs = require("nixio.fs") local fs = require("nixio.fs")
local uci = require("uci") local uci = require("luci.model.uci").cursor()
local json = require("luci.jsonc") local json = require("luci.jsonc")
local nw = require("luci.model.network").init() local nw = require("luci.model.network").init()
local fw = require("luci.model.firewall").init() local fw = require("luci.model.firewall").init()
local uplink = uci.get("network", "trm_wwan") or "" local trmiface = uci.get("travelmate", "global", "trm_iface") or "trm_wwan"
local trminput = uci.get("travelmate", "global", "trm_rtfile") or "/tmp/trm_runtime.json" local trminput = uci.get("travelmate", "global", "trm_rtfile") or "/tmp/trm_runtime.json"
local uplink = uci.get("network", trmiface) or ""
local parse = json.parse(fs.readfile(trminput) or "") local parse = json.parse(fs.readfile(trminput) or "")
m = Map("travelmate", translate("Travelmate"), m = Map("travelmate", translate("Travelmate"),
@ -21,10 +22,56 @@ function m.on_after_commit(self)
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate")) luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate"))
end end
-- Main travelmate options
s = m:section(NamedSection, "global", "travelmate") s = m:section(NamedSection, "global", "travelmate")
-- Interface Wizard
if uplink == "" then
dv = s:option(DummyValue, "nil", translate("Interface Wizard"))
dv.template = "cbi/nullsection"
o = s:option(Value, "trm_iface", translate("Uplink interface"))
o.datatype = "and(uciname,rangelength(3,15))"
o.default = "trm_wwan"
o.rmempty = false
function o.validate(self, value)
iface = value
return iface
end
function o.write(self, section, value)
uci:set("travelmate", section, "trm_iface", iface)
uci:save("travelmate")
uci:commit("travelmate")
end
btn = s:option(Button, "", translate("Create Uplink Interface"),
translate("Create a new wireless wan uplink interface, configure it to use dhcp and ")
.. translate("add it to the wan zone of the firewall. This step has only to be done once."))
btn.inputtitle = translate("Add Interface")
btn.inputstyle = "apply"
btn.disabled = false
function btn.write()
local net = nw:add_network(iface, { proto = "dhcp" })
if net then
nw:save("network")
nw:commit("network")
local zone = fw:get_zone_by_network("wan")
if zone then
zone:add_network(iface)
fw:save("firewall")
fw:commit("firewall")
luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1")
end
end
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate"))
end
return m
end
-- Main travelmate options
o1 = s:option(Flag, "trm_enabled", translate("Enable travelmate")) o1 = s:option(Flag, "trm_enabled", translate("Enable travelmate"))
o1.default = o1.disabled o1.default = o1.disabled
o1.rmempty = false o1.rmempty = false
@ -34,10 +81,11 @@ o2 = s:option(Flag, "trm_automatic", translate("Enable 'automatic' mode"),
o2.default = o2.enabled o2.default = o2.enabled
o2.rmempty = false o2.rmempty = false
o3 = s:option(Value, "trm_iface", translate("Restrict interface trigger to certain interface(s)"), o3 = s:option(Value, "trm_iface", translate("Uplink / Trigger interface"),
translate("Space separated list of interfaces that trigger travelmate processing. ".. translate("Name of the uplink interface that triggers travelmate processing."))
"To disable event driven (re-)starts remove all entries.")) o3.datatype = "and(uciname,rangelength(3,15))"
o3.rmempty = true o3.default = "trm_wwan"
o3.rmempty = false
o4 = s:option(Value, "trm_triggerdelay", translate("Trigger delay"), o4 = s:option(Value, "trm_triggerdelay", translate("Trigger delay"),
translate("Additional trigger delay in seconds before travelmate processing begins.")) translate("Additional trigger delay in seconds before travelmate processing begins."))
@ -49,42 +97,6 @@ o5 = s:option(Flag, "trm_debug", translate("Enable verbose debug logging"))
o5.default = o5.disabled o5.default = o5.disabled
o5.rmempty = false o5.rmempty = false
-- Interface setup
if uplink == "" then
dv = s:option(DummyValue, "_dummy", translate("Interface Setup"))
dv.template = "cbi/nullsection"
btn = s:option(Button, "", translate("Create Uplink Interface"),
translate("Automatically create a new wireless wan uplink interface 'trm_wwan', configure it to use dhcp and ")
.. translate("add it to the wan zone of the firewall. This step has only to be done once."))
btn.inputtitle = translate("Add Interface")
btn.inputstyle = "apply"
btn.disabled = false
function btn.write()
local name = "trm_wwan"
local net = nw:add_network(name, { proto = "dhcp" })
if net then
nw:save("network")
nw:commit("network")
local zone = fw:get_zone_by_network("wan")
if zone then
zone:add_network(name)
fw:save("firewall")
fw:commit("firewall")
end
luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1")
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate"))
end
end
else
dv = s:option(DummyValue, "_dummy", translate("Interface Setup"),
translate("<br />&nbsp;Network Interface 'trm_wwan' created successfully. ")
.. translatef("Scan &amp; Add new wireless stations via standard "
.. "<a href=\"%s\">"
.. "Wireless Setup</a>", luci.dispatcher.build_url("admin/network/wireless")))
dv.template = "cbi/nullsection"
end
-- Runtime information -- Runtime information
ds = s:option(DummyValue, "_dummy", translate("Runtime information")) ds = s:option(DummyValue, "_dummy", translate("Runtime information"))

View file

@ -0,0 +1,65 @@
-- Copyright 2017 Dirk Brenken (dev@brenken.org)
-- This is free software, licensed under the Apache License, Version 2.0
local fs = require("nixio.fs")
local uci = require("luci.model.uci").cursor()
local http = require("luci.http")
local trmiface = uci.get("travelmate", "global", "trm_iface") or "trm_wwan"
m = SimpleForm("add", translate("Add Wireless Uplink Configuration"))
m.cancel = translate("Back to overview")
m.reset = false
function m.on_cancel()
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
end
m.hidden = {
device = http.formvalue("device"),
ssid = http.formvalue("ssid"),
wep = http.formvalue("wep"),
wpa_suites = http.formvalue("wpa_suites"),
wpa_version = http.formvalue("wpa_version")
}
wssid = m:field(Value, "ssid", translate("SSID"))
wssid.default = m.hidden.ssid
if (tonumber(m.hidden.wep) or 0) == 1 then
wkey = m:field(Value, "key", translate("WEP passphrase"),
translate("Specify the secret encryption key here."))
wkey.password = true
wkey.datatype = "wepkey"
elseif (tonumber(m.hidden.wpa_version) or 0) > 0 and
(m.hidden.wpa_suites == "PSK" or m.hidden.wpa_suites == "PSK2")
then
wkey = m:field(Value, "key", translate("WPA passphrase"),
translate("Specify the secret encryption key here."))
wkey.password = true
wkey.datatype = "wpakey"
end
function wssid.write(self, section, value)
newsection = uci:section("wireless", "wifi-iface", nil, {
mode = "sta",
network = trmiface,
device = m.hidden.device,
ssid = wssid:formvalue(section),
disabled = "1"
})
if (tonumber(m.hidden.wep) or 0) == 1 then
uci:set("wireless", newsection, "encryption", "wep-open")
uci:set("wireless", newsection, "key", "1")
uci:set("wireless", newsection, "key1", wkey:formvalue(section))
elseif (tonumber(m.hidden.wpa_version) or 0) > 0 then
uci:set("wireless", newsection, "encryption", "psk2")
uci:set("wireless", newsection, "key", wkey:formvalue(section))
else
uci:set("wireless", newsection, "encryption", "none")
end
uci:save("wireless")
uci:commit("wireless")
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
end
return m

View file

@ -0,0 +1,14 @@
-- Copyright 2017 Dirk Brenken (dev@brenken.org)
-- This is free software, licensed under the Apache License, Version 2.0
local uci = require("luci.model.uci").cursor()
local http = require("luci.http")
local cfg = http.formvalue("cfg")
if cfg ~= nil then
uci:delete("wireless", cfg)
uci:save("wireless")
uci:commit("wireless")
end
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))

View file

@ -0,0 +1,49 @@
-- Copyright 2017 Dirk Brenken (dev@brenken.org)
-- This is free software, licensed under the Apache License, Version 2.0
local fs = require("nixio.fs")
local uci = require("luci.model.uci").cursor()
local http = require("luci.http")
m = SimpleForm("edit", translate("Edit Wireless Uplink Configuration"))
m.cancel = translate("Back to overview")
m.reset = false
function m.on_cancel()
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
end
m.hidden = {
cfg = http.formvalue("cfg")
}
local s = uci:get_all("wireless", m.hidden.cfg)
if s ~= nil then
wssid = m:field(Value, "ssid", translate("SSID"))
wssid.default = s.ssid
if s.encryption and s.key then
wkey = m:field(Value, "key", translatef("Passphrase (%s)", s.encryption))
wkey.password = true
wkey.default = s.key
if s.encryption == "wep" then
wkey.datatype = "wepkey"
else
wkey.datatype = "wpakey"
end
end
else
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
end
function wssid.write(self, section, value)
uci:set("wireless", m.hidden.cfg, "ssid", wssid:formvalue(section))
if s.encryption and s.key then
uci:set("wireless", m.hidden.cfg, "key", wkey:formvalue(section))
end
uci:save("wireless")
uci:commit("wireless")
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
end
return m

View file

@ -5,6 +5,6 @@ This is free software, licensed under the Apache License, Version 2.0
<%+cbi/valueheader%> <%+cbi/valueheader%>
<input name="runtime" id="runtime" type="text" class="cbi-input-text" style="border: none; box-shadow: none; background-color: #ffffff; color: #0069d6;" value="<%=self:cfgvalue(section)%>" disabled="disabled" /> <input name="runtime" id="runtime" type="text" class="cbi-input-text" style="border:none; box-shadow:none; background-color:#ffffff; color:#0069d6;" value="<%=self:cfgvalue(section)%>" disabled="disabled" />
<%+cbi/valuefooter%> <%+cbi/valuefooter%>

View file

@ -0,0 +1,73 @@
<%#
Copyright 2017 Dirk Brenken (dev@brenken.org)
This is free software, licensed under the Apache License, Version 2.0
-%>
<%-
local write = io.write
local uci = require "luci.model.uci".cursor()
local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan"
-%>
<%+header%>
<div class="cbi-map">
<h2 name="content"><%:Wireless Stations%></h2>
<div class="cbi-map-descr"><%:Provides an overview of all configured uplink interfaces for travelmate. You can edit and delete existing interfaces or scan for new uplinks.%></div>
<fieldset class="cbi-section">
<table class="cbi-section-table" style="empty-cells:hide">
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell" style="text-align:left"><%:Device%></th>
<th class="cbi-section-table-cell" style="text-align:left"><%:Mode%></th>
<th class="cbi-section-table-cell" style="text-align:left"><%:Uplink Interface%></th>
<th class="cbi-section-table-cell" style="text-align:left"><%:SSID%></th>
<th class="cbi-section-table-cell" style="text-align:left"><%:Encryption%></th>
<th class="cbi-section-table-cell" style="text-align:left" colspan="2"><%:Disabled%></th>
</tr>
<%
uci:foreach("wireless", "wifi-iface", function(s)
local section = s['.name']
local device = s.device or ""
local mode = s.mode or ""
local iface = s.network or ""
local ssid = s.ssid or ""
local encryption = s.encryption or ""
local disabled = s.disabled or ""
if iface == trmiface then
%>
<tr class="cbi-section-table-row cbi-rowstyle-6">
<td style="text-align:left"><%=device%></td>
<td style="text-align:left"><%=mode%></td>
<td style="text-align:left"><%=iface%></td>
<td style="text-align:left"><%=ssid%></td>
<td style="text-align:left"><%=encryption%></td>
<td style="text-align:left"><%=disabled%></td>
<td class="cbi-value-field" style="width:200px;text-align:right">
<input type="button" class="cbi-button cbi-button-edit" style="width:85px" onclick="location.href='<%=url('admin/services/travelmate/wifiedit')%>?cfg=<%=section%>'" title="<%:Edit this Uplink%>" value="<%:Edit%>" />
<input type="button" class="cbi-button cbi-button-remove" style="width:85px" onclick="location.href='<%=url('admin/services/travelmate/wifidelete')%>?cfg=<%=section%>'" title="<%:Delete this Uplink%>" value="<%:Delete%>"/>
</td>
</tr>
<%
end
end)
%>
</table>
</fieldset>
<div class="cbi-page-actions right">
<%
uci:foreach("wireless", "wifi-device", function(s)
local device = s[".name"]
%>
<form class="inline" action="<%=url('admin/services/travelmate/wifiscan')%>" method="post">
<input type="hidden" name="device" value="<%=device%>" />
<input type="hidden" name="token" value="<%=token%>" />
<input type="submit" class="cbi-button cbi-button-find" style="width:110px" title="<%:Find and join network on %><%=device%>" value="<%:Scan %><%=device%>" />
</form>
<%
end)
%>
</div>
<%+footer%>

View file

@ -0,0 +1,108 @@
<%#
Copyright 2017 Dirk Brenken (dev@brenken.org)
This is free software, licensed under the Apache License, Version 2.0
-%>
<%-
local sys = require "luci.sys"
local utl = require "luci.util"
local dev = luci.http.formvalue("device")
local iw = luci.sys.wifi.getiwinfo(dev)
if not iw then
luci.http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
end
function format_wifi_encryption(info)
if info.wep == true then
return translate("WEP")
elseif info.wpa > 0 then
return translate("WPA / WPA2")
elseif info.enabled then
return translate("Unknown")
else
return translate("Open")
end
end
function percent_wifi_signal(info)
local qc = info.quality or 0
local qm = info.quality_max or 0
if info.bssid and qc > 0 and qm > 0 then
return math.floor((100 / qm) * qc)
else
return 0
end
end
function scanlist(times)
local i, k, v
local l = { }
local s = { }
for i = 1, times do
for k, v in ipairs(iw.scanlist or { }) do
if not s[v.bssid] then
l[#l+1] = v
s[v.bssid] = true
end
end
end
return l
end
-%>
<%+header%>
<div class="cbi-map">
<h2 name="content"><%:Wireless Scan%></h2>
<fieldset class="cbi-section">
<table class="cbi-section-table" style="empty-cells:hide">
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell" style="text-align:left"><%:Uplink SSID%></th>
<th class="cbi-section-table-cell" style="text-align:left"><%:Encryption%></th>
<th class="cbi-section-table-cell" style="text-align:left" colspan="2"><%:Signal strength%></th>
</tr>
<% for i, net in ipairs(scanlist(3)) do net.encryption = net.encryption or { } %>
<tr class="cbi-section-table-row cbi-rowstyle-4">
<td class="cbi-value-field" style="text-align:left">
<strong><%=net.ssid and utl.pcdata(net.ssid) or "<em>%s</em>" % translate("hidden")%></strong>
</td>
<td class="cbi-value-field" style="text-align:left">
<%=format_wifi_encryption(net.encryption)%>
</td>
<td class="cbi-value-field" style="text-align:left">
<%=percent_wifi_signal(net)%> %
</td>
<td class="cbi-value-field" style="width:120px; text-align:right">
<form class="inline" action="<%=url('admin/services/travelmate/wifiadd')%>" method="post">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="device" value="<%=utl.pcdata(dev)%>" />
<input type="hidden" name="ssid" value="<%=utl.pcdata(net.ssid)%>" />
<input type="hidden" name="wep" value="<%=net.encryption.wep and 1 or 0%>" />
<% if net.encryption.wpa then %>
<input type="hidden" name="wpa_version" value="<%=net.encryption.wpa%>" />
<% for _, v in ipairs(net.encryption.auth_suites) do %><input type="hidden" name="wpa_suites" value="<%=v%>" />
<% end; for _, v in ipairs(net.encryption.group_ciphers) do %><input type="hidden" name="wpa_group" value="<%=v%>" />
<% end; for _, v in ipairs(net.encryption.pair_ciphers) do %><input type="hidden" name="wpa_pairwise" value="<%=v%>" />
<% end; end %>
<input class="cbi-button cbi-button-apply" style="width:110px" type="submit" value="<%:Add Uplink%>" />
</form>
</td>
</tr>
<% end %>
</table>
</fieldset>
<div class="cbi-page-actions right">
<form class="inline" action="<%=url('admin/services/travelmate/stations')%>" method="post">
<input class="cbi-button cbi-button-reset" type="submit" value="<%:Back to overview%>" />
</form>
<form class="inline" action="<%=url('admin/services/travelmate/wifiscan')%>" method="post">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="device" value="<%=utl.pcdata(dev)%>" />
<input class="cbi-button cbi-input-find" type="submit" value="<%:Repeat scan%>" />
</form>
</div>
<%+footer%>