summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--applications/luci-app-coovachilli/luasrc/model/cbi/coovachilli_network.lua10
-rw-r--r--applications/luci-app-ddns/Makefile27
-rw-r--r--applications/luci-app-ddns/luasrc/controller/ddns.lua45
-rw-r--r--applications/luci-app-ddns/luasrc/model/cbi/ddns/detail.lua2
-rw-r--r--applications/luci-app-ddns/luasrc/model/cbi/ddns/hints.lua3
-rw-r--r--applications/luci-app-ddns/luasrc/model/cbi/ddns/overview.lua16
-rw-r--r--applications/luci-app-ddns/luasrc/tools/ddns.lua42
-rw-r--r--applications/luci-app-ddns/luasrc/view/ddns/detail_lvalue.htm2
-rw-r--r--applications/luci-app-ddns/luasrc/view/ddns/detail_value.htm2
-rw-r--r--applications/luci-app-ddns/luasrc/view/ddns/overview_startstop.htm2
-rw-r--r--applications/luci-app-ddns/luasrc/view/ddns/overview_status.htm36
-rw-r--r--applications/luci-app-ddns/luasrc/view/ddns/system_status.htm7
-rw-r--r--applications/luci-app-ddns/po/de/ddns.po118
-rw-r--r--applications/luci-app-ddns/po/templates/ddns.pot102
-rw-r--r--applications/luci-app-firewall/luasrc/view/firewall/cbi_addforward.htm3
-rw-r--r--applications/luci-app-ocserv/luasrc/controller/ocserv.lua2
-rw-r--r--applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua2
-rw-r--r--applications/luci-app-ocserv/luasrc/model/cbi/ocserv/users.lua2
-rw-r--r--applications/luci-app-olsr/luasrc/controller/olsr.lua105
-rw-r--r--applications/luci-app-privoxy/Makefile38
-rwxr-xr-xapplications/luci-app-privoxy/luasrc/controller/privoxy.lua117
-rwxr-xr-xapplications/luci-app-privoxy/luasrc/model/cbi/privoxy/apperror.lua47
-rwxr-xr-xapplications/luci-app-privoxy/luasrc/model/cbi/privoxy/detail.lua928
-rwxr-xr-xapplications/luci-app-privoxy/luasrc/view/privoxy/detail_logview.htm56
-rw-r--r--applications/luci-app-privoxy/luasrc/view/privoxy/detail_startstop.htm49
-rw-r--r--applications/luci-app-privoxy/po/de/privoxy.po496
-rw-r--r--applications/luci-app-privoxy/po/templates/privoxy.pot405
-rwxr-xr-xapplications/luci-app-privoxy/root/etc/uci-defaults/luci-privoxy12
-rw-r--r--applications/luci-app-siitwizard/luasrc/model/cbi/siitwizard.lua29
-rw-r--r--applications/luci-app-splash/luasrc/controller/splash/splash.lua20
-rw-r--r--applications/luci-app-splash/luasrc/view/admin_status/splash.htm11
-rwxr-xr-xapplications/luci-app-splash/root/usr/sbin/luci-splash77
-rwxr-xr-xbuild/luadoc/doc.lua (renamed from contrib/luadoc/hostfiles/bin/luadoc)7
-rw-r--r--build/luadoc/luadoc/config.lua (renamed from contrib/luadoc/lua/luadoc/config.lua)0
-rw-r--r--build/luadoc/luadoc/doclet/debug.lua (renamed from contrib/luadoc/lua/luadoc/doclet/debug.lua)0
-rw-r--r--build/luadoc/luadoc/doclet/formatter.lua (renamed from contrib/luadoc/lua/luadoc/doclet/formatter.lua)0
-rw-r--r--build/luadoc/luadoc/doclet/html.lua (renamed from contrib/luadoc/lua/luadoc/doclet/html.lua)0
-rw-r--r--build/luadoc/luadoc/doclet/html/constant.lp (renamed from contrib/luadoc/lua/luadoc/doclet/html/constant.lp)0
-rw-r--r--build/luadoc/luadoc/doclet/html/file.lp (renamed from contrib/luadoc/lua/luadoc/doclet/html/file.lp)2
-rw-r--r--build/luadoc/luadoc/doclet/html/function.lp (renamed from contrib/luadoc/lua/luadoc/doclet/html/function.lp)4
-rw-r--r--build/luadoc/luadoc/doclet/html/index.lp (renamed from contrib/luadoc/lua/luadoc/doclet/html/index.lp)0
-rw-r--r--build/luadoc/luadoc/doclet/html/luadoc.css (renamed from contrib/luadoc/lua/luadoc/doclet/html/luadoc.css)11
-rw-r--r--build/luadoc/luadoc/doclet/html/menu.lp (renamed from contrib/luadoc/lua/luadoc/doclet/html/menu.lp)0
-rw-r--r--build/luadoc/luadoc/doclet/html/module.lp (renamed from contrib/luadoc/lua/luadoc/doclet/html/module.lp)53
-rw-r--r--build/luadoc/luadoc/doclet/html/table.lp (renamed from contrib/luadoc/lua/luadoc/doclet/html/table.lp)0
-rw-r--r--build/luadoc/luadoc/doclet/raw.lua (renamed from contrib/luadoc/lua/luadoc/doclet/raw.lua)0
-rw-r--r--build/luadoc/luadoc/init.lua (renamed from contrib/luadoc/lua/luadoc/init.lua)0
-rw-r--r--build/luadoc/luadoc/lp.lua (renamed from contrib/luadoc/lua/luadoc/lp.lua)0
-rw-r--r--build/luadoc/luadoc/taglet/standard.lua (renamed from contrib/luadoc/lua/luadoc/taglet/standard.lua)6
-rw-r--r--build/luadoc/luadoc/taglet/standard/tags.lua (renamed from contrib/luadoc/lua/luadoc/taglet/standard/tags.lua)15
-rw-r--r--build/luadoc/luadoc/util.lua (renamed from contrib/luadoc/lua/luadoc/util.lua)28
-rwxr-xr-xbuild/makedocs.sh16
-rwxr-xr-xbuild/zoneinfo2lua.pl24
-rw-r--r--contrib/luadoc/Makefile2
-rw-r--r--libs/luci-lib-httpclient/luasrc/httpclient.lua42
-rw-r--r--libs/luci-lib-ip/Makefile14
-rw-r--r--libs/luci-lib-ip/src/Makefile17
-rw-r--r--libs/luci-lib-ip/src/ip.c1392
-rw-r--r--libs/luci-lib-ip/src/ip.luadoc831
-rw-r--r--libs/luci-lib-json/luasrc/json.lua35
-rw-r--r--libs/luci-lib-json/luasrc/json.luadoc94
-rw-r--r--libs/luci-lib-jsonc/Makefile14
-rw-r--r--libs/luci-lib-jsonc/src/Makefile17
-rw-r--r--libs/luci-lib-jsonc/src/jsonc.c388
-rw-r--r--libs/luci-lib-jsonc/src/jsonc.luadoc134
-rw-r--r--libs/luci-lib-nixio/docsrc/CHANGELOG.lua4
-rw-r--r--libs/luci-lib-nixio/docsrc/README.lua4
-rw-r--r--libs/luci-lib-nixio/src/Makefile2
-rw-r--r--libs/luci-lib-rpcc/luasrc/rpcc.lua15
-rw-r--r--libs/luci-lib-rpcc/luasrc/rpcc.luadoc36
-rw-r--r--libs/luci-lib-rpcc/luasrc/rpcc/ruci.lua5
-rw-r--r--libs/luci-lib-rpcc/luasrc/rpcc/ruci.luadoc16
-rw-r--r--luci.mk1
-rw-r--r--modules/luci-base/Makefile2
-rw-r--r--modules/luci-base/luasrc/dispatcher.lua84
-rw-r--r--modules/luci-base/luasrc/dispatcher.luadoc220
-rw-r--r--modules/luci-base/luasrc/http.lua90
-rw-r--r--modules/luci-base/luasrc/http.luadoc166
-rw-r--r--modules/luci-base/luasrc/http/protocol.lua62
-rw-r--r--modules/luci-base/luasrc/http/protocol.luadoc142
-rw-r--r--modules/luci-base/luasrc/http/protocol/conditionals.lua31
-rw-r--r--modules/luci-base/luasrc/http/protocol/conditionals.luadoc85
-rw-r--r--modules/luci-base/luasrc/http/protocol/date.lua16
-rw-r--r--modules/luci-base/luasrc/http/protocol/date.luadoc46
-rw-r--r--modules/luci-base/luasrc/http/protocol/mime.lua9
-rw-r--r--modules/luci-base/luasrc/http/protocol/mime.luadoc34
-rw-r--r--modules/luci-base/luasrc/i18n.lua26
-rw-r--r--modules/luci-base/luasrc/i18n.luadoc84
-rw-r--r--modules/luci-base/luasrc/ip.lua661
-rw-r--r--modules/luci-base/luasrc/ltn12.lua76
-rw-r--r--modules/luci-base/luasrc/model/ipkg.lua38
-rw-r--r--modules/luci-base/luasrc/model/ipkg.luadoc109
-rw-r--r--modules/luci-base/luasrc/model/uci.lua179
-rw-r--r--modules/luci-base/luasrc/model/uci.luadoc291
-rw-r--r--modules/luci-base/luasrc/sys.lua199
-rw-r--r--modules/luci-base/luasrc/sys.luadoc396
-rw-r--r--modules/luci-base/luasrc/sys/iptparser.lua24
-rw-r--r--modules/luci-base/luasrc/sys/iptparser.luadoc69
-rw-r--r--modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua8
-rw-r--r--modules/luci-base/luasrc/sys/zoneinfo/tzoffset.lua6
-rw-r--r--modules/luci-base/luasrc/tools/webadmin.lua111
-rw-r--r--modules/luci-base/luasrc/util.lua176
-rw-r--r--modules/luci-base/luasrc/util.luadoc378
-rw-r--r--modules/luci-mod-admin-full/luasrc/controller/admin/system.lua8
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua13
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua18
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/routes.lua12
-rw-r--r--modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview.htm8
-rw-r--r--modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm117
-rw-r--r--modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua14
-rw-r--r--modules/luci-mod-freifunk/luasrc/view/freifunk/public_status.htm53
-rw-r--r--protocols/luci-proto-openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua3
112 files changed, 7890 insertions, 2216 deletions
diff --git a/applications/luci-app-coovachilli/luasrc/model/cbi/coovachilli_network.lua b/applications/luci-app-coovachilli/luasrc/model/cbi/coovachilli_network.lua
index e1a084a98d..025bc1795b 100644
--- a/applications/luci-app-coovachilli/luasrc/model/cbi/coovachilli_network.lua
+++ b/applications/luci-app-coovachilli/luasrc/model/cbi/coovachilli_network.lua
@@ -2,8 +2,8 @@
-- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
-require("luci.sys")
-require("luci.ip")
+local sys = require"luci.sys"
+local ip = require "luci.ip"
m = Map("coovachilli")
@@ -16,8 +16,8 @@ s1:option( Value, "tundev" ).optional = true
s1:option( Value, "txqlen" ).optional = true
net = s1:option( Value, "net" )
-for _, route in ipairs(luci.sys.net.routes()) do
- if route.device ~= "lo" and route.dest:prefix() < 32 then
+for _, route in ipairs(ip.routes({ family = 4, type = 1 })) do
+ if route.dest:prefix() > 0 and route.dest:prefix() < 32 then
net:value( route.dest:string() )
end
end
@@ -41,7 +41,7 @@ s2 = m:section(TypedSection, "dhcp")
s2.anonymous = true
dif = s2:option( Value, "dhcpif" )
-for _, nif in ipairs(luci.sys.net.devices()) do
+for _, nif in ipairs(sys.net.devices()) do
if nif ~= "lo" then dif:value(nif) end
end
diff --git a/applications/luci-app-ddns/Makefile b/applications/luci-app-ddns/Makefile
index d116f06a46..18906cd1c2 100644
--- a/applications/luci-app-ddns/Makefile
+++ b/applications/luci-app-ddns/Makefile
@@ -6,17 +6,32 @@
include $(TOPDIR)/rules.mk
-LUCI_TITLE:=LuCI Support for Dynamic DNS (ddns-scripts)
-LUCI_DEPENDS:=+ddns-scripts +luci-mod-admin-full
+# LuCI specific settings
+LUCI_TITLE:=LuCI Support for Dynamic DNS Client (ddns-scripts)
+LUCI_DEPENDS:=+luci-mod-admin-full +ddns-scripts
PKG_NAME:=luci-app-ddns
-PKG_VERSION:=2.1.0
-PKG_RELEASE:=4
-PKG_LICENSE:=Apache-2.0
-PKGARCH:=all
+# Version == major.minor.patch
+# increase on new functionality (minor) or patches (patch)
+PKG_VERSION:=2.1.1
+
+# Release == build
+# increase on changes of translation files
+PKG_RELEASE:=0
+
+PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
+define Package/$(PKG_NAME)/config
+# shown in make menuconfig <Help>
+help
+ $(LUCI_TITLE)
+
+ Version : $(PKG_VERSION)-$(PKG_RELEASE)
+ Maintainer: $(PKG_MAINTAINER)
+endef
+
include ../../luci.mk
# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-ddns/luasrc/controller/ddns.lua b/applications/luci-app-ddns/luasrc/controller/ddns.lua
index 3cd52e5e3c..56d2b66e21 100644
--- a/applications/luci-app-ddns/luasrc/controller/ddns.lua
+++ b/applications/luci-app-ddns/luasrc/controller/ddns.lua
@@ -15,19 +15,21 @@ local SYS = require "luci.sys"
local DDNS = require "luci.tools.ddns" -- ddns multiused functions
local UTIL = require "luci.util"
-local luci_ddns_version = "2.1.0-4" -- luci-app-ddns / openwrt Makefile compatible version
-local ddns_scripts_min = "2.1.0-3" -- minimum version of ddns-scripts required
+DDNS_MIN = "2.1.0-2" -- minimum version of service required
function index()
- -- no services_ipv6 file or no dynamic_dns_lucihelper.sh
- -- do NOT start
- if not nixio.fs.access("/usr/lib/ddns/services_ipv6")
- or not nixio.fs.access("/usr/lib/ddns/dynamic_dns_lucihelper.sh") then
+ local nxfs = require "nixio.fs" -- global definitions not available
+ local sys = require "luci.sys" -- in function index()
+ local ddns = require "luci.tools.ddns" -- ddns multiused functions
+ local verinst = ddns.ipkg_ver_installed("ddns-scripts")
+ local verok = ddns.ipkg_ver_compare(verinst, ">=", "2.0.0-0")
+ -- do NOT start it not ddns-scripts version 2.x
+ if not verok then
return
end
-- no config create an empty one
- if not nixio.fs.access("/etc/config/ddns") then
- nixio.fs.writefile("/etc/config/ddns", "")
+ if not nxfs.access("/etc/config/ddns") then
+ nxfs.writefile("/etc/config/ddns", "")
end
entry( {"admin", "services", "ddns"}, cbi("ddns/overview"), _("Dynamic DNS"), 59)
@@ -44,17 +46,11 @@ local function _get_status()
local uci = UCI.cursor()
local service = SYS.init.enabled("ddns") and 1 or 0
local url_start = DISP.build_url("admin", "system", "startup")
- local luci_build = DDNS.ipkg_version("luci-app-ddns").version
- local ddns_act = DDNS.ipkg_version("ddns-scripts").version
local data = {} -- Array to transfer data to javascript
data[#data+1] = {
enabled = service, -- service enabled
url_up = url_start, -- link to enable DDS (System-Startup)
- luci_ver = luci_ddns_version, -- luci-app-ddns / openwrt Makefile compatible version
- luci_build = luci_build, -- installed luci build
- script_min = ddns_scripts_min, -- minimum version of ddns-scripts needed
- script_ver = ddns_act -- installed ddns-scripts
}
uci:foreach("ddns", "service", function (s)
@@ -63,8 +59,8 @@ local function _get_status()
-- and enabled state
local section = s[".name"]
local enabled = tonumber(s["enabled"]) or 0
- local datelast = "_empty_" -- formated date of last update
- local datenext = "_empty_" -- formated date of next update
+ local datelast = "_empty_" -- formatted date of last update
+ local datenext = "_empty_" -- formatted date of next update
-- get force seconds
local force_seconds = DDNS.calc_seconds(
@@ -182,7 +178,7 @@ function startstop(section, enabled)
return
end
- -- read uncommited changes
+ -- read uncommitted changes
-- we don't save and commit data from other section or other options
-- only enabled will be done
local exec = true
@@ -210,9 +206,9 @@ function startstop(section, enabled)
end
-- we can not execute because other
- -- uncommited changes pending, so exit here
+ -- uncommitted changes pending, so exit here
if not exec then
- HTTP.write("_uncommited_")
+ HTTP.write("_uncommitted_")
return
end
@@ -238,14 +234,3 @@ function status()
HTTP.prepare_content("application/json")
HTTP.write_json(data)
end
-
--- check if installed ddns-scripts version < required version
-function update_needed()
- local sver = DDNS.ipkg_version("ddns-scripts")
- local rver = UTIL.split(ddns_scripts_min, "[%.%-]", nil, true)
- return (sver.major < (tonumber(rver[1]) or 0))
- or (sver.minor < (tonumber(rver[2]) or 0))
- or (sver.patch < (tonumber(rver[3]) or 0))
- or (sver.build < (tonumber(rver[4]) or 0))
-end
-
diff --git a/applications/luci-app-ddns/luasrc/model/cbi/ddns/detail.lua b/applications/luci-app-ddns/luasrc/model/cbi/ddns/detail.lua
index 057b8c8aa2..77753c03a7 100644
--- a/applications/luci-app-ddns/luasrc/model/cbi/ddns/detail.lua
+++ b/applications/luci-app-ddns/luasrc/model/cbi/ddns/detail.lua
@@ -22,7 +22,7 @@ has_ipv6 = DDNS.check_ipv6() -- IPv6 support
has_ssl = DDNS.check_ssl() -- HTTPS support
has_proxy = DDNS.check_proxy() -- Proxy support
has_dnstcp = DDNS.check_bind_host() -- DNS TCP support
-has_force = has_ssl and has_dnstcp -- Force IP Protocoll
+has_force = has_ssl and has_dnstcp -- Force IP Protocoll
-- html constants -- ###########################################################
font_red = "<font color='red'>"
diff --git a/applications/luci-app-ddns/luasrc/model/cbi/ddns/hints.lua b/applications/luci-app-ddns/luasrc/model/cbi/ddns/hints.lua
index 15da0289f1..009ba99eb8 100644
--- a/applications/luci-app-ddns/luasrc/model/cbi/ddns/hints.lua
+++ b/applications/luci-app-ddns/luasrc/model/cbi/ddns/hints.lua
@@ -11,7 +11,8 @@ local DDNS = require "luci.tools.ddns" -- ddns multiused functions
has_ssl = DDNS.check_ssl() -- HTTPS support
has_proxy = DDNS.check_proxy() -- Proxy support
has_dnstcp = DDNS.check_bind_host() -- DNS TCP support
-need_update = CTRL.update_needed() -- correct ddns-scripts version
+-- correct ddns-scripts version
+need_update = DDNS.ipkg_ver_compare(DDNS.ipkg_ver_installed("ddns-scripts"), "<<", CTRL.DDNS_MIN)
-- html constants
font_red = [[<font color="red">]]
diff --git a/applications/luci-app-ddns/luasrc/model/cbi/ddns/overview.lua b/applications/luci-app-ddns/luasrc/model/cbi/ddns/overview.lua
index 2944ec52f9..83b10e9366 100644
--- a/applications/luci-app-ddns/luasrc/model/cbi/ddns/overview.lua
+++ b/applications/luci-app-ddns/luasrc/model/cbi/ddns/overview.lua
@@ -14,7 +14,8 @@ show_hints = not (DDNS.check_ipv6() -- IPv6 support
and DDNS.check_proxy() -- Proxy support
and DDNS.check_bind_host() -- DNS TCP support
)
-need_update = CTRL.update_needed() -- correct ddns-scripts version
+-- correct ddns-scripts version
+need_update = DDNS.ipkg_ver_compare(DDNS.ipkg_ver_installed("ddns-scripts"), "<<", CTRL.DDNS_MIN)
-- html constants
font_red = [[<font color="red">]]
@@ -28,8 +29,17 @@ m = Map("ddns")
-- first need to close <a> from cbi map template our <a> closed by template
--m.title = [[</a><a href="javascript:alert(']] .. CTRL.show_versions() ..[[')">]] ..
-- translate("Dynamic DNS")
-m.title = [[</a><a href="#" onclick="onclick_maptitle();">]] ..
- translate("Dynamic DNS")
+m.title = [[</a><a href="javascript:alert(']]
+ .. translate("Version Information")
+ .. [[\n\nluci-app-ddns]]
+ .. [[\n\t]] .. translate("Version") .. [[:\t]] .. DDNS.ipkg_ver_installed("luci-app-ddns")
+ .. [[\n\nddns-scripts ]] .. translate("required") .. [[:]]
+ .. [[\n\t]] .. translate("Version") .. [[:\t]] .. CTRL.DDNS_MIN .. [[ ]] .. translate("or higher")
+ .. [[\n\nddns-scripts ]] .. translate("installed") .. [[:]]
+ .. [[\n\t]] .. translate("Version") .. [[:\t]] .. DDNS.ipkg_ver_installed("ddns-scripts")
+ .. [[\n\n]]
+ .. [[')">]]
+ .. translate("Dynamic DNS")
m.description = translate("Dynamic DNS allows that your router can be reached with " ..
"a fixed hostname while having a dynamically changing " ..
diff --git a/applications/luci-app-ddns/luasrc/tools/ddns.lua b/applications/luci-app-ddns/luasrc/tools/ddns.lua
index 5c8ced50b3..2fbcff8bad 100644
--- a/applications/luci-app-ddns/luasrc/tools/ddns.lua
+++ b/applications/luci-app-ddns/luasrc/tools/ddns.lua
@@ -96,33 +96,29 @@ function get_pid(section)
return pid
end
--- read version information for given package if installed
-function ipkg_version(package)
- if not package then
+-- compare versions using "<=" "<" ">" ">=" "=" "<<" ">>"
+function ipkg_ver_compare(ver1, comp, ver2)
+ if not ver1 or not (#ver1 > 0)
+ or not ver2 or not (#ver2 > 0)
+ or not comp or not (#comp > 0) then
return nil
end
- local info = OPKG.info(package)
- local data = {}
- local version = ""
- local i = 0
- for k, v in pairs(info) do
- if v.Package == package and v.Status.installed then
- version = v.Version
- i = i + 1
- end
+ return (tonumber(SYS.call(
+ [[opkg compare-versions "]] .. ver1 .. [[" "]] .. comp .. [[" "]] .. ver2 .. [["]]
+ )) == 1)
+end
+
+-- read version information for given package if installed
+function ipkg_ver_installed(pkg)
+ if not pkg then
+ return nil
end
- if i > 1 then -- more then one valid record
- return data
+ -- opkg list-installed [pkg] | cut -d " " -f 3 - return version as sting
+ local ver = SYS.exec([[opkg list-installed ]] .. pkg .. [[ | cut -d " " -f 3 ]])
+ if (#ver > 0) then
+ return ver
end
- local sver = UTIL.split(version, "[%.%-]", nil, true)
- data = {
- version = version,
- major = tonumber(sver[1]) or 0,
- minor = tonumber(sver[2]) or 0,
- patch = tonumber(sver[3]) or 0,
- build = tonumber(sver[4]) or 0
- }
- return data
+ return nil
end
-- replacement of build-in read of UCI option
diff --git a/applications/luci-app-ddns/luasrc/view/ddns/detail_lvalue.htm b/applications/luci-app-ddns/luasrc/view/ddns/detail_lvalue.htm
index d516837b2b..0bcfd44283 100644
--- a/applications/luci-app-ddns/luasrc/view/ddns/detail_lvalue.htm
+++ b/applications/luci-app-ddns/luasrc/view/ddns/detail_lvalue.htm
@@ -1,6 +1,6 @@
<!-- ++ BEGIN ++ Dynamic DNS ++ detail_lvalue.htm ++ -->
-<!-- no value header to supress next line -->
+<!-- no value header to suppress next line -->
&#160;
<% if self.widget == "select" then %>
<select class="cbi-input-select" onchange="cbi_d_update(this.id)"<%= attr("id", cbid) .. attr("name", cbid) .. ifattr(self.size, "size") %>>
diff --git a/applications/luci-app-ddns/luasrc/view/ddns/detail_value.htm b/applications/luci-app-ddns/luasrc/view/ddns/detail_value.htm
index 7cb28e282e..cbe76abc6e 100644
--- a/applications/luci-app-ddns/luasrc/view/ddns/detail_value.htm
+++ b/applications/luci-app-ddns/luasrc/view/ddns/detail_value.htm
@@ -5,5 +5,5 @@
attr("name", cbid) .. attr("id", cbid) .. attr("value", self:cfgvalue(section) or self.default) ..
ifattr(self.size, "size") .. ifattr(self.placeholder, "placeholder")
%> />
-<!-- no value footer to supress next line -->
+<!-- no value footer to suppress next line -->
<!-- ++ END ++ Dynamic DNS ++ detail_value.htm ++ -->
diff --git a/applications/luci-app-ddns/luasrc/view/ddns/overview_startstop.htm b/applications/luci-app-ddns/luasrc/view/ddns/overview_startstop.htm
index 8255aa63f3..327028cbea 100644
--- a/applications/luci-app-ddns/luasrc/view/ddns/overview_startstop.htm
+++ b/applications/luci-app-ddns/luasrc/view/ddns/overview_startstop.htm
@@ -6,7 +6,7 @@
-- We need to garantie that function cfgvalue run first to set missing parameters
%>
<!-- style="font-size: 100%;" needed for openwrt theme to fix font size -->
- <!-- type="button" onclick="..." enable standard onclick functionalty -->
+ <!-- type="button" onclick="..." enable standard onclick functionality -->
<input class="cbi-button cbi-input-<%=self.inputstyle or "button" %>" style="font-size: 100%;" type="button" onclick="onclick_startstop(this.id)"
<%=
attr("name", section) .. attr("id", cbid) .. attr("value", self.inputtitle) .. ifattr(self.disabled, "disabled")
diff --git a/applications/luci-app-ddns/luasrc/view/ddns/overview_status.htm b/applications/luci-app-ddns/luasrc/view/ddns/overview_status.htm
index 37c54be25f..6cca0e75d9 100644
--- a/applications/luci-app-ddns/luasrc/view/ddns/overview_status.htm
+++ b/applications/luci-app-ddns/luasrc/view/ddns/overview_status.htm
@@ -2,12 +2,6 @@
<!-- ++ BEGIN ++ Dynamic DNS ++ overview_status.htm ++ -->
<script type="text/javascript">//<![CDATA[
- // variables to store version information
- var luci_version
- var luci_build
- var ddns_version
- var ddns_required
-
// helper to extract section from objects id
// cbi.ddns.SECTION._xyz
function _id2section(id) {
@@ -19,13 +13,6 @@
// screen objects
// called by XHR.poll and onclick_startstop
function _data2elements(data) {
- // DDNS Service
- // fill Version informations
- luci_version = data[0].luci_ver
- luci_build = data[0].luci_build
- ddns_version = data[0].script_ver
- ddns_required = data[0].script_min
-
// Service sections
for( i = 1; i < data.length; i++ )
{
@@ -135,27 +122,13 @@
}
}
- // event handler for map.title link
- function onclick_maptitle() {
- var str = "<%:Version Information%>";
- str += "\n\nluci-app-ddns:";
- str += "\n\t<%:Version%>:\t" + luci_version;
- str += "\n\t<%:Build%>:\t" + luci_build;
- str += "\n\nddns-scripts <%:required%>:";
- str += "\n\t<%:Version%>:\t" + ddns_required + " <%:or greater%>";
- str += "\n\nddns-scripts <%:installed%>:";
- str += "\n\t<%:Version%>:\t" + ddns_version;
- str += "\n\n"
- alert(str);
- }
-
// event handler for start/stop button
function onclick_startstop(id) {
// extract section
var section = _id2section(id);
// get elements
var cbx = document.getElementById("cbid.ddns." + section + ".enabled"); // Enabled
- var obj = document.getElementById("cbi-ddns-overview-status-legend"); // objext defined below to make in-/visible
+ var obj = document.getElementById("cbi-ddns-overview-status-legend"); // object defined below to make in-/visible
if ( !(obj && cbx) ) { return; } // security check
// make me visible
@@ -165,7 +138,7 @@
var btnXHR = new XHR();
btnXHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "startstop")%>/' + section + '/' + cbx.checked, null,
function(x, data) {
- if (x.responseText == "_uncommited_") {
+ if (x.responseText == "_uncommitted_") {
// we need a trick to display Ampersand "&" in stead of "&#38;" or "&amp;"
// after translation
txt="<%:Please [Save & Apply] your changes first%>";
@@ -182,8 +155,9 @@
);
}
+ var ddns_ov_XHR = new XHR();
// force to immediate show status on page load (not waiting for XHR.poll)
- XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
+ ddns_ov_XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
function(x, data) {
_data2elements(data);
}
@@ -192,7 +166,7 @@
// define only ONE XHR.poll in a page because if one is running it blocks the other one
// optimum is to define on Map or Section Level from here you can reach all elements
// we need update every 15 seconds only
- XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
+ ddns_ov_XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
function(x, data) {
_data2elements(data);
}
diff --git a/applications/luci-app-ddns/luasrc/view/ddns/system_status.htm b/applications/luci-app-ddns/luasrc/view/ddns/system_status.htm
index db9d1d1a01..7c60726e24 100644
--- a/applications/luci-app-ddns/luasrc/view/ddns/system_status.htm
+++ b/applications/luci-app-ddns/luasrc/view/ddns/system_status.htm
@@ -106,7 +106,7 @@
break;
}
- // monitored interfacce
+ // monitored interface
if (data[i].iface == "_nonet_")
tr.insertCell(-1).innerHTML = '<em><%:Config error%></em>';
else
@@ -125,14 +125,15 @@
}
}
+ var ddns_status_XHR = new XHR();
// force to immediate show status (not waiting for XHR.poll)
- XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
+ ddns_status_XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
function(x, data) {
_data2elements(x, data);
}
);
- XHR.poll(10, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
+ ddns_status_XHR.poll(10, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
function(x, data) {
_data2elements(x, data);
}
diff --git a/applications/luci-app-ddns/po/de/ddns.po b/applications/luci-app-ddns/po/de/ddns.po
index 9706dbd106..b965a91fd3 100644
--- a/applications/luci-app-ddns/po/de/ddns.po
+++ b/applications/luci-app-ddns/po/de/ddns.po
@@ -1,10 +1,10 @@
msgid ""
msgstr ""
"Project-Id-Version: luci-app-ddns\n"
-"POT-Creation-Date: 2014-11-09 13:41+0100\n"
-"PO-Revision-Date: 2014-11-09 14:29+0100\n"
+"POT-Creation-Date: 2015-01-17 18:28+0100\n"
+"PO-Revision-Date: 2015-01-17 18:36+0100\n"
"Last-Translator: Christian Schoenebeck <christian.schoenebeck@gmail.com>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -17,6 +17,15 @@ msgstr ""
msgid "&"
msgstr "&"
+msgid "-- custom --"
+msgstr "-- benutzerdefiniert --"
+
+msgid "Advanced Settings"
+msgstr "Erweiterte Einstellungen"
+
+msgid "Applying changes"
+msgstr "Änderungen anwenden"
+
msgid "Basic Settings"
msgstr "Grundlegende Einstellungen"
@@ -36,9 +45,6 @@ msgstr ""
">Wenn Sie Aktualisierungen für IPv4 und IPv6 senden möchten benötigen Sie "
"zwei Konfigurationen z.B. 'myddns_ipv4' und 'myddns_ipv6'"
-msgid "Build"
-msgstr "Build"
-
msgid ""
"BusyBox's nslookup and Wget do not support to specify the IP version to use "
"for communication with DDNS Provider."
@@ -56,15 +62,15 @@ msgstr ""
msgid "Check Interval"
msgstr "Prüfinterval"
-msgid "Check for changed IP every"
-msgstr "Teste auf neue IP alle"
-
-msgid "Check-time unit"
-msgstr "Zeiteinheit"
+msgid "Collecting data..."
+msgstr "Sammle Daten..."
msgid "Config error"
msgstr "Konfigurationsfehler"
+msgid "Configuration"
+msgstr "Einstellungen"
+
msgid "Configure here the details for selected Dynamic DNS service"
msgstr "Konfiguriere hier die Details für den gewählten Dynamik DNS Dienst"
@@ -153,6 +159,9 @@ msgstr ""
msgid "Details for"
msgstr "Details für"
+msgid "Disabled"
+msgstr "Deaktiviert"
+
msgid "Dynamic DNS"
msgstr "Dynamisches DNS"
@@ -166,6 +175,12 @@ msgstr ""
msgid "Enable secure communication with DDNS provider"
msgstr "Aktiviert sichere Kommunikation mit dem DDNS Anbieter"
+msgid "Enabled"
+msgstr "Aktiviert"
+
+msgid "Error"
+msgstr "Fehler"
+
msgid "Error Retry Counter"
msgstr "Wiederholungszähler bei Fehler"
@@ -175,8 +190,8 @@ msgstr "Wiederholungsintervall bei Fehler"
msgid "Event Network"
msgstr "Ereignis Netzwerk"
-msgid "Event interface"
-msgstr "Ereignis Netzwerk"
+msgid "File"
+msgstr "Datei"
msgid "File not found"
msgstr "Datei nicht gefunden"
@@ -203,12 +218,6 @@ msgstr "Erzwungene Aktualisierung"
msgid "Force TCP on DNS"
msgstr "Erzwinge TCP bei DNS-Anfragen"
-msgid "Force update every"
-msgstr "Erzwinge Aktualisierung alle"
-
-msgid "Force-time unit"
-msgstr "Zeiteinheit"
-
msgid "Forced IP Version don't matched"
msgstr "Erzwungene IP Version stimmt nicht überein"
@@ -233,6 +242,9 @@ msgstr "IP-Adressquelle"
msgid "IP address version"
msgstr "IP-Adressversion"
+msgid "IPv4-Address"
+msgstr "IPv4-Adresse"
+
msgid "IPv6 address must be given in square brackets"
msgstr "Eine IPv6 Adresse muss in eckigen Klammern angegeben werden"
@@ -248,6 +260,9 @@ msgstr ""
msgid "IPv6 not supported"
msgstr "IPv6 nicht unterstützt"
+msgid "IPv6-Address"
+msgstr "IPv6-Adresse"
+
msgid ""
"If this service section is disabled it could not be started.<br />Neither "
"from LuCI interface nor from console"
@@ -261,6 +276,12 @@ msgstr ""
"In einigen Versionen von OpenWrt wurde cURL/libcurl ohne Proxy Unterstützung "
"compiliert."
+msgid "Info"
+msgstr "Informationen"
+
+msgid "Interface"
+msgstr "Schnittstelle"
+
msgid ""
"Interval to check for changed IP<br />Values below 5 minutes == 300 seconds "
"are not supported"
@@ -280,6 +301,9 @@ msgstr ""
msgid "Last Update"
msgstr "Letztes Aktualisierung"
+msgid "Loading"
+msgstr "Lade"
+
msgid "Log File Viewer"
msgstr "Protokolldatei"
@@ -296,6 +320,9 @@ msgstr ""
"Weder GNU Wget mit SSL noch cURL sind installiert um Aktualisierungen über "
"HTTPS Protokoll zu unterstützen."
+msgid "Network"
+msgstr "Netzwerk"
+
msgid "Network on which the ddns-updater scripts will be started"
msgstr "Netzwerk auf dem Ereignisse die ddns-updater Skripte starten"
@@ -311,6 +338,9 @@ msgstr "Keine Daten"
msgid "No logging"
msgstr "Keine Protokollierung"
+msgid "Notice"
+msgstr "Notiz"
+
msgid "OPTIONAL: Force the usage of pure IPv4/IPv6 only communication."
msgstr ""
"OPTIONAL: Erzwingt die Verwendung einer reinen IPv4/IPv6 Kommunikation."
@@ -338,12 +368,21 @@ msgstr ""
msgid "On Error the script will stop execution after given number of retrys"
msgstr "Das Skript wird nach der gegebener Anzahlt von Fehlversuchen beendet"
+msgid "Overview"
+msgstr "Ãœbersicht"
+
msgid "PROXY-Server"
msgstr "Proxy-Server"
msgid "PROXY-Server not supported"
msgstr "Proxy-Server nicht unterstützt"
+msgid "Password"
+msgstr "Passwort"
+
+msgid "Path to CA-Certificate"
+msgstr "Pfad zum CA-Zertifikat"
+
msgid "Please [Save & Apply] your changes first"
msgstr "Bitte [Speichern & Anwenden] Sie Änderungen zunächst"
@@ -377,17 +416,14 @@ msgstr "Einmalig ausführen"
msgid "Script"
msgstr "Skript"
-msgid "Service"
-msgstr "Dienst"
-
msgid "Show more"
msgstr "Zeige mehr"
msgid "Software update required"
msgstr "Softwareaktualisierung nötig"
-msgid "Source of IP address"
-msgstr "Quelle der IP-Adresse"
+msgid "Start"
+msgstr "Start"
msgid "Start / Stop"
msgstr "Start / Stopp"
@@ -435,9 +471,24 @@ msgstr ""
"Definiert das Skript mit dem die aktuelle IP-Adresse des System gelesen "
"wird."
+msgid "Username"
+msgstr "Benutzername"
+
+msgid "Verify"
+msgstr "überprüfen"
+
+msgid "Version"
+msgstr "Version"
+
msgid "Version Information"
msgstr "Versionsinformationen"
+msgid "Waiting for changes to be applied..."
+msgstr "Änderungen werden angewandt..."
+
+msgid "Warning"
+msgstr "Warnung"
+
msgid ""
"Writes detailed messages to log file. File will be truncated automatically."
msgstr ""
@@ -482,9 +533,6 @@ msgstr "Konnte Server nicht finden:"
msgid "config error"
msgstr "Konfigurationsfehler"
-msgid "custom"
-msgstr "benutzerdefiniert"
-
msgid "days"
msgstr "Tage"
@@ -500,9 +548,6 @@ msgstr "hier aktivieren"
msgid "file or directory not found or not 'IGNORE'"
msgstr "Datei oder Verzeichnis nicht gefunden oder nicht 'IGNORE'"
-msgid "h"
-msgstr "Stunden"
-
msgid "hours"
msgstr "Stunden"
@@ -512,15 +557,9 @@ msgstr "Aktualisierung hier installieren"
msgid "installed"
msgstr "installiert"
-msgid "interface"
-msgstr "Schnittstelle"
-
msgid "invalid - Sample"
msgstr "ungültig - Beispiel"
-msgid "min"
-msgstr "Minuten"
-
msgid "minimum value '0'"
msgstr "Minimum Wert '0'"
@@ -545,9 +584,6 @@ msgstr "muss mit 'http://' beginnen"
msgid "nc (netcat) can not connect"
msgstr "nc (netcat) kann keine Verbindung herstellen"
-msgid "network"
-msgstr "Netzwerk"
-
msgid "never"
msgstr "nie"
@@ -564,8 +600,8 @@ msgstr "nslookup kann den Namen nicht auflösen"
msgid "or"
msgstr "oder"
-msgid "or greater"
-msgstr "oder größer"
+msgid "or higher"
+msgstr "oder höher"
msgid "please disable"
msgstr "Bitte deaktivieren"
diff --git a/applications/luci-app-ddns/po/templates/ddns.pot b/applications/luci-app-ddns/po/templates/ddns.pot
index c3b8c9367d..4b983cec1e 100644
--- a/applications/luci-app-ddns/po/templates/ddns.pot
+++ b/applications/luci-app-ddns/po/templates/ddns.pot
@@ -4,6 +4,15 @@ msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "&"
msgstr ""
+msgid "-- custom --"
+msgstr ""
+
+msgid "Advanced Settings"
+msgstr ""
+
+msgid "Applying changes"
+msgstr ""
+
msgid "Basic Settings"
msgstr ""
@@ -18,9 +27,6 @@ msgid ""
"separate Configurations i.e. 'myddns_ipv4' and 'myddns_ipv6'"
msgstr ""
-msgid "Build"
-msgstr ""
-
msgid ""
"BusyBox's nslookup and Wget do not support to specify the IP version to use "
"for communication with DDNS Provider."
@@ -34,13 +40,13 @@ msgstr ""
msgid "Check Interval"
msgstr ""
-msgid "Check for changed IP every"
+msgid "Collecting data..."
msgstr ""
-msgid "Check-time unit"
+msgid "Config error"
msgstr ""
-msgid "Config error"
+msgid "Configuration"
msgstr ""
msgid "Configure here the details for selected Dynamic DNS service"
@@ -109,6 +115,9 @@ msgstr ""
msgid "Details for"
msgstr ""
+msgid "Disabled"
+msgstr ""
+
msgid "Dynamic DNS"
msgstr ""
@@ -120,6 +129,12 @@ msgstr ""
msgid "Enable secure communication with DDNS provider"
msgstr ""
+msgid "Enabled"
+msgstr ""
+
+msgid "Error"
+msgstr ""
+
msgid "Error Retry Counter"
msgstr ""
@@ -129,7 +144,7 @@ msgstr ""
msgid "Event Network"
msgstr ""
-msgid "Event interface"
+msgid "File"
msgstr ""
msgid "File not found"
@@ -155,12 +170,6 @@ msgstr ""
msgid "Force TCP on DNS"
msgstr ""
-msgid "Force update every"
-msgstr ""
-
-msgid "Force-time unit"
-msgstr ""
-
msgid "Forced IP Version don't matched"
msgstr ""
@@ -185,6 +194,9 @@ msgstr ""
msgid "IP address version"
msgstr ""
+msgid "IPv4-Address"
+msgstr ""
+
msgid "IPv6 address must be given in square brackets"
msgstr ""
@@ -197,6 +209,9 @@ msgstr ""
msgid "IPv6 not supported"
msgstr ""
+msgid "IPv6-Address"
+msgstr ""
+
msgid ""
"If this service section is disabled it could not be started.<br />Neither "
"from LuCI interface nor from console"
@@ -206,6 +221,12 @@ msgid ""
"In some versions cURL/libcurl in OpenWrt is compiled without proxy support."
msgstr ""
+msgid "Info"
+msgstr ""
+
+msgid "Interface"
+msgstr ""
+
msgid ""
"Interval to check for changed IP<br />Values below 5 minutes == 300 seconds "
"are not supported"
@@ -220,6 +241,9 @@ msgstr ""
msgid "Last Update"
msgstr ""
+msgid "Loading"
+msgstr ""
+
msgid "Log File Viewer"
msgstr ""
@@ -234,6 +258,9 @@ msgid ""
"protocol."
msgstr ""
+msgid "Network"
+msgstr ""
+
msgid "Network on which the ddns-updater scripts will be started"
msgstr ""
@@ -249,6 +276,9 @@ msgstr ""
msgid "No logging"
msgstr ""
+msgid "Notice"
+msgstr ""
+
msgid "OPTIONAL: Force the usage of pure IPv4/IPv6 only communication."
msgstr ""
@@ -270,12 +300,21 @@ msgstr ""
msgid "On Error the script will stop execution after given number of retrys"
msgstr ""
+msgid "Overview"
+msgstr ""
+
msgid "PROXY-Server"
msgstr ""
msgid "PROXY-Server not supported"
msgstr ""
+msgid "Password"
+msgstr ""
+
+msgid "Path to CA-Certificate"
+msgstr ""
+
msgid "Please [Save & Apply] your changes first"
msgstr ""
@@ -309,16 +348,13 @@ msgstr ""
msgid "Script"
msgstr ""
-msgid "Service"
-msgstr ""
-
msgid "Show more"
msgstr ""
msgid "Software update required"
msgstr ""
-msgid "Source of IP address"
+msgid "Start"
msgstr ""
msgid "Start / Stop"
@@ -361,9 +397,24 @@ msgstr ""
msgid "User defined script to read systems IP-Address"
msgstr ""
+msgid "Username"
+msgstr ""
+
+msgid "Verify"
+msgstr ""
+
+msgid "Version"
+msgstr ""
+
msgid "Version Information"
msgstr ""
+msgid "Waiting for changes to be applied..."
+msgstr ""
+
+msgid "Warning"
+msgstr ""
+
msgid ""
"Writes detailed messages to log file. File will be truncated automatically."
msgstr ""
@@ -397,9 +448,6 @@ msgstr ""
msgid "config error"
msgstr ""
-msgid "custom"
-msgstr ""
-
msgid "days"
msgstr ""
@@ -415,9 +463,6 @@ msgstr ""
msgid "file or directory not found or not 'IGNORE'"
msgstr ""
-msgid "h"
-msgstr ""
-
msgid "hours"
msgstr ""
@@ -427,15 +472,9 @@ msgstr ""
msgid "installed"
msgstr ""
-msgid "interface"
-msgstr ""
-
msgid "invalid - Sample"
msgstr ""
-msgid "min"
-msgstr ""
-
msgid "minimum value '0'"
msgstr ""
@@ -460,9 +499,6 @@ msgstr ""
msgid "nc (netcat) can not connect"
msgstr ""
-msgid "network"
-msgstr ""
-
msgid "never"
msgstr ""
@@ -478,7 +514,7 @@ msgstr ""
msgid "or"
msgstr ""
-msgid "or greater"
+msgid "or higher"
msgstr ""
msgid "please disable"
diff --git a/applications/luci-app-firewall/luasrc/view/firewall/cbi_addforward.htm b/applications/luci-app-firewall/luasrc/view/firewall/cbi_addforward.htm
index 3726f643df..3c46e228f7 100644
--- a/applications/luci-app-firewall/luasrc/view/firewall/cbi_addforward.htm
+++ b/applications/luci-app-firewall/luasrc/view/firewall/cbi_addforward.htm
@@ -6,7 +6,8 @@
for _, z in ipairs(fw:get_zones()) do
if z:name() ~= "wan" then
izl[#izl+1] = z
- elseif z:name() ~= "lan" then
+ end
+ if z:name() ~= "lan" then
ezl[#ezl+1] = z
end
end
diff --git a/applications/luci-app-ocserv/luasrc/controller/ocserv.lua b/applications/luci-app-ocserv/luasrc/controller/ocserv.lua
index bb7fe3f2e9..91bddc73dd 100644
--- a/applications/luci-app-ocserv/luasrc/controller/ocserv.lua
+++ b/applications/luci-app-ocserv/luasrc/controller/ocserv.lua
@@ -44,7 +44,7 @@ function ocserv_status()
if not ln then break end
local id, user, group, vpn_ip, ip, device, time, cipher, status =
- ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+).*")
+ ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%(%)%:%.-_%w]+)%s+([%:%.-_%w]+).*")
if id then
fwd[#fwd+1] = {
id = id,
diff --git a/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua b/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua
index ef0e53daf4..d1cc155fa5 100644
--- a/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua
+++ b/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua
@@ -42,7 +42,7 @@ if fd then local ln
found_pki = true
elseif found_pki then
local hash = ln:match("([a-f0-9]+)")
- o_pki.default = hash and hash:upper()
+ o_pki.default = hash and "sha1:" .. hash:upper()
complete = complete + 1
found_pki = false
end
diff --git a/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/users.lua b/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/users.lua
index e2a08acf36..8cf35b79b6 100644
--- a/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/users.lua
+++ b/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/users.lua
@@ -47,7 +47,7 @@ if fd then local ln
if not ln then break end
local id, user, group, vpn_ip, ip, device, time, cipher, status =
- ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+).*")
+ ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%(%)%:%.-_%w]+)%s+([%:%.-_%w]+).*")
if id then
table.insert(lusers, {id, user, group, vpn_ip, ip, device, time, cipher, status})
end
diff --git a/applications/luci-app-olsr/luasrc/controller/olsr.lua b/applications/luci-app-olsr/luasrc/controller/olsr.lua
index 3615372909..74deb716c4 100644
--- a/applications/luci-app-olsr/luasrc/controller/olsr.lua
+++ b/applications/luci-app-olsr/luasrc/controller/olsr.lua
@@ -1,5 +1,8 @@
module("luci.controller.olsr", package.seeall)
+local neigh_table = nil
+local ifaddr_table = nil
+
function index()
local ipv4,ipv6
if nixio.fs.access("/etc/config/olsrd") then
@@ -93,6 +96,46 @@ function action_json()
http.write('{"v4":' .. jsonreq4 .. ', "v6":' .. jsonreq6 .. '}')
end
+
+local function local_mac_lookup(ipaddr)
+ local _, ifa, dev
+
+ ipaddr = tostring(ipaddr)
+
+ if not ifaddr_table then
+ ifaddr_table = nixio.getifaddrs()
+ end
+
+ -- ipaddr -> ifname
+ for _, ifa in ipairs(ifaddr_table) do
+ if ifa.addr == ipaddr then
+ dev = ifa.name
+ break
+ end
+ end
+
+ -- ifname -> macaddr
+ for _, ifa in ipairs(ifaddr_table) do
+ if ifa.name == dev and ifa.family == "packet" then
+ return ifa.addr
+ end
+ end
+end
+
+local function remote_mac_lookup(ipaddr)
+ local _, n
+
+ if not neigh_table then
+ neigh_table = luci.ip.neighbors()
+ end
+
+ for _, n in ipairs(neigh_table) do
+ if n.mac and n.dest and n.dest:equal(ipaddr) then
+ return n.mac
+ end
+ end
+end
+
function action_neigh(json)
local data, has_v4, has_v6, error = fetch_jsoninfo('links')
@@ -107,17 +150,13 @@ function action_neigh(json)
local sys = require "luci.sys"
local assoclist = {}
--local neightbl = require "neightbl"
+ local ntm = require "luci.model.network"
local ipc = require "luci.ip"
+ local nxo = require "nixio"
+ local defaultgw
- luci.sys.net.routes(function(r)
- if r.dest:prefix() == 0 then
- defaultgw = r.gateway:string()
- end
- end)
-
- if not defaultgw then
- defaultgw = luci.util.exec("ip route list exact 0.0.0.0/0 table all"):match(" via (%S+)")
- end
+ ipc.routes({ family = 4, type = 1, dest_exact = "0.0.0.0/0" },
+ function(rt) defaultgw = rt.gw end)
local function compare(a,b)
if a.proto == b.proto then
@@ -138,14 +177,10 @@ function action_neigh(json)
end
for k, v in ipairs(data) do
- local interface
local snr = 0
local signal = 0
local noise = 0
- local arptable = sys.net.arptable()
local mac = ""
- local rmac = ""
- local lmac = ""
local ip
local neihgt = {}
@@ -155,45 +190,11 @@ function action_neigh(json)
v.hostname = hostname
end
end
- if v.proto == '4' then
- uci:foreach("network", "interface",function(vif)
- if vif.ipaddr and vif.ipaddr == v.localIP then
- interface = vif['.name'] or vif.interface
- lmac = string.lower(vif.macaddr or "")
- return
- end
- end)
- for _, arpt in ipairs(arptable) do
- ip = arpt['IP address']
- if ip == v.remoteIP then
- rmac = string.lower(arpt['HW address'] or "")
- end
- end
- elseif v.proto == '6' then
- uci:foreach("network", "interface",function(vif)
- local name = vif['.name']
- local net = ntm:get_network(name)
- local device = net and net:get_interface()
- local locip = ipc.IPv6(v.localIP)
- if device and device:ip6addrs() and locip then
- for _, a in ipairs(device:ip6addrs()) do
- if not a:is6linklocal() then
- if a:host() == locip:host() then
- interface = name
- --neihgt = neightbl.get(device.ifname) or {}
- end
- end
- end
- end
- end)
- --[[
- for ip,mac in pairs(neihgt) do
- if ip == v.remoteIP then
- rmac = mac
- end
- end
- ]]--
- end
+
+ local interface = ntm:get_status_by_address(v.localIP)
+ local lmac = local_mac_lookup(v.localIP)
+ local rmac = remote_mac_lookup(v.remoteIP)
+
for _, val in ipairs(assoclist) do
if val.network == interface and val.list then
for assocmac, assot in pairs(val.list) do
diff --git a/applications/luci-app-privoxy/Makefile b/applications/luci-app-privoxy/Makefile
new file mode 100644
index 0000000000..4c1fc578a8
--- /dev/null
+++ b/applications/luci-app-privoxy/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2008-2015 The LuCI Team <luci@lists.subsignal.org>
+#
+# This is free software, licensed under the Apache License, Version 2.0 .
+#
+
+include $(TOPDIR)/rules.mk
+
+# LuCI specific settings
+LUCI_TITLE:=LuCI Support for Privoxy WEB proxy
+LUCI_DEPENDS:=+luci-mod-admin-full +privoxy
+LUCI_PKGARCH:=all
+
+PKG_NAME:=luci-app-privoxy
+
+# Version == major.minor.patch
+# increase "minor" on new functionality and "patch" on patches/optimization
+PKG_VERSION:=1.0.2
+
+# Release == build
+# increase on changes of translation files
+PKG_RELEASE:=0
+
+PKG_LICENSE:=Apache-2.0
+PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
+
+define Package/$(PKG_NAME)/config
+# shown in make menuconfig <Help>
+help
+ $(LUCI_TITLE)
+
+ Version : $(PKG_VERSION)-$(PKG_RELEASE)
+ Maintainer: $(PKG_MAINTAINER)
+endef
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-privoxy/luasrc/controller/privoxy.lua b/applications/luci-app-privoxy/luasrc/controller/privoxy.lua
new file mode 100755
index 0000000000..de73d0c5df
--- /dev/null
+++ b/applications/luci-app-privoxy/luasrc/controller/privoxy.lua
@@ -0,0 +1,117 @@
+-- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Licensed under the Apache License, Version 2.0
+
+module("luci.controller.privoxy", package.seeall)
+
+local NX = require "nixio"
+local NXFS = require "nixio.fs"
+local HTTP = require "luci.http"
+local UCI = require "luci.model.uci"
+local SYS = require "luci.sys"
+
+PRIVOXY_MIN = "3.0.22-0" -- minimum version of service required
+
+function index()
+ local _sys = require "luci.sys"
+ local _verinst = _sys.exec([[opkg list-installed ]] .. "privoxy" .. [[ | cut -d " " -f 3 ]])
+ local _cmd = [[opkg compare-versions "]] .. _verinst .. [[" ">=" "]] .. "3.0.22-0" .. [["]]
+ local _verok = tonumber(_sys.call(_cmd))
+
+ -- check config file and version
+ if not nixio.fs.access("/etc/config/privoxy") or (_verok == 0) then
+ entry( {"admin", "services", "privoxy"}, cbi("privoxy/apperror",
+ {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true }), _("Privoxy WEB proxy"), 59)
+ else
+ entry( {"admin", "services", "privoxy"}, cbi("privoxy/detail"), _("Privoxy WEB proxy"), 59)
+ entry( {"admin", "services", "privoxy", "logview"}, call("logread") ).leaf = true
+ entry( {"admin", "services", "privoxy", "startstop"}, call("startstop") ).leaf = true
+ entry( {"admin", "services", "privoxy", "status"}, call("get_pid") ).leaf = true
+ end
+end
+
+-- called by XHR.get from detail_logview.htm
+function logread()
+ -- read application settings
+ local uci = UCI.cursor()
+ local logdir = uci:get("privoxy", "privoxy", "logdir") or "/var/log"
+ local logfile = uci:get("privoxy", "privoxy", "logfile") or "privoxy.log"
+ uci:unload("privoxy")
+
+ local lfile=logdir .. "/" .. logfile
+ local ldata=NXFS.readfile(lfile)
+ if not ldata or #ldata == 0 then
+ ldata="_nodata_"
+ end
+ HTTP.write(ldata)
+end
+
+-- called by XHR.get from detail_startstop.htm
+function startstop()
+ local pid = get_pid(true)
+ if pid > 0 then
+ SYS.call("/etc/init.d/privoxy stop")
+ NX.nanosleep(1) -- sleep a second
+ if NX.kill(pid, 0) then -- still running
+ NX.kill(pid, 9) -- send SIGKILL
+ end
+ pid = 0
+ else
+ SYS.call("/etc/init.d/privoxy start")
+ NX.nanosleep(1) -- sleep a second
+ pid = tonumber(NXFS.readfile("/var/run/privoxy.pid") or 0 )
+ if pid > 0 and not NX.kill(pid, 0) then
+ pid = 0 -- process did not start
+ end
+ end
+ HTTP.write(tostring(pid)) -- HTTP needs string not number
+end
+
+-- called by XHR.poll from detail_startstop.htm
+-- and from lua (with parameter "true")
+function get_pid(from_lua)
+ local pid = tonumber(NXFS.readfile("/var/run/privoxy.pid") or 0 )
+ if pid > 0 and not NX.kill(pid, 0) then
+ pid = 0
+ end
+ if from_lua then
+ return pid
+ else
+ HTTP.write(tostring(pid)) -- HTTP needs string not number
+ end
+end
+
+-- get the "name" of the current active theme
+function get_theme()
+ local _uci = UCI.cursor()
+ local _base = _uci:get("luci", "main", "mediaurlbase") -- only pathname
+ _uci:unload("luci")
+
+ for k, v in pairs(luci.config.themes) do
+ if k:sub(1, 1) ~= "." and v == _base then
+ return k
+ end
+ end
+ return nil
+end
+
+-- replacement of build-in Flag.parse of cbi.lua
+-- modified to mark section as changed if value changes
+-- current parse did not do this, but it is done AbstaractValue.parse()
+function flag_parse(self, section)
+ local fexists = self.map:formvalue(
+ luci.cbi.FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option)
+
+ if fexists then
+ local fvalue = self:formvalue(section) and self.enabled or self.disabled
+ local cvalue = self:cfgvalue(section)
+ if fvalue ~= self.default or (not self.optional and not self.rmempty) then
+ self:write(section, fvalue)
+ else
+ self:remove(section)
+ end
+ if (fvalue ~= cvalue) then self.section.changed = true end
+ else
+ self:remove(section)
+ self.section.changed = true
+ end
+end
diff --git a/applications/luci-app-privoxy/luasrc/model/cbi/privoxy/apperror.lua b/applications/luci-app-privoxy/luasrc/model/cbi/privoxy/apperror.lua
new file mode 100755
index 0000000000..fcbb88074d
--- /dev/null
+++ b/applications/luci-app-privoxy/luasrc/model/cbi/privoxy/apperror.lua
@@ -0,0 +1,47 @@
+-- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Licensed under the Apache License, Version 2.0
+
+local CTRL = require "luci.controller.privoxy" -- this application's controller
+local DISP = require "luci.dispatcher"
+local SYS = require "luci.sys"
+
+local HELP = [[<a href="http://www.privoxy.org/user-manual/config.html#%s" target="_blank">%s</a>]]
+
+-- cbi-map -- ##################################################################
+local m = Map("privoxy")
+m.title = [[</a><a href="javascript:alert(']]
+ .. translate("Version Information")
+ .. [[\n\nluci-app-privoxy]]
+ .. [[\n\t]] .. translate("Version") .. [[:\t]]
+ .. SYS.exec([[opkg list-installed ]] .. [[luci-app-privoxy]] .. [[ | cut -d " " -f 3 ]])
+ .. [[\n\nprivoxy ]] .. translate("required") .. [[:]]
+ .. [[\n\t]] .. translate("Version") .. [[:\t]] .. CTRL.PRIVOXY_MIN .. [[ ]] .. translate("or higher")
+ .. [[\n\nprivoxy ]] .. translate("installed") .. [[:]]
+ .. [[\n\t]] .. translate("Version") .. [[:\t]]
+ .. SYS.exec([[opkg list-installed ]] .. [[privoxy]] .. [[ | cut -d " " -f 3 ]])
+ .. [[\n\n]]
+ .. [[')">]]
+ .. translate("Privoxy WEB proxy")
+m.description = translate("Privoxy is a non-caching web proxy with advanced filtering "
+ .. "capabilities for enhancing privacy, modifying web page data and HTTP headers, "
+ .. "controlling access, and removing ads and other obnoxious Internet junk.")
+
+-- cbi-section -- ##############################################################
+local s = m:section(SimpleSection)
+s.title = [[<font color="red">]] .. [[<strong>]]
+ .. translate("Software update required")
+ .. [[</strong>]] .. [[</font>]]
+
+-- old privoxy sofware version --------------------------------------------------------------
+local v = s:option(DummyValue, "_update_needed")
+v.titleref = DISP.build_url("admin", "system", "packages")
+v.rawhtml = true
+--v.title = [[<h3>]] .. [[<font color="red">]] .. [[<strong>]]
+-- .. translate("Software update required")
+-- .. [[</strong>]] .. [[</font>]] .. [[</h3>]] .. [[<br />]]
+v.value = [[<h3>]] .. [[<strong>]]
+ .. translate("The currently installed 'privoxy' package is not supported by LuCI application.")
+ .. [[<br />]]
+ .. translate("Please update to the current version!")
+ .. [[</strong>]] .. [[</h3>]]
+return m
diff --git a/applications/luci-app-privoxy/luasrc/model/cbi/privoxy/detail.lua b/applications/luci-app-privoxy/luasrc/model/cbi/privoxy/detail.lua
new file mode 100755
index 0000000000..2c846a1f99
--- /dev/null
+++ b/applications/luci-app-privoxy/luasrc/model/cbi/privoxy/detail.lua
@@ -0,0 +1,928 @@
+-- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Licensed under the Apache License, Version 2.0
+
+local NXFS = require "nixio.fs"
+local SYS = require "luci.sys"
+local UTIL = require "luci.util"
+local DTYP = require "luci.cbi.datatypes"
+local CTRL = require "luci.controller.privoxy" -- this application's controller
+
+-- Bootstrap theme needs 2 or 3 additional linefeeds for tab description for better optic
+local LFLF = (CTRL.get_theme() == "Bootstrap") and [[<br /><br /><br />]] or [[]]
+local HELP = [[<a href="http://www.privoxy.org/user-manual/config.html#%s" target="_blank">%s</a>]]
+
+-- cbi-map -- ##################################################################
+local m = Map("privoxy")
+m.title = [[</a><a href="javascript:alert(']]
+ .. translate("Version Information")
+ .. [[\n\nluci-app-privoxy]]
+ .. [[\n\t]] .. translate("Version") .. [[:\t]]
+ .. SYS.exec([[opkg list-installed ]] .. [[luci-app-privoxy]] .. [[ | cut -d " " -f 3 ]])
+ .. [[\n\nprivoxy ]] .. translate("required") .. [[:]]
+ .. [[\n\t]] .. translate("Version") .. [[:\t]] .. CTRL.PRIVOXY_MIN .. [[ ]] .. translate("or higher")
+ .. [[\n\nprivoxy ]] .. translate("installed") .. [[:]]
+ .. [[\n\t]] .. translate("Version") .. [[:\t]]
+ .. SYS.exec([[opkg list-installed ]] .. [[privoxy]] .. [[ | cut -d " " -f 3 ]])
+ .. [[\n\n]]
+ .. [[')">]]
+ .. translate("Privoxy WEB proxy")
+m.description = translate("Privoxy is a non-caching web proxy with advanced filtering "
+ .. "capabilities for enhancing privacy, modifying web page data and HTTP headers, "
+ .. "controlling access, and removing ads and other obnoxious Internet junk.")
+ .. [[<br /><strong>]]
+ .. translate("For help use link at the relevant option")
+ .. [[</strong>]]
+function m.commit_handler(self)
+ if self.changed then -- changes ?
+ os.execute("/etc/init.d/privoxy reload &") -- reload configuration
+ end
+end
+
+-- cbi-section -- ##############################################################
+local ns = m:section( NamedSection, "privoxy", "privoxy")
+
+ns:tab("local",
+ translate("Local Set-up"),
+ translate("If you intend to operate Privoxy for more users than just yourself, "
+ .. "it might be a good idea to let them know how to reach you, what you block "
+ .. "and why you do that, your policies, etc.")
+ .. LFLF )
+local function err_tab_local(title, msg)
+ return string.format(translate("Local Set-up") .. " - %s: %s", title, msg )
+end
+
+ns:tab("filter",
+ translate("Files and Directories"),
+ translate("Privoxy can (and normally does) use a number of other files "
+ .. "for additional configuration, help and logging. This section of "
+ .. "the configuration file tells Privoxy where to find those other files.")
+ .. LFLF )
+local function err_tab_filter(title, msg)
+ return string.format(translate("Files and Directories") .. " - %s: %s", title, msg )
+end
+
+ns:tab("access",
+ translate("Access Control"),
+ translate("This tab controls the security-relevant aspects of Privoxy's configuration.")
+ .. LFLF )
+local function err_tab_access(title, msg)
+ return string.format(translate("Access Control") .. " - %s: %s", title, msg )
+end
+
+ns:tab("forward",
+ translate("Forwarding"),
+ translate("Configure here the routing of HTTP requests through a chain of multiple proxies. "
+ .. "Note that parent proxies can severely decrease your privacy level. "
+ .. "Also specified here are SOCKS proxies.")
+ .. LFLF )
+
+ns:tab("misc",
+ translate("Miscellaneous"),
+ nil)
+local function err_tab_misc(self, msg)
+ return string.format(translate("Miscellaneous") .. " - %s: %s", self.title_base, msg )
+end
+
+ns:tab("debug",
+ translate("Logging"),
+ nil )
+
+ns:tab("logview",
+ translate("Log File Viewer"),
+ nil )
+
+-- tab: local -- ###############################################################
+
+-- start/stop button -----------------------------------------------------------
+local btn = ns:taboption("local", Button, "_startstop")
+btn.title = translate("Start / Stop")
+btn.description = translate("Start/Stop Privoxy WEB Proxy")
+btn.template = "privoxy/detail_startstop"
+function btn.cfgvalue(self, section)
+ local pid = CTRL.get_pid(true)
+ if pid > 0 then
+ btn.inputtitle = "PID: " .. pid
+ btn.inputstyle = "reset"
+ btn.disabled = false
+ else
+ btn.inputtitle = translate("Start")
+ btn.inputstyle = "apply"
+ btn.disabled = false
+ end
+ return true
+end
+
+-- enabled ---------------------------------------------------------------------
+local ena = ns:taboption("local", Flag, "_enabled")
+ena.title = translate("Enabled")
+ena.description = translate("Enable/Disable autostart of Privoxy on system startup and interface events")
+ena.orientation = "horizontal" -- put description under the checkbox
+ena.rmempty = false
+function ena.cfgvalue(self, section)
+ return (SYS.init.enabled("privoxy")) and "1" or "0"
+end
+function ena.validate(self, value)
+ error("Validate " .. value)
+end
+function ena.write(self, section, value)
+ --error("Write " .. value)
+ if value == "1" then
+ return SYS.init.enable("privoxy")
+ else
+ return SYS.init.disable("privoxy")
+ end
+end
+
+-- hostname --------------------------------------------------------------------
+local hn = ns:taboption("local", Value, "hostname")
+hn.title = string.format(HELP, "HOSTNAME", "Hostname" )
+hn.description = translate("The hostname shown on the CGI pages.")
+hn.placeholder = SYS.hostname()
+hn.optional = true
+hn.rmempty = true
+
+-- user-manual -----------------------------------------------------------------
+local um = ns:taboption("local", Value, "user_manual")
+um.title = string.format(HELP, "USER-MANUAL", "User Manual" )
+um.description = translate("Location of the Privoxy User Manual.")
+um.placeholder = "http://www.privoxy.org/user-manual/"
+um.optional = true
+um.rmempty = true
+
+-- admin-address ---------------------------------------------------------------
+local aa = ns:taboption("local", Value, "admin_address")
+aa.title_base = "Admin Email"
+aa.title = string.format(HELP, "ADMIN-ADDRESS", aa.title_base )
+aa.description = translate("An email address to reach the Privoxy administrator.")
+aa.placeholder = "privoxy.admin@example.com"
+aa.optional = true
+aa.rmempty = true
+function aa.validate(self, value)
+ if not value or #value == 0 then
+ return ""
+ end
+ if not (value:match("[A-Za-z0-9%.%%%+%-]+@[A-Za-z0-9%.%%%+%-]+%.%w%w%w?%w?")) then
+ return nil, err_tab_local(self.title_base, translate("Invalid email address") )
+ end
+ return value
+end
+
+-- proxy-info-url --------------------------------------------------------------
+local piu = ns:taboption("local", Value, "proxy_info_url")
+piu.title = string.format(HELP, "PROXY-INFO-URL", "Proxy Info URL" )
+piu.description = translate("A URL to documentation about the local Privoxy setup, configuration or policies.")
+piu.optional = true
+piu.rmempty = true
+
+-- trust-info-url --------------------------------------------------------------
+local tiu = ns:taboption("local", DynamicList, "trust_info_url")
+tiu.title = string.format(HELP, "TRUST-INFO-URL", "Trust Info URLs" )
+tiu.description = translate("A URL to be displayed in the error page that users will see if access to an untrusted page is denied.")
+ .. [[<br /><strong>]]
+ .. translate("The value of this option only matters if the experimental trust mechanism has been activated.")
+ .. [[</strong>]]
+tiu.optional = true
+tiu.rmepty = true
+
+-- tab: filter -- ##############################################################
+
+-- logdir ----------------------------------------------------------------------
+local ld = ns:taboption("filter", Value, "logdir")
+ld.title_base = "Log Directory"
+ld.title = string.format(HELP, "LOGDIR", ld.title_base )
+ld.description = translate("The directory where all logging takes place (i.e. where the logfile is located).")
+ .. [[<br />]]
+ .. translate("No trailing '/', please.")
+ld.default = "/var/log"
+ld.rmempty = false
+function ld.validate(self, value)
+ if not value or #value == 0 then
+ return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No Directory given!") )
+ elseif not NXFS.access(value) then
+ return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
+ else
+ return value
+ end
+end
+
+-- logfile ---------------------------------------------------------------------
+local lf = ns:taboption("filter", Value, "logfile")
+lf.title_base = "Log File"
+lf.title = string.format(HELP, "LOGFILE", lf.title_base )
+lf.description = translate("The log file to use. File name, relative to log directory.")
+lf.default = "privoxy.log"
+lf.rmempty = false
+function lf.validate(self, value)
+ if not value or #value == 0 then
+ return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No File given!") )
+ else
+ return value
+ end
+end
+
+-- confdir ---------------------------------------------------------------------
+local cd = ns:taboption("filter", Value, "confdir")
+cd.title_base = "Configuration Directory"
+cd.title = string.format(HELP, "CONFDIR", cd.title_base )
+cd.description = translate("The directory where the other configuration files are located.")
+ .. [[<br />]]
+ .. translate("No trailing '/', please.")
+cd.default = "/etc/privoxy"
+cd.rmempty = false
+function cd.validate(self, value)
+ if not value or #value == 0 then
+ return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No Directory given!") )
+ elseif not NXFS.access(value) then
+ return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
+ else
+ return value
+ end
+end
+
+-- templdir --------------------------------------------------------------------
+local td = ns:taboption("filter", Value, "templdir")
+td.title_base = "Template Directory"
+td.title = string.format(HELP, "TEMPLDIR", td.title_base )
+td.description = translate("An alternative directory where the templates are loaded from.")
+ .. [[<br />]]
+ .. translate("No trailing '/', please.")
+td.placeholder = "/etc/privoxy/templates"
+td.rmempty = true
+function td.validate(self, value)
+ if not NXFS.access(value) then
+ return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
+ else
+ return value
+ end
+end
+
+-- actionsfile -----------------------------------------------------------------
+local af = ns:taboption("filter", DynamicList, "actionsfile")
+af.title_base = "Action Files"
+af.title = string.format(HELP, "ACTIONSFILE", af.title_base)
+af.description = translate("The actions file(s) to use. Multiple actionsfile lines are permitted, and are in fact recommended!")
+ .. [[<br /><strong>match-all.action := </strong>]]
+ .. translate("Actions that are applied to all sites and maybe overruled later on.")
+ .. [[<br /><strong>default.action := </strong>]]
+ .. translate("Main actions file")
+ .. [[<br /><strong>user.action := </strong>]]
+ .. translate("User customizations")
+af.rmempty = false
+function af.validate(self, value)
+ if not value or #value == 0 then
+ return nil, err_tab_access(self.title_base, translate("Mandatory Input: No files given!") )
+ end
+ local confdir = cd:formvalue(ns.section)
+ local err = false
+ local file = ""
+ if type(value) == "table" then
+ local x
+ for _, x in ipairs(value) do
+ if x and #x > 0 then
+ if not NXFS.access(confdir .."/".. x) then
+ err = true
+ file = x
+ break -- break/leave for on error
+ end
+ end
+ end
+ else
+ if not NXFS.access(confdir .."/".. value) then
+ err = true
+ file = value
+ end
+ end
+ if err then
+ return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file)
+ end
+ return value
+end
+
+-- filterfile ------------------------------------------------------------------
+local ff = ns:taboption("filter", DynamicList, "filterfile")
+ff.title_base = "Filter files"
+ff.title = string.format(HELP, "FILTERFILE", ff.title_base )
+ff.description = translate("The filter files contain content modification rules that use regular expressions.")
+ff.rmempty = false
+function ff.validate(self, value)
+ if not value or #value == 0 then
+ return nil, err_tab_access(self.title_base, translate("Mandatory Input: No files given!") )
+ end
+ local confdir = cd:formvalue(ns.section)
+ local err = false
+ local file = ""
+ if type(value) == "table" then
+ local x
+ for _, x in ipairs(value) do
+ if x and #x > 0 then
+ if not NXFS.access(confdir .."/".. x) then
+ err = true
+ file = x
+ break -- break/leave for on error
+ end
+ end
+ end
+ else
+ if not NXFS.access(confdir .."/".. value) then
+ err = true
+ file = value
+ end
+ end
+ if err then
+ return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file )
+ end
+ return value
+end
+
+-- trustfile -------------------------------------------------------------------
+local tf = ns:taboption("filter", Value, "trustfile")
+tf.title_base = "Trust file"
+tf.title = string.format(HELP, "TRUSTFILE", tf.title_base )
+tf.description = translate("The trust mechanism is an experimental feature for building white-lists "
+ .."and should be used with care.")
+ .. [[<br /><strong>]]
+ .. translate("It is NOT recommended for the casual user.")
+ .. [[</strong>]]
+tf.placeholder = "sites.trust"
+tf.rmempty = true
+function tf.validate(self, value)
+ local confdir = cd:formvalue(ns.section)
+ local err = false
+ local file = ""
+ if type(value) == "table" then
+ local x
+ for _, x in ipairs(value) do
+ if x and #x > 0 then
+ if not NCFS.access(confdir .."/".. x) then
+ err = true
+ file = x
+ break -- break/leave for on error
+ end
+ end
+ end
+ else
+ if not NXFS.access(confdir .."/".. value) then
+ err = true
+ file = value
+ end
+ end
+ if err then
+ return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file )
+ end
+ return value
+end
+
+-- tab: access -- ##############################################################
+
+-- listen-address --------------------------------------------------------------
+local la = ns:taboption("access", DynamicList, "listen_address")
+la.title_base = "Listen addresses"
+la.title = string.format(HELP, "LISTEN-ADDRESS", la.title_base )
+la.description = translate("The address and TCP port on which Privoxy will listen for client requests.")
+ .. [[<br />]]
+ .. translate("Syntax: ")
+ .. "IPv4:Port / [IPv6]:Port / Host:Port"
+la.default = "127.0.0.1:8118"
+la.rmempty = false
+function la.validate(self, value)
+ if not value or #value == 0 then
+ return nil, err_tab_access(self.title_base, translate("Mandatory Input: No Data given!") )
+ end
+
+ local function check_value(v)
+ local _ret = UTIL.split(v, "]:")
+ local _ip
+ if _ret[2] then -- ip6 with port
+ _ip = string.gsub(_ret[1], "%[", "") -- remove "[" at beginning
+ if not DTYP.ip6addr(_ip) then
+ return translate("Mandatory Input: No valid IPv6 address given!")
+ elseif not DTYP.port(_ret[2]) then
+ return translate("Mandatory Input: No valid Port given!")
+ else
+ return nil
+ end
+ end
+ _ret = UTIL.split(v, ":")
+ if not _ret[2] then
+ return translate("Mandatory Input: No Port given!")
+ end
+ if #_ret[1] > 0 and not DTYP.host(_ret[1]) then -- :8118 is valid address
+ return translate("Mandatory Input: No valid IPv4 address or host given!")
+ elseif not DTYP.port(_ret[2]) then
+ return translate("Mandatory Input: No valid Port given!")
+ else
+ return nil
+ end
+ end
+
+ local err = ""
+ local entry = ""
+ if type(value) == "table" then
+ local x
+ for _, x in ipairs(value) do
+ if x and #x > 0 then
+ err = check_value(x)
+ if err then
+ entry = x
+ break
+ end
+ end
+ end
+ else
+ err = check_value(value)
+ entry = value
+ end
+ if err then
+ return nil, string.format(err_tab_access(self.title_base, err .. " - %s"), entry )
+ end
+ return value
+end
+
+-- permit-access ---------------------------------------------------------------
+local pa = ns:taboption("access", DynamicList, "permit_access")
+pa.title = string.format(HELP, "ACLS", "Permit access" )
+pa.description = translate("Who can access what.")
+ .. [[<br /><strong>]]
+ .. translate("Please read Privoxy manual for details!")
+ .. [[</strong>]]
+pa.rmempty = true
+
+-- deny-access -----------------------------------------------------------------
+local da = ns:taboption("access", DynamicList, "deny_access")
+da.title = string.format(HELP, "ACLS", "Deny Access" )
+da.description = translate("Who can access what.")
+ .. [[<br /><strong>]]
+ .. translate("Please read Privoxy manual for details!")
+ .. [[</strong>]]
+da.rmempty = true
+
+-- buffer-limit ----------------------------------------------------------------
+local bl = ns:taboption("access", Value, "buffer_limit")
+bl.title_base = "Buffer Limit"
+bl.title = string.format(HELP, "BUFFER-LIMIT", bl.title_base )
+bl.description = translate("Maximum size (in KB) of the buffer for content filtering.")
+ .. [[<br />]]
+ .. translate("Value range 1 to 4096, no entry defaults to 4096")
+bl.default = 4096
+bl.rmempty = true
+function bl.validate(self, value)
+ local v = tonumber(value)
+ if not v then
+ return nil, err_tab_access(self.title_base, translate("Value is not a number") )
+ elseif v < 1 or v > 4096 then
+ return nil, err_tab_access(self.title_base, translate("Value not between 1 and 4096") )
+ elseif v == self.default then
+ return "" -- dont need to save default
+ end
+ return value
+end
+
+-- toggle ----------------------------------------------------------------------
+local tgl = ns:taboption("access", Flag, "toggle")
+tgl.title = string.format(HELP, "TOGGLE", "Toggle Status" )
+tgl.description = translate("Enable/Disable filtering when Privoxy starts.")
+ .. [[<br />]]
+ .. translate("Disabled == Transparent Proxy Mode")
+tgl.orientation = "horizontal"
+tgl.default = "1"
+tgl.rmempty = false
+function tgl.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- enable-remote-toggle --------------------------------------------------------
+local ert = ns:taboption("access", Flag, "enable_remote_toggle")
+ert.title = string.format(HELP, "ENABLE-REMOTE-TOGGLE", "Enable remote toggle" )
+ert.description = translate("Whether or not the web-based toggle feature may be used.")
+ert.orientation = "horizontal"
+ert.rmempty = true
+function ert.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- enable-remote-http-toggle ---------------------------------------------------
+local eht = ns:taboption("access", Flag, "enable_remote_http_toggle")
+eht.title = string.format(HELP, "ENABLE-REMOTE-HTTP-TOGGLE", "Enable remote toggle via HTTP" )
+eht.description = translate("Whether or not Privoxy recognizes special HTTP headers to change toggle state.")
+ .. [[<br /><strong>]]
+ .. translate("This option will be removed in future releases as it has been obsoleted by the more general header taggers.")
+ .. [[</strong>]]
+eht.orientation = "horizontal"
+eht.rmempty = true
+function eht.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- enable-edit-actions ---------------------------------------------------------
+local eea = ns:taboption("access", Flag, "enable_edit_actions")
+eea.title = string.format(HELP, "ENABLE-EDIT-ACTIONS", "Enable action file editor" )
+eea.description = translate("Whether or not the web-based actions file editor may be used.")
+eea.orientation = "horizontal"
+eea.rmempty = true
+function eea.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- enforce-blocks --------------------------------------------------------------
+local eb = ns:taboption("access", Flag, "enforce_blocks")
+eb.title = string.format(HELP, "ENFORCE-BLOCKS", "Enforce page blocking" )
+eb.description = translate("If enabled, Privoxy hides the 'go there anyway' link. "
+ .. "The user obviously should not be able to bypass any blocks.")
+eb.orientation = "horizontal"
+eb.rmempty = true
+function eb.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- tab: forward -- #############################################################
+
+-- enable-proxy-authentication-forwarding --------------------------------------
+local paf = ns:taboption("forward", Flag, "enable_proxy_authentication_forwarding")
+paf.title = string.format(HELP, "ENABLE-PROXY-AUTHENTICATION-FORWARDING",
+ translate("Enable proxy authentication forwarding") )
+paf.description = translate("Whether or not proxy authentication through Privoxy should work.")
+ .. [[<br /><strong>]]
+ .. translate("Enabling this option is NOT recommended if there is no parent proxy that requires authentication!")
+ .. [[</strong>]]
+--paf.orientation = "horizontal"
+paf.rmempty = true
+function paf.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- forward ---------------------------------------------------------------------
+local fwd = ns:taboption("forward", DynamicList, "forward")
+fwd.title = string.format(HELP, "FORWARD", "Forward HTTP" )
+fwd.description = translate("To which parent HTTP proxy specific requests should be routed.")
+ .. [[<br />]]
+ .. translate("Syntax: target_pattern http_parent[:port]")
+fwd.rmempty = true
+
+-- forward-socks4 --------------------------------------------------------------
+local fs4 = ns:taboption("forward", DynamicList, "forward_socks4")
+fs4.title = string.format(HELP, "SOCKS", "Forward SOCKS 4" )
+fs4.description = translate("Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.")
+ .. [[<br />]]
+ .. translate("Syntax: target_pattern socks_proxy[:port] http_parent[:port]")
+fs4.rmempty = true
+
+-- forward-socks4a -------------------------------------------------------------
+local f4a = ns:taboption("forward", DynamicList, "forward_socks4a")
+f4a.title = string.format(HELP, "SOCKS", "Forward SOCKS 4A" )
+f4a.description = fs4.description
+f4a.rmempty = true
+
+-- forward-socks5 --------------------------------------------------------------
+local fs5 = ns:taboption("forward", DynamicList, "forward_socks5")
+fs5.title = string.format(HELP, "SOCKS", "Forward SOCKS 5" )
+fs5.description = fs4.description
+fs5.rmempty = true
+
+-- forward-socks5t -------------------------------------------------------------
+local f5t = ns:taboption("forward", DynamicList, "forward_socks5t")
+f5t.title = string.format(HELP, "SOCKS", "Forward SOCKS 5t" )
+f5t.description = fs4.description
+f5t.rmempty = true
+
+-- tab: misc -- ################################################################
+
+-- accept-intercepted-requests -------------------------------------------------
+local air = ns:taboption("misc", Flag, "accept_intercepted_requests")
+air.title = string.format(HELP, "ACCEPT-INTERCEPTED-REQUESTS", "Accept intercepted requests" )
+air.description = translate("Whether intercepted requests should be treated as valid.")
+air.orientation = "horizontal"
+air.rmempty = true
+function air.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- allow-cgi-request-crunching -------------------------------------------------
+local crc = ns:taboption("misc", Flag, "allow_cgi_request_crunching")
+crc.title = string.format(HELP, "ALLOW-CGI-REQUEST-CRUNCHING", "Allow CGI request crunching" )
+crc.description = translate("Whether requests to Privoxy's CGI pages can be blocked or redirected.")
+crc.orientation = "horizontal"
+crc.rmempty = true
+function crc.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- split-large-forms -----------------------------------------------------------
+local slf = ns:taboption("misc", Flag, "split_large_forms")
+slf.title = string.format(HELP, "SPLIT-LARGE-FORMS", "Split large forms" )
+slf.description = translate("Whether the CGI interface should stay compatible with broken HTTP clients.")
+slf.orientation = "horizontal"
+slf.rmempty = true
+function slf.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- keep-alive-timeout ----------------------------------------------------------
+local kat = ns:taboption("misc", Value, "keep_alive_timeout")
+kat.title_base = "Keep-alive timeout"
+kat.title = string.format(HELP, "KEEP-ALIVE-TIMEOUT", kat.title_base)
+kat.description = translate("Number of seconds after which an open connection will no longer be reused.")
+kat.rmempty = true
+function kat.validate(self, value)
+ local v = tonumber(value)
+ if not v then
+ return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+ elseif v < 1 then
+ return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
+ end
+ return value
+end
+
+-- tolerate-pipelining ---------------------------------------------------------
+local tp = ns:taboption("misc", Flag, "tolerate_pipelining")
+tp.title = string.format(HELP, "TOLERATE-PIPELINING", "Tolerate pipelining" )
+tp.description = translate("Whether or not pipelined requests should be served.")
+tp.orientation = "horizontal"
+tp.rmempty = true
+function tp.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- default-server-timeout ------------------------------------------------------
+local dst = ns:taboption("misc", Value, "default_server_timeout")
+dst.title_base = "Default server timeout"
+dst.title = string.format(HELP, "DEFAULT-SERVER-TIMEOUT", dst.title_base)
+dst.description = translate("Assumed server-side keep-alive timeout (in seconds) if not specified by the server.")
+dst.rmempty = true
+function dst.validate(self, value)
+ local v = tonumber(value)
+ if not v then
+ return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+ elseif v < 1 then
+ return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
+ end
+ return value
+end
+
+-- connection-sharing ----------------------------------------------------------
+local cs = ns:taboption("misc", Flag, "connection_sharing")
+cs.title = string.format(HELP, "CONNECTION-SHARING", "Connection sharing" )
+cs.description = translate("Whether or not outgoing connections that have been kept alive should be shared between different incoming connections.")
+cs.orientation = "horizontal"
+cs.rmempty = true
+function cs.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- socket-timeout --------------------------------------------------------------
+local st = ns:taboption("misc", Value, "socket_timeout")
+st.title_base = "Socket timeout"
+st.title = string.format(HELP, "SOCKET-TIMEOUT", st.title_base )
+st.description = translate("Number of seconds after which a socket times out if no data is received.")
+st.default = 300
+st.rmempty = true
+function st.validate(self, value)
+ local v = tonumber(value)
+ if not v then
+ return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+ elseif v < 1 then
+ return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
+ elseif v == self.default then
+ return "" -- dont need to save default
+ end
+ return value
+end
+
+-- max-client-connections ------------------------------------------------------
+local mcc = ns:taboption("misc", Value, "max_client_connections")
+mcc.title_base = "Max. client connections"
+mcc.title = string.format(HELP, "MAX-CLIENT-CONNECTIONS", mcc.title_base )
+mcc.description = translate("Maximum number of client connections that will be served.")
+mcc.default = 128
+mcc.rmempty = true
+function mcc.validate(self, value)
+ local v = tonumber(value)
+ if not v then
+ return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+ elseif v < 1 then
+ return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
+ elseif v == self.default then
+ return "" -- dont need to save default
+ end
+ return value
+end
+
+-- handle-as-empty-doc-returns-ok ----------------------------------------------
+local her = ns:taboption("misc", Flag, "handle_as_empty_doc_returns_ok")
+her.title = string.format(HELP, "HANDLE-AS-EMPTY-DOC-RETURNS-OK", "Handle as empty doc returns ok" )
+her.description = translate("The status code Privoxy returns for pages blocked with +handle-as-empty-document.")
+her.orientation = "horizontal"
+her.rmempty = true
+function her.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- enable-compression ----------------------------------------------------------
+local ec = ns:taboption("misc", Flag, "enable_compression")
+ec.title = string.format(HELP, "ENABLE-COMPRESSION", "Enable compression" )
+ec.description = translate("Whether or not buffered content is compressed before delivery.")
+ec.orientation = "horizontal"
+ec.rmempty = true
+function ec.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- compression-level -----------------------------------------------------------
+local cl = ns:taboption("misc", Value, "compression_level")
+cl.title_base = "Compression level"
+cl.title = string.format(HELP, "COMPRESSION-LEVEL", cl.title_base )
+cl.description = translate("The compression level that is passed to the zlib library when compressing buffered content.")
+cl.default = 1
+cl.rmempty = true
+function cl.validate(self, value)
+ local v = tonumber(value)
+ if not v then
+ return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+ elseif v < 0 or v > 9 then
+ return nil, err_tab_misc(self.title_base, translate("Value not between 0 and 9") )
+ elseif v == self.default then
+ return "" -- don't need to save default
+ end
+ return value
+end
+
+-- client-header-order ---------------------------------------------------------
+local cho = ns:taboption("misc", Value, "client_header_order")
+cho.title = string.format(HELP, "CLIENT-HEADER-ORDER", "Client header order" )
+cho.description = translate("The order in which client headers are sorted before forwarding them.")
+ .. [[<br />]]
+ .. translate("Syntax: Client header names delimited by spaces.")
+cho.rmempty = true
+
+-- "debug"-tab definition -- ###################################################
+
+-- single-threaded -------------------------------------------------------------
+local st = ns:taboption("debug", Flag, "single_threaded")
+st.title = string.format(HELP, "SINGLE-THREADED", "Single Threaded" )
+st.description = translate("Whether to run only one server thread.")
+ .. [[<br /><strong>]]
+ .. translate("This option is only there for debugging purposes. It will drastically reduce performance.")
+ .. [[</strong>]]
+st.rmempty = true
+function st.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d1 = ns:taboption("debug", Flag, "debug_1")
+d1.title = string.format(HELP, "DEBUG", "Debug 1" )
+d1.description = translate("Log the destination for each request Privoxy let through. See also 'Debug 1024'.")
+d1.rmempty = true
+function d1.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d2 = ns:taboption("debug", Flag, "debug_2")
+d2.title = string.format(HELP, "DEBUG", "Debug 2" )
+d2.description = translate("Show each connection status")
+d2.rmempty = true
+function d2.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d3 = ns:taboption("debug", Flag, "debug_4")
+d3.title = string.format(HELP, "DEBUG", "Debug 4" )
+d3.description = translate("Show I/O status")
+d3.rmempty = true
+function d3.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d4 = ns:taboption("debug", Flag, "debug_8")
+d4.title = string.format(HELP, "DEBUG", "Debug 8" )
+d4.description = translate("Show header parsing")
+d4.rmempty = true
+function d4.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d5 = ns:taboption("debug", Flag, "debug_16")
+d5.title = string.format(HELP, "DEBUG", "Debug 16" )
+d5.description = translate("Log all data written to the network")
+d5.rmempty = true
+function d5.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d6 = ns:taboption("debug", Flag, "debug_32")
+d6.title = string.format(HELP, "DEBUG", "Debug 32" )
+d6.description = translate("Debug force feature")
+d6.rmempty = true
+function d6.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d7 = ns:taboption("debug", Flag, "debug_64")
+d7.title = string.format(HELP, "DEBUG", "Debug 64" )
+d7.description = translate("Debug regular expression filters")
+d7.rmempty = true
+function d7.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d8 = ns:taboption("debug", Flag, "debug_128")
+d8.title = string.format(HELP, "DEBUG", "Debug 128" )
+d8.description = translate("Debug redirects")
+d8.rmempty = true
+function d8.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d9 = ns:taboption("debug", Flag, "debug_256")
+d9.title = string.format(HELP, "DEBUG", "Debug 256" )
+d9.description = translate("Debug GIF de-animation")
+d9.rmempty = true
+function d9.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d10 = ns:taboption("debug", Flag, "debug_512")
+d10.title = string.format(HELP, "DEBUG", "Debug 512" )
+d10.description = translate("Common Log Format")
+d10.rmempty = true
+function d10.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d11 = ns:taboption("debug", Flag, "debug_1024")
+d11.title = string.format(HELP, "DEBUG", "Debug 1024" )
+d11.description = translate("Log the destination for requests Privoxy didn't let through, and the reason why.")
+d11.rmempty = true
+function d11.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d12 = ns:taboption("debug", Flag, "debug_2048")
+d12.title = string.format(HELP, "DEBUG", "Debug 2048" )
+d12.description = translate("CGI user interface")
+d12.rmempty = true
+function d12.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d13 = ns:taboption("debug", Flag, "debug_4096")
+d13.title = string.format(HELP, "DEBUG", "Debug 4096" )
+d13.description = translate("Startup banner and warnings.")
+d13.rmempty = true
+function d13.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d14 = ns:taboption("debug", Flag, "debug_8192")
+d14.title = string.format(HELP, "DEBUG", "Debug 8192" )
+d14.description = translate("Non-fatal errors - *we highly recommended enabling this*")
+d14.rmempty = true
+function d14.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d15 = ns:taboption("debug", Flag, "debug_32768")
+d15.title = string.format(HELP, "DEBUG", "Debug 32768" )
+d15.description = translate("Log all data read from the network")
+d15.rmempty = true
+function d15.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- debug -----------------------------------------------------------------------
+local d16 = ns:taboption("debug", Flag, "debug_65536")
+d16.title = string.format(HELP, "DEBUG", "Debug 65536" )
+d16.description = translate("Log the applying actions")
+d16.rmempty = true
+function d16.parse(self, section)
+ CTRL.flag_parse(self, section)
+end
+
+-- tab: logview -- #############################################################
+
+local lv = ns:taboption("logview", DummyValue, "_logview")
+lv.template = "privoxy/detail_logview"
+lv.inputtitle = translate("Read / Reread log file")
+lv.rows = 50
+function lv.cfgvalue(self, section)
+ local lfile=self.map:get(ns.section, "logdir") .. "/" .. self.map:get(ns.section, "logfile")
+ if NXFS.access(lfile) then
+ return lfile .. "\n" .. translate("Please press [Read] button")
+ end
+ return lfile .. "\n" .. translate("File not found or empty")
+end
+
+return m
diff --git a/applications/luci-app-privoxy/luasrc/view/privoxy/detail_logview.htm b/applications/luci-app-privoxy/luasrc/view/privoxy/detail_logview.htm
new file mode 100755
index 0000000000..3e190709fb
--- /dev/null
+++ b/applications/luci-app-privoxy/luasrc/view/privoxy/detail_logview.htm
@@ -0,0 +1,56 @@
+
+<!-- ++ BEGIN ++ Privoxy ++ detail_logview.htm ++ -->
+<script type="text/javascript">//<![CDATA[
+ function onclick_logview(section, bottom) {
+ // get elements
+ var txt = document.getElementById("cbid.privoxy.privoxy._logview.txt"); // TextArea
+ if ( !txt ) { return; } // security check
+ var lvXHR = new XHR();
+ lvXHR.get('<%=luci.dispatcher.build_url("admin", "services", "privoxy", "logview")%>', null,
+ function(x) {
+ if (x.responseText == "_nodata_")
+ txt.value = "<%:File not found or empty%>";
+ else
+ txt.value = x.responseText;
+ if (bottom)
+ txt.scrollTop = txt.scrollHeight;
+ else
+ txt.scrollTop = 0; }
+ );
+ }
+//]]></script>
+
+<%+cbi/valueheader%>
+
+<br />
+
+<%
+-- one button on top, one at the buttom
+%>
+<input class="cbi-button cbi-input-button" style="align: center; width: 100%" type="button" onclick="onclick_logview(this.name, false)"
+<%=
+attr("name", section) .. attr("id", cbid .. ".btn1") .. attr("value", self.inputtitle)
+%> />
+
+<br /><br />
+
+<%
+-- set a readable style taken from openwrt theme for textarea#syslog
+-- in openwrt theme there are problems with a width of 100 so we check for theme and set to lower value
+%>
+<textarea style="width: <%if media == "/luci-static/openwrt.org" then%>98.7%<%else%>100%<%end%> ; min-height: 500px; border: 3px solid #cccccc; padding: 5px; font-family: monospace; resize: none;" wrap="off" readonly="readonly"
+<%=
+attr("name", cbid .. ".txt") .. attr("id", cbid .. ".txt") .. ifattr(self.rows, "rows")
+%> >
+<%-=pcdata(self:cfgvalue(section))-%>
+</textarea>
+<br /><br />
+
+<%
+-- one button on top, one at the buttom
+%>
+<input class="cbi-button cbi-input-button" style="align: center; width: 100%" type="button" onclick="onclick_logview(this.name, true)"
+<%= attr("name", section) .. attr("id", cbid .. ".btn2") .. attr("value", self.inputtitle) %> />
+
+<%+cbi/valuefooter%>
+<!-- ++ END ++ Privoxy ++ detail_logview.htm ++ -->
diff --git a/applications/luci-app-privoxy/luasrc/view/privoxy/detail_startstop.htm b/applications/luci-app-privoxy/luasrc/view/privoxy/detail_startstop.htm
new file mode 100644
index 0000000000..b9de8864e4
--- /dev/null
+++ b/applications/luci-app-privoxy/luasrc/view/privoxy/detail_startstop.htm
@@ -0,0 +1,49 @@
+
+<!-- ++ BEGIN ++ Privoxy ++ detail_startstop.htm ++ -->
+<script type="text/javascript">//<![CDATA[
+
+ // show XHR.poll/XHR.get response on button
+ function _data2elements(x) {
+ var btn = document.getElementById("cbid.privoxy.privoxy._startstop");
+ if ( ! btn ) { return; } // security check
+ if (x.responseText == "0") {
+ btn.value = "<%:Start%>";
+ btn.className = "cbi-button cbi-button-apply";
+ btn.disabled = false;
+ } else {
+ btn.value = "PID: " + x.responseText;
+ btn.className = "cbi-button cbi-button-reset";
+ btn.disabled = false;
+ }
+ }
+
+ // event handler for start/stop button
+ function onclick_startstop(id) {
+ // do start/stop
+ var btnXHR = new XHR();
+ btnXHR.get('<%=luci.dispatcher.build_url("admin", "services", "privoxy", "startstop")%>', null,
+ function(x) { _data2elements(x); }
+ );
+ }
+
+ XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "services", "privoxy", "status")%>', null,
+ function(x, data) { _data2elements(x); }
+ );
+
+//]]></script>
+
+<%+cbi/valueheader%>
+
+<% if self:cfgvalue(section) ~= false then
+-- We need to garantie that function cfgvalue run first to set missing parameters
+%>
+ <!-- style="font-size: 100%;" needed for openwrt theme to fix font size -->
+ <!-- type="button" onclick="..." enable standard onclick functionalty -->
+ <input class="cbi-button cbi-input-<%=self.inputstyle or "button" %>" style="font-size: 100%;" type="button" onclick="onclick_startstop(this.id)"
+ <%=
+ attr("name", section) .. attr("id", cbid) .. attr("value", self.inputtitle) .. ifattr(self.disabled, "disabled")
+ %> />
+<% end %>
+
+<%+cbi/valuefooter%>
+<!-- ++ END ++ Privoxy ++ detail_startstop.htm ++ -->
diff --git a/applications/luci-app-privoxy/po/de/privoxy.po b/applications/luci-app-privoxy/po/de/privoxy.po
new file mode 100644
index 0000000000..6ee3af47b7
--- /dev/null
+++ b/applications/luci-app-privoxy/po/de/privoxy.po
@@ -0,0 +1,496 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: luci-app-privoxy\n"
+"POT-Creation-Date: 2015-01-18 21:48+0100\n"
+"PO-Revision-Date: 2015-01-18 21:51+0100\n"
+"Last-Translator: Christian Schoenebeck <christian.schoenebeck@gmail.com>\n"
+"Language-Team: \n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.5.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+
+msgid ""
+"A URL to be displayed in the error page that users will see if access to an "
+"untrusted page is denied."
+msgstr ""
+"Ein Link auf der Fehlerseite, der Benutzern angezeigt wird, wenn der Zugang "
+"zu einer nicht vertrauenswürdigen Seite verweigert wird."
+
+msgid ""
+"A URL to documentation about the local Privoxy setup, configuration or "
+"policies."
+msgstr ""
+"Ein Link zur Dokumentation über die lokale Privoxy Konfiguration und die "
+"Sicherheitseinstellungen."
+
+msgid "Access Control"
+msgstr "Zugriffskontrolle"
+
+msgid "Actions that are applied to all sites and maybe overruled later on."
+msgstr ""
+"Aktionen, die für alle Websites angewendet werden, und vielleicht später "
+"überschrieben werden."
+
+msgid "An alternative directory where the templates are loaded from."
+msgstr "Eine alternatives Verzeichnis, aus dem die Vorlagen geladen werden."
+
+msgid "An email address to reach the Privoxy administrator."
+msgstr "Eine E-Mail-Adresse, um die Privoxy-Administrator zu erreichen."
+
+msgid ""
+"Assumed server-side keep-alive timeout (in seconds) if not specified by the "
+"server."
+msgstr ""
+"Angenommenes serverseitiges Keep-Alive-Timeout (in Sekunden), falls nicht "
+"vom Server festgelegt."
+
+msgid "CGI user interface"
+msgstr "Protokolliert die CGI Benutzer Schnittstelle"
+
+msgid "Common Log Format"
+msgstr "Gemeinsames Protokollformat"
+
+msgid ""
+"Configure here the routing of HTTP requests through a chain of multiple "
+"proxies. Note that parent proxies can severely decrease your privacy level. "
+"Also specified here are SOCKS proxies."
+msgstr ""
+"Konfigurieren Sie hier das Weiterleiten von HTTP-Anforderungen durch eine "
+"Kette von mehreren Proxies. Beachten Sie, dass übergeordnete Proxies Ihre "
+"Privatsphäre stark verringern können. Auch hier angegeben werden SOCKS-"
+"Proxies."
+
+msgid "Debug GIF de-animation"
+msgstr "Protokolliert die GIF de-animation"
+
+msgid "Debug force feature"
+msgstr "Protokolliert die 'Force' Eigenschaft"
+
+msgid "Debug redirects"
+msgstr "Protokolliert Weiterleitungen"
+
+msgid "Debug regular expression filters"
+msgstr "Protokolliert Filter für reguläre Ausdrücke"
+
+msgid "Directory does not exist!"
+msgstr "Verzeichnis existiert nicht!"
+
+msgid "Disabled == Transparent Proxy Mode"
+msgstr "Deaktiviert == Transparent Proxy Betrieb"
+
+msgid "Enable proxy authentication forwarding"
+msgstr "Aktivieren die Weiterleitung von Proxy-Authentifizierungen"
+
+msgid ""
+"Enable/Disable autostart of Privoxy on system startup and interface events"
+msgstr ""
+"Aktivieren / Deaktivieren des Autostart von Privoxy beim Systemstart und "
+"Schnittstellenereignissen."
+
+msgid "Enable/Disable filtering when Privoxy starts."
+msgstr "Aktivieren / Deaktivieren der Filterung, wenn Privoxy startet."
+
+msgid "Enabled"
+msgstr "Aktiviert"
+
+msgid ""
+"Enabling this option is NOT recommended if there is no parent proxy that "
+"requires authentication!"
+msgstr ""
+"Die Aktivierung dieser Option wird NICHT empfohlen, wenn es keinen "
+"übergeordneten Proxy gibt, der eine Authentifizierung erfordert!"
+
+msgid "File '%s' not found inside Configuration Directory"
+msgstr "Datei '%s' nicht im Konfigurationsverzeichnis gefunden!"
+
+msgid "File not found or empty"
+msgstr "Datei nicht gefunden oder leer"
+
+msgid "Files and Directories"
+msgstr "Dateien und Verzeichnisse"
+
+msgid "For help use link at the relevant option"
+msgstr ""
+"Für Hilfe zur Verwendung, benutzen Sie die Verknüpfung der betreffenden "
+"Option."
+
+msgid "Forwarding"
+msgstr "Weiterleitung"
+
+msgid ""
+"If enabled, Privoxy hides the 'go there anyway' link. The user obviously "
+"should not be able to bypass any blocks."
+msgstr ""
+"Wenn aktiviert, verbirgt Privoxy den Link 'go there anyway'. Normalerweise "
+"sollten Benutzer nicht in der Lage sein, Blockierungen zu umgehen."
+
+msgid ""
+"If you intend to operate Privoxy for more users than just yourself, it might "
+"be a good idea to let them know how to reach you, what you block and why you "
+"do that, your policies, etc."
+msgstr ""
+"Wenn Sie beabsichtigen, Privoxy für mehr Nutzer als nur sich selbst zu "
+"betreiben, ist es eine gute Idee, sie wissen zu lassen, wie sie Sie "
+"erreichen können, was Sie blockieren und warum Sie das tun, etc."
+
+msgid "Invalid email address"
+msgstr "Ungültige Email Adresse"
+
+msgid "It is NOT recommended for the casual user."
+msgstr "Es wird NICHT für den gelegentlichen Anwender empfohlen."
+
+msgid "Local Set-up"
+msgstr "Lokale Einstellungen"
+
+msgid "Location of the Privoxy User Manual."
+msgstr "Ort des Privoxy Benutzer Handbuches"
+
+msgid "Log File Viewer"
+msgstr "Protokolldatei"
+
+msgid "Log all data read from the network"
+msgstr "Protokolliert alle Daten, die vom Netzwerk gelesen werden."
+
+msgid "Log all data written to the network"
+msgstr "Protokolliert alle Daten, die auf das Netzwerk geschrieben werden."
+
+msgid "Log the applying actions"
+msgstr "Protokiolliert angewendete Aktionen"
+
+msgid ""
+"Log the destination for each request Privoxy let through. See also 'Debug "
+"1024'."
+msgstr ""
+"Protokolliert das Ziel für jede Anforderung die Privoxy durchlässt. Siehe "
+"auch 'Debug 1024'."
+
+msgid ""
+"Log the destination for requests Privoxy didn't let through, and the reason "
+"why."
+msgstr ""
+"Protokolliert das Ziel für Anfragen die Privoxy nicht durchgelassen hat, und "
+"den Grund dafür."
+
+msgid "Logging"
+msgstr "Protokollierung"
+
+msgid "Main actions file"
+msgstr "Wichtige Aktionen-Datei"
+
+msgid "Mandatory Input: No Data given!"
+msgstr "Pflichtfeld: Keine Daten angegeben!"
+
+msgid "Mandatory Input: No Directory given!"
+msgstr "Pflichtfeld: Kein Verzeichnis angegeben!"
+
+msgid "Mandatory Input: No File given!"
+msgstr "Pflichtfeld: Keine Datei angegeben!"
+
+msgid "Mandatory Input: No Port given!"
+msgstr "Pflichtfeld: Kein Port angegeben!"
+
+msgid "Mandatory Input: No files given!"
+msgstr "Pflichtfeld: Keine Dateien angegeben!"
+
+msgid "Mandatory Input: No valid IPv4 address or host given!"
+msgstr ""
+"Pflichtfeld: Keine gültige IPv4 Adresse oder gültiger Hostname angegeben!"
+
+msgid "Mandatory Input: No valid IPv6 address given!"
+msgstr "Pflichtfeld: Keine gültige IPv6 Adresse angegeben!"
+
+msgid "Mandatory Input: No valid Port given!"
+msgstr "Pflichtfeld: Keine gültige Port Nummer angegeben!"
+
+msgid "Maximum number of client connections that will be served."
+msgstr "Maximale Anzahl von Client-Verbindungen."
+
+msgid "Maximum size (in KB) of the buffer for content filtering."
+msgstr "Maximale Größe (in KB) des Puffers für die Inhaltsfilterung."
+
+msgid "Miscellaneous"
+msgstr "Verschiedenes"
+
+msgid "No trailing '/', please."
+msgstr "Bitte kein '/' am Ende."
+
+msgid "Non-fatal errors - *we highly recommended enabling this*"
+msgstr ""
+"Protokolliert nicht schwerwiegende Fehler - * Es wird dringend empfohlen, "
+"dieses zu aktivieren *"
+
+msgid ""
+"Number of seconds after which a socket times out if no data is received."
+msgstr ""
+"Anzahl der Sekunden, nach der eine Socket Timeout erfolgt, wenn keine Daten "
+"empfangen werden."
+
+msgid ""
+"Number of seconds after which an open connection will no longer be reused."
+msgstr ""
+"Anzahl von Sekunden, nach der eine offene Verbindung nicht mehr "
+"wiederverwendet wird."
+
+msgid "Please press [Read] button"
+msgstr "Bitte Protokolldatei einlesen"
+
+msgid "Please read Privoxy manual for details!"
+msgstr "Bitte lesen Sie das Privoxy Handbuch für Details!"
+
+msgid "Please update to the current version!"
+msgstr "Aktualisieren Sie bitte auf die aktuelle Version!"
+
+msgid "Privoxy WEB proxy"
+msgstr "Privoxy WEB proxy"
+
+msgid ""
+"Privoxy can (and normally does) use a number of other files for additional "
+"configuration, help and logging. This section of the configuration file "
+"tells Privoxy where to find those other files."
+msgstr ""
+"Privoxy verwendet (was in der Regel der Fall ist), eine Reihe von anderen "
+"Dateien für eine zusätzliche Konfiguration, Hilfe und Protokollierung. "
+"Dieser Abschnitt der Konfigurationsdatei definiert, wo diese Dateien zu "
+"finden sind."
+
+msgid ""
+"Privoxy is a non-caching web proxy with advanced filtering capabilities for "
+"enhancing privacy, modifying web page data and HTTP headers, controlling "
+"access, and removing ads and other obnoxious Internet junk."
+msgstr ""
+"Privoxy ist ein non-caching Web-Proxy mit erweiterten Filterfunktion zur "
+"Verbesserung der Privatsphäre. Er modifiziert Webseitendaten und HTTP-"
+"Header, kontrolliert den Zugang und das Entfernen von Anzeigen und anderem "
+"abscheulichen Internet Schrott."
+
+msgid "Read / Reread log file"
+msgstr "Protokolldatei (neu) lesen"
+
+msgid "Show I/O status"
+msgstr "Protokolliert den I/O Status"
+
+msgid "Show each connection status"
+msgstr "Protokolliert jeden Verbindungsstatus"
+
+msgid "Show header parsing"
+msgstr "Protokolliert das 'Header parsing'"
+
+msgid "Software update required"
+msgstr "Softwareaktualisierung nötig"
+
+msgid "Start"
+msgstr "Start"
+
+msgid "Start / Stop"
+msgstr "Start / Stopp"
+
+msgid "Start/Stop Privoxy WEB Proxy"
+msgstr "Start/Stopp Privoxy WEB Proxy"
+
+msgid "Startup banner and warnings."
+msgstr "Protokolliert Start-Meldungen und Warnungen"
+
+msgid "Syntax:"
+msgstr "Syntax:"
+
+msgid "Syntax: Client header names delimited by spaces."
+msgstr "Syntax: Client header Namen getrennt durch Leerzeichen."
+
+msgid "Syntax: target_pattern http_parent[:port]"
+msgstr "Syntax: target_pattern http_parent[:port]"
+
+msgid "Syntax: target_pattern socks_proxy[:port] http_parent[:port]"
+msgstr "Syntax: target_pattern socks_proxy[:port] http_parent[:port]"
+
+msgid ""
+"The actions file(s) to use. Multiple actionsfile lines are permitted, and "
+"are in fact recommended!"
+msgstr ""
+"Die zu verwendenden Aktion-Datei(en). Mehrere Dateien sind gestattet und "
+"empfohlen!"
+
+msgid ""
+"The address and TCP port on which Privoxy will listen for client requests."
+msgstr ""
+"Die Adresse und das TCP-Port, auf dem Privoxy auf Client-Anforderungen "
+"wartet."
+
+msgid ""
+"The compression level that is passed to the zlib library when compressing "
+"buffered content."
+msgstr ""
+"Die Komprimierungsstufe (0-9), die der zlib-Bibliothek beim Komprimieren "
+"gepufferten Inhaltes übergeben wird."
+
+msgid ""
+"The currently installed 'privoxy' package is not supported by LuCI "
+"application."
+msgstr ""
+"Das aktuell installierte 'privoxy' Paket wird von dieser LuCI Anwendung "
+"NICHT unterstützt."
+
+msgid ""
+"The directory where all logging takes place (i.e. where the logfile is "
+"located)."
+msgstr "Das Verzeichnis in dem die Protokolldatei gespeichert wird."
+
+msgid "The directory where the other configuration files are located."
+msgstr "Das Verzeichnis in dem weitere Konfigurationsdateien gespeichert sind."
+
+msgid ""
+"The filter files contain content modification rules that use regular "
+"expressions."
+msgstr ""
+"Die Filterdateien enthalten Änderung des Inhalts, die reguläre Ausdrücke "
+"als Regeln verwenden."
+
+msgid "The hostname shown on the CGI pages."
+msgstr "Der Hostname der auf CGI-Seiten angezeigt wird."
+
+msgid "The log file to use. File name, relative to log directory."
+msgstr ""
+"Zu verwendende Protokolldatei. Dateiname relativ zum Protokoll-Verzeichnis."
+
+msgid "The order in which client headers are sorted before forwarding them."
+msgstr ""
+"Die Reihenfolge, in der Client-Header sortiert werden, bevor sie "
+"weitergeleitet werden."
+
+msgid ""
+"The status code Privoxy returns for pages blocked with +handle-as-empty-"
+"document."
+msgstr ""
+"Ob Statuscode 200(OK) oder 403(forbidden) für Seiten gemeldet wird, die "
+"durch den Filter 'handle-as-empty-document' blockiert werden."
+
+msgid ""
+"The trust mechanism is an experimental feature for building white-lists and "
+"should be used with care."
+msgstr ""
+"Der Trust-Mechanismus ist eine experimentelle Funktion für den Aufbau von "
+"White-Listen und sollte mit Vorsicht verwendet werden."
+
+msgid ""
+"The value of this option only matters if the experimental trust mechanism "
+"has been activated."
+msgstr ""
+"Der Wert dieser Option ist nur wirksam, wenn der experimentelle Trust-"
+"Mechanismus aktiviert wurde."
+
+msgid ""
+"This option is only there for debugging purposes. It will drastically reduce "
+"performance."
+msgstr ""
+"Diese Option ist ausschließlich zur Fehlersuche. Es wird drastisch die "
+"Leistung beeinträchtigt."
+
+msgid ""
+"This option will be removed in future releases as it has been obsoleted by "
+"the more general header taggers."
+msgstr "Diese Option wird in zukünftigen Versionen entfernt werden."
+
+msgid ""
+"This tab controls the security-relevant aspects of Privoxy's configuration."
+msgstr ""
+"Diese Registerkarte steuert die sicherheitsrelevanten Aspekte der Privoxy "
+"Konfiguration."
+
+msgid ""
+"Through which SOCKS proxy (and optionally to which parent HTTP proxy) "
+"specific requests should be routed."
+msgstr ""
+"An welchen SOCKS-Proxy (und gegebenenfalls an welchen übergeordneten HTTP-"
+"Proxy) spezifischen Anforderungen weitergeleitet werden."
+
+msgid "To which parent HTTP proxy specific requests should be routed."
+msgstr ""
+"An welchen übergeordneten HTTP-Proxy spezifischen Anforderungen "
+"weitergeleitet werden."
+
+msgid "User customizations"
+msgstr "Benutzerdefinierte Anpassungen"
+
+msgid "Value is not a number"
+msgstr "Eingabe ist keine Zahl"
+
+msgid "Value not between 0 and 9"
+msgstr "Wert nicht zwischen 0 und 9"
+
+msgid "Value not between 1 and 4096"
+msgstr "Wert nicht zwischen 1 und 4096"
+
+msgid "Value not greater 0 or empty"
+msgstr "Wert nicht größer 0 oder leer"
+
+msgid "Value range 1 to 4096, no entry defaults to 4096"
+msgstr "Wertebereich: 1 bis 4096; Keine Angabe setzt 4096."
+
+msgid "Version"
+msgstr "Version"
+
+msgid "Version Information"
+msgstr "Versionsinformation"
+
+msgid "Whether intercepted requests should be treated as valid."
+msgstr "Ob abgefangen Anfragen als gültig behandelt werden."
+
+msgid ""
+"Whether or not Privoxy recognizes special HTTP headers to change toggle "
+"state."
+msgstr ""
+"Ob Privoxy erkannte spezielle HTTP-Header zur Änderung des Toggle-Status "
+"verwendet.."
+
+msgid "Whether or not buffered content is compressed before delivery."
+msgstr ""
+"Ob gepufferte Inhalte vor der Weiterleitung komprimiert werden oder nicht."
+
+msgid ""
+"Whether or not outgoing connections that have been kept alive should be "
+"shared between different incoming connections."
+msgstr ""
+"Ob ausgehende Verbindungen, die am Leben gehalten werden, für verschiedenen "
+"eingehenden Verbindungen gemeinsam genutzt werden oder nicht."
+
+msgid "Whether or not pipelined requests should be served."
+msgstr "Ob Pipeline-Anfragen bedient werden oder nicht."
+
+msgid "Whether or not proxy authentication through Privoxy should work."
+msgstr ""
+"Ob Proxy-Authentifizierungen durch Privoxy weitergeleitet werden oder nicht."
+
+msgid "Whether or not the web-based actions file editor may be used."
+msgstr "De-/Aktiviert den webbasierte Action-Datei Editor."
+
+msgid "Whether or not the web-based toggle feature may be used."
+msgstr "De-Aktiviert die webbasierte Umschaltfunktion."
+
+msgid "Whether requests to Privoxy's CGI pages can be blocked or redirected."
+msgstr ""
+"Ob Anfragen an Privoxy CGI-Seiten gesperrt oder umgeleitet werden können "
+"oder nicht."
+
+msgid ""
+"Whether the CGI interface should stay compatible with broken HTTP clients."
+msgstr ""
+"Ob die CGI-Schnittstelle mit broken HTTP-Clients kompatibel bleibt oder "
+"nicht."
+
+msgid "Whether to run only one server thread."
+msgstr "Ob nur ein Server-Thread ausgeführt wird."
+
+msgid "Who can access what."
+msgstr "Wer kann auf Was zugreifen."
+
+msgid "installed"
+msgstr "installiert"
+
+msgid "or higher"
+msgstr "oder höher"
+
+msgid "required"
+msgstr "benötigt"
diff --git a/applications/luci-app-privoxy/po/templates/privoxy.pot b/applications/luci-app-privoxy/po/templates/privoxy.pot
new file mode 100644
index 0000000000..8f836bef0f
--- /dev/null
+++ b/applications/luci-app-privoxy/po/templates/privoxy.pot
@@ -0,0 +1,405 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+msgid ""
+"A URL to be displayed in the error page that users will see if access to an "
+"untrusted page is denied."
+msgstr ""
+
+msgid ""
+"A URL to documentation about the local Privoxy setup, configuration or "
+"policies."
+msgstr ""
+
+msgid "Access Control"
+msgstr ""
+
+msgid "Actions that are applied to all sites and maybe overruled later on."
+msgstr ""
+
+msgid "An alternative directory where the templates are loaded from."
+msgstr ""
+
+msgid "An email address to reach the Privoxy administrator."
+msgstr ""
+
+msgid ""
+"Assumed server-side keep-alive timeout (in seconds) if not specified by the "
+"server."
+msgstr ""
+
+msgid "CGI user interface"
+msgstr ""
+
+msgid "Common Log Format"
+msgstr ""
+
+msgid ""
+"Configure here the routing of HTTP requests through a chain of multiple "
+"proxies. Note that parent proxies can severely decrease your privacy level. "
+"Also specified here are SOCKS proxies."
+msgstr ""
+
+msgid "Debug GIF de-animation"
+msgstr ""
+
+msgid "Debug force feature"
+msgstr ""
+
+msgid "Debug redirects"
+msgstr ""
+
+msgid "Debug regular expression filters"
+msgstr ""
+
+msgid "Directory does not exist!"
+msgstr ""
+
+msgid "Disabled == Transparent Proxy Mode"
+msgstr ""
+
+msgid "Enable proxy authentication forwarding"
+msgstr ""
+
+msgid ""
+"Enable/Disable autostart of Privoxy on system startup and interface events"
+msgstr ""
+
+msgid "Enable/Disable filtering when Privoxy starts."
+msgstr ""
+
+msgid "Enabled"
+msgstr ""
+
+msgid ""
+"Enabling this option is NOT recommended if there is no parent proxy that "
+"requires authentication!"
+msgstr ""
+
+msgid "File '%s' not found inside Configuration Directory"
+msgstr ""
+
+msgid "File not found or empty"
+msgstr ""
+
+msgid "Files and Directories"
+msgstr ""
+
+msgid "For help use link at the relevant option"
+msgstr ""
+
+msgid "Forwarding"
+msgstr ""
+
+msgid ""
+"If enabled, Privoxy hides the 'go there anyway' link. The user obviously "
+"should not be able to bypass any blocks."
+msgstr ""
+
+msgid ""
+"If you intend to operate Privoxy for more users than just yourself, it might "
+"be a good idea to let them know how to reach you, what you block and why you "
+"do that, your policies, etc."
+msgstr ""
+
+msgid "Invalid email address"
+msgstr ""
+
+msgid "It is NOT recommended for the casual user."
+msgstr ""
+
+msgid "Local Set-up"
+msgstr ""
+
+msgid "Location of the Privoxy User Manual."
+msgstr ""
+
+msgid "Log File Viewer"
+msgstr ""
+
+msgid "Log all data read from the network"
+msgstr ""
+
+msgid "Log all data written to the network"
+msgstr ""
+
+msgid "Log the applying actions"
+msgstr ""
+
+msgid ""
+"Log the destination for each request Privoxy let through. See also 'Debug "
+"1024'."
+msgstr ""
+
+msgid ""
+"Log the destination for requests Privoxy didn't let through, and the reason "
+"why."
+msgstr ""
+
+msgid "Logging"
+msgstr ""
+
+msgid "Main actions file"
+msgstr ""
+
+msgid "Mandatory Input: No Data given!"
+msgstr ""
+
+msgid "Mandatory Input: No Directory given!"
+msgstr ""
+
+msgid "Mandatory Input: No File given!"
+msgstr ""
+
+msgid "Mandatory Input: No Port given!"
+msgstr ""
+
+msgid "Mandatory Input: No files given!"
+msgstr ""
+
+msgid "Mandatory Input: No valid IPv4 address or host given!"
+msgstr ""
+
+msgid "Mandatory Input: No valid IPv6 address given!"
+msgstr ""
+
+msgid "Mandatory Input: No valid Port given!"
+msgstr ""
+
+msgid "Maximum number of client connections that will be served."
+msgstr ""
+
+msgid "Maximum size (in KB) of the buffer for content filtering."
+msgstr ""
+
+msgid "Miscellaneous"
+msgstr ""
+
+msgid "No trailing '/', please."
+msgstr ""
+
+msgid "Non-fatal errors - *we highly recommended enabling this*"
+msgstr ""
+
+msgid ""
+"Number of seconds after which a socket times out if no data is received."
+msgstr ""
+
+msgid ""
+"Number of seconds after which an open connection will no longer be reused."
+msgstr ""
+
+msgid "Please press [Read] button"
+msgstr ""
+
+msgid "Please read Privoxy manual for details!"
+msgstr ""
+
+msgid "Please update to the current version!"
+msgstr ""
+
+msgid "Privoxy WEB proxy"
+msgstr ""
+
+msgid ""
+"Privoxy can (and normally does) use a number of other files for additional "
+"configuration, help and logging. This section of the configuration file "
+"tells Privoxy where to find those other files."
+msgstr ""
+
+msgid ""
+"Privoxy is a non-caching web proxy with advanced filtering capabilities for "
+"enhancing privacy, modifying web page data and HTTP headers, controlling "
+"access, and removing ads and other obnoxious Internet junk."
+msgstr ""
+
+msgid "Read / Reread log file"
+msgstr ""
+
+msgid "Show I/O status"
+msgstr ""
+
+msgid "Show each connection status"
+msgstr ""
+
+msgid "Show header parsing"
+msgstr ""
+
+msgid "Software update required"
+msgstr ""
+
+msgid "Start"
+msgstr ""
+
+msgid "Start / Stop"
+msgstr ""
+
+msgid "Start/Stop Privoxy WEB Proxy"
+msgstr ""
+
+msgid "Startup banner and warnings."
+msgstr ""
+
+msgid "Syntax:"
+msgstr ""
+
+msgid "Syntax: Client header names delimited by spaces."
+msgstr ""
+
+msgid "Syntax: target_pattern http_parent[:port]"
+msgstr ""
+
+msgid "Syntax: target_pattern socks_proxy[:port] http_parent[:port]"
+msgstr ""
+
+msgid ""
+"The actions file(s) to use. Multiple actionsfile lines are permitted, and "
+"are in fact recommended!"
+msgstr ""
+
+msgid ""
+"The address and TCP port on which Privoxy will listen for client requests."
+msgstr ""
+
+msgid ""
+"The compression level that is passed to the zlib library when compressing "
+"buffered content."
+msgstr ""
+
+msgid ""
+"The currently installed 'privoxy' package is not supported by LuCI "
+"application."
+msgstr ""
+
+msgid ""
+"The directory where all logging takes place (i.e. where the logfile is "
+"located)."
+msgstr ""
+
+msgid "The directory where the other configuration files are located."
+msgstr ""
+
+msgid ""
+"The filter files contain content modification rules that use regular "
+"expressions."
+msgstr ""
+
+msgid "The hostname shown on the CGI pages."
+msgstr ""
+
+msgid "The log file to use. File name, relative to log directory."
+msgstr ""
+
+msgid "The order in which client headers are sorted before forwarding them."
+msgstr ""
+
+msgid ""
+"The status code Privoxy returns for pages blocked with +handle-as-empty-"
+"document."
+msgstr ""
+
+msgid ""
+"The trust mechanism is an experimental feature for building white-lists and "
+"should be used with care."
+msgstr ""
+
+msgid ""
+"The value of this option only matters if the experimental trust mechanism "
+"has been activated."
+msgstr ""
+
+msgid ""
+"This option is only there for debugging purposes. It will drastically reduce "
+"performance."
+msgstr ""
+
+msgid ""
+"This option will be removed in future releases as it has been obsoleted by "
+"the more general header taggers."
+msgstr ""
+
+msgid ""
+"This tab controls the security-relevant aspects of Privoxy's configuration."
+msgstr ""
+
+msgid ""
+"Through which SOCKS proxy (and optionally to which parent HTTP proxy) "
+"specific requests should be routed."
+msgstr ""
+
+msgid "To which parent HTTP proxy specific requests should be routed."
+msgstr ""
+
+msgid "User customizations"
+msgstr ""
+
+msgid "Value is not a number"
+msgstr ""
+
+msgid "Value not between 0 and 9"
+msgstr ""
+
+msgid "Value not between 1 and 4096"
+msgstr ""
+
+msgid "Value not greater 0 or empty"
+msgstr ""
+
+msgid "Value range 1 to 4096, no entry defaults to 4096"
+msgstr ""
+
+msgid "Version"
+msgstr ""
+
+msgid "Version Information"
+msgstr ""
+
+msgid "Whether intercepted requests should be treated as valid."
+msgstr ""
+
+msgid ""
+"Whether or not Privoxy recognizes special HTTP headers to change toggle "
+"state."
+msgstr ""
+
+msgid "Whether or not buffered content is compressed before delivery."
+msgstr ""
+
+msgid ""
+"Whether or not outgoing connections that have been kept alive should be "
+"shared between different incoming connections."
+msgstr ""
+
+msgid "Whether or not pipelined requests should be served."
+msgstr ""
+
+msgid "Whether or not proxy authentication through Privoxy should work."
+msgstr ""
+
+msgid "Whether or not the web-based actions file editor may be used."
+msgstr ""
+
+msgid "Whether or not the web-based toggle feature may be used."
+msgstr ""
+
+msgid "Whether requests to Privoxy's CGI pages can be blocked or redirected."
+msgstr ""
+
+msgid ""
+"Whether the CGI interface should stay compatible with broken HTTP clients."
+msgstr ""
+
+msgid "Whether to run only one server thread."
+msgstr ""
+
+msgid "Who can access what."
+msgstr ""
+
+msgid "installed"
+msgstr ""
+
+msgid "or higher"
+msgstr ""
+
+msgid "required"
+msgstr ""
diff --git a/applications/luci-app-privoxy/root/etc/uci-defaults/luci-privoxy b/applications/luci-app-privoxy/root/etc/uci-defaults/luci-privoxy
new file mode 100755
index 0000000000..3405479b54
--- /dev/null
+++ b/applications/luci-app-privoxy/root/etc/uci-defaults/luci-privoxy
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# no longer needed for "Save and Apply" to restart privoxy
+# luci-app-privoxy calls /etc/init.d/privoxy reload
+uci -q batch <<-EOF >/dev/null
+ delete ucitrack.@privoxy[-1]
+ commit ucitrack
+EOF
+
+rm -f /tmp/luci-indexcache
+
+exit 0
diff --git a/applications/luci-app-siitwizard/luasrc/model/cbi/siitwizard.lua b/applications/luci-app-siitwizard/luasrc/model/cbi/siitwizard.lua
index 4068cdbf54..0d738326a0 100644
--- a/applications/luci-app-siitwizard/luasrc/model/cbi/siitwizard.lua
+++ b/applications/luci-app-siitwizard/luasrc/model/cbi/siitwizard.lua
@@ -1,23 +1,24 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
--- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
+-- Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local uci = require "luci.model.uci".cursor()
local bit = require "nixio".bit
+local ip = require "luci.ip"
-------------------- Init --------------------
--
-- Find link-local address
--
-LL_PREFIX = luci.ip.IPv6("fe80::/64")
function find_ll()
- for _, r in ipairs(luci.sys.net.routes6()) do
- if LL_PREFIX:contains(r.dest) and r.dest:higher(LL_PREFIX) then
- return r.dest:sub(LL_PREFIX)
+ local _, r
+ for _, r in ipairs(ip.routes({ family = 6, dest = "fe80::/64" })) do
+ if r.dest:higher("fe80:0:0:0:ff:fe00:0:0") then
+ return (r.dest - "fe80::")
end
end
- return luci.ip.IPv6("::")
+ return ip.IPv6("::")
end
--
@@ -33,15 +34,15 @@ local ipv4_netsz = uci:get("siit", "ipv4", "netsize") or "24"
--
-- Find IPv4 allocation pool
--
-local gv4_net = luci.ip.IPv4(ipv4_pool)
+local gv4_net = ip.IPv4(ipv4_pool)
--
-- Generate ULA
--
-local ula = luci.ip.IPv6("::/64")
+local ula = ip.IPv6("::/64")
for _, prefix in ipairs({ ula_prefix, ula_global, ula_subnet }) do
- ula = ula:add(luci.ip.IPv6(prefix))
+ ula = ula:add(ip.IPv6(prefix))
end
ula = ula:add(find_ll())
@@ -72,7 +73,7 @@ uci:foreach("wireless", "wifi-device",
lanip = f:field(Value, "ipaddr", "LAN IPv4 subnet")
function lanip.formvalue(self, section)
local val = self.map:formvalue(self:cbid(section))
- local net = luci.ip.IPv4("%s/%i" %{ val, ipv4_netsz })
+ local net = ip.IPv4("%s/%i" %{ val, ipv4_netsz })
if net then
if gv4_net:contains(net) then
@@ -110,7 +111,7 @@ function mode.write(self, section, value)
--
-- Find LAN IPv4 range
--
- local lan_net = luci.ip.IPv4(
+ local lan_net = ip.IPv4(
( lanip:formvalue(section) or "172.16.0.1" ) .. "/" .. ipv4_netsz
)
@@ -182,7 +183,7 @@ function mode.write(self, section, value)
})
-- use full siit subnet
- siit_route = luci.ip.IPv6(siit_prefix .. "/96")
+ siit_route = ip.IPv6(siit_prefix .. "/96")
-- v4 <-> siit route
uci:delete_all("network", "route",
@@ -212,7 +213,7 @@ function mode.write(self, section, value)
})
-- derive siit subnet from lan config
- siit_route = luci.ip.IPv6(
+ siit_route = ip.IPv6(
siit_prefix .. "/" .. (96 + lan_net:prefix())
):add(lan_net[2])
@@ -301,7 +302,7 @@ function mode.write(self, section, value)
-- siit0 route
uci:delete_all("network", "route6",
- function(s) return siit_route:contains(luci.ip.IPv6(s.target)) end)
+ function(s) return siit_route:contains(ip.IPv6(s.target)) end)
uci:section("network", "route6", nil, {
interface = "siit0",
diff --git a/applications/luci-app-splash/luasrc/controller/splash/splash.lua b/applications/luci-app-splash/luasrc/controller/splash/splash.lua
index 97d0400822..4add43559f 100644
--- a/applications/luci-app-splash/luasrc/controller/splash/splash.lua
+++ b/applications/luci-app-splash/luasrc/controller/splash/splash.lua
@@ -23,14 +23,26 @@ function index()
page.leaf = true
end
+function ip_to_mac(ip)
+ local ipc = require "luci.ip"
+ local i, n
+
+ for i, n in ipairs(ipc.neighbors()) do
+ if n.mac and n.dest and n.dest:equal(ip) then
+ return n.mac
+ end
+ end
+end
+
function action_dispatch()
local uci = luci.model.uci.cursor_state()
- local mac = luci.sys.net.ip4mac(luci.http.getenv("REMOTE_ADDR")) or ""
+ local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR")) or ""
local access = false
uci:foreach("luci_splash", "lease", function(s)
if s.mac and s.mac:lower() == mac then access = true end
end)
+
uci:foreach("luci_splash", "whitelist", function(s)
if s.mac and s.mac:lower() == mac then access = true end
end)
@@ -51,13 +63,13 @@ function blacklist()
end
function action_activate()
- local ip = luci.http.getenv("REMOTE_ADDR") or "127.0.0.1"
- local mac = luci.sys.net.ip4mac(ip:match("^[\[::ffff:]*(%d+.%d+%.%d+%.%d+)\]*$"))
+ local ipc = require "luci.ip"
+ local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR") or "127.0.0.1") or ""
local uci_state = require "luci.model.uci".cursor_state()
local blacklisted = false
if mac and luci.http.formvalue("accept") then
uci:foreach("luci_splash", "blacklist",
- function(s) if s.mac:lower() == mac or s.mac == mac then blacklisted = true end
+ function(s) if s.mac and s.mac:lower() == mac then blacklisted = true end
end)
if blacklisted then
luci.http.redirect(luci.dispatcher.build_url("splash" ,"blocked"))
diff --git a/applications/luci-app-splash/luasrc/view/admin_status/splash.htm b/applications/luci-app-splash/luasrc/view/admin_status/splash.htm
index 67bb2fc49e..831fa75f65 100644
--- a/applications/luci-app-splash/luasrc/view/admin_status/splash.htm
+++ b/applications/luci-app-splash/luasrc/view/admin_status/splash.htm
@@ -9,6 +9,7 @@ local utl = require "luci.util"
local ipt = require "luci.sys.iptparser".IptParser()
local uci = require "luci.model.uci".cursor_state()
local wat = require "luci.tools.webadmin"
+local ipc = require "luci.ip"
local fs = require "nixio.fs"
local clients = { }
@@ -100,10 +101,12 @@ if fs.access(leasefile) then
end
end
-for i, a in ipairs(luci.sys.net.arptable()) do
- local c = clients[a["HW address"]:lower()]
- if c and not c.ip then
- c.ip = a["IP address"]
+for i, n in ipairs(ipc.neighbors({ family = 4 })) do
+ if n.mac and n.dest then
+ local c = clients[n.mac]
+ if c and not c.ip then
+ c.ip = n.dest:string()
+ end
end
end
diff --git a/applications/luci-app-splash/root/usr/sbin/luci-splash b/applications/luci-app-splash/root/usr/sbin/luci-splash
index 0f8bdc2c47..e566e9b508 100755
--- a/applications/luci-app-splash/root/usr/sbin/luci-splash
+++ b/applications/luci-app-splash/root/usr/sbin/luci-splash
@@ -2,14 +2,11 @@
utl = require "luci.util"
sys = require "luci.sys"
+ipc = require "luci.ip"
-require("luci.model.uci")
-require("luci.sys.iptparser")
-- Init state session
-local uci = luci.model.uci.cursor_state()
-local ipt = luci.sys.iptparser.IptParser()
-local net = sys.net
+local uci = require "luci.model.uci".cursor_state()
local fs = require "nixio.fs"
local ip = require "luci.ip"
@@ -139,6 +136,30 @@ function ipvalid(ipaddr)
return false
end
+function mac_to_ip(mac)
+ ipc.neighbors({ family = 4 }, function(n)
+ if n.mac == mac and n.dest then
+ return n.dest:string()
+ end
+ end)
+end
+
+function mac_to_dev(mac)
+ ipc.neighbors({ family = 4 }, function(n)
+ if n.mac == mac and n.dev then
+ return n.dev
+ end
+ end)
+end
+
+function ip_to_mac(ip)
+ ipc.neighbors({ family = 4 }, function(n)
+ if n.mac and n.dest and n.dest:equal(ip) then
+ return n.mac
+ end
+ end)
+end
+
function main(argv)
local cmd = table.remove(argv, 1)
local arg = argv[1]
@@ -157,7 +178,6 @@ function main(argv)
lock()
- local arp_cache = net.arptable()
local leased_macs = get_known_macs("lease")
local blacklist_macs = get_known_macs("blacklist")
local whitelist_macs = get_known_macs("whitelist")
@@ -167,17 +187,12 @@ function main(argv)
if adr:find(":") then
mac = adr:lower()
else
- for _, e in ipairs(arp_cache) do
- if e["IP address"] == adr then
- mac = e["HW address"]:lower()
- break
- end
- end
+ mac = ip_to_mac(adr)
end
if mac and cmd == "add-rules" then
if leased_macs[mac] then
- add_lease(mac, arp_cache, true)
+ add_lease(mac, true)
elseif blacklist_macs[mac] then
add_blacklist_rule(mac)
elseif whitelist_macs[mac] then
@@ -277,15 +292,6 @@ function main(argv)
end
end
--- Get current arp cache
-function get_arpcache()
- local arpcache = { }
- for _, entry in ipairs(net.arptable()) do
- arpcache[entry["HW address"]:lower()] = { entry["Device"]:lower(), entry["IP address"]:lower() }
- end
- return arpcache
-end
-
-- Get a list of known mac addresses
function get_known_macs(list)
local leased_macs = { }
@@ -355,17 +361,11 @@ function convert_mac_to_secname(mac)
end
-- Add a lease to state and invoke add_rule
-function add_lease(mac, arp, no_uci)
+function add_lease(mac, no_uci)
mac = mac:lower()
-- Get current ip address
- local ipaddr
- for _, entry in ipairs(arp or net.arptable()) do
- if entry["HW address"]:lower() == mac then
- ipaddr = entry["IP address"]
- break
- end
- end
+ local ipaddr = mac_to_ip(mac)
-- Add lease if there is an ip addr
if ipaddr then
@@ -598,8 +598,6 @@ function sync()
uci:revert("luci_splash_leases")
- local arpcache = get_arpcache()
-
local blackwhitelist = uci:get_all("luci_splash")
local whitelist_total = 0
local whitelist_online = 0
@@ -618,7 +616,7 @@ function sync()
leasecount = leasecount + 1
-- only count leases_online for connected clients
- if arpcache[v.mac] then
+ if mac_to_ip(v.mac) then
leases_online = leases_online + 1
end
@@ -643,7 +641,7 @@ function sync()
whitelist_total = whitelist_total + 1
if s.mac then
local mac = s.mac:lower()
- if arpcache[mac] then
+ if mac_to_ip(mac) then
whitelist_online = whitelist_online + 1
end
end
@@ -652,7 +650,7 @@ function sync()
blacklist_total = blacklist_total + 1
if s.mac then
local mac = s.mac:lower()
- if arpcache[mac] then
+ if mac_to_ip(mac) then
blacklist_online = blacklist_online + 1
end
end
@@ -693,7 +691,6 @@ end
-- Show client info
function list()
- local arpcache = get_arpcache()
-- Find traffic usage
local function traffic(lease)
local traffic_in = 0
@@ -722,12 +719,11 @@ function list()
if s[".type"] == "lease" and s.mac then
local ti, to = traffic(s)
local mac = s.mac:lower()
- local arp = arpcache[mac]
print(string.format(
"%-17s %-15s %-9s %3dm %-7s %7dKB %7dKB",
mac, s.ipaddr, "leased",
math.floor(( os.time() - tonumber(s.start) ) / 60),
- arp and arp[1] or "?", ti, to
+ mac_to_dev(mac) or "?", ti, to
))
end
end
@@ -738,11 +734,10 @@ function list()
) do
if (s[".type"] == "whitelist" or s[".type"] == "blacklist") and s.mac then
local mac = s.mac:lower()
- local arp = arpcache[mac]
print(string.format(
"%-17s %-15s %-9s %4s %-7s %9s %9s",
- mac, arp and arp[2] or "?", s[".type"],
- "- ", arp and arp[1] or "?", "-", "-"
+ mac, mac_to_ip(mac) or "?", s[".type"],
+ "- ", mac_to_dev(mac) or "?", "-", "-"
))
end
end
diff --git a/contrib/luadoc/hostfiles/bin/luadoc b/build/luadoc/doc.lua
index ba99a3775e..383dde29cd 100755
--- a/contrib/luadoc/hostfiles/bin/luadoc
+++ b/build/luadoc/doc.lua
@@ -4,7 +4,12 @@
-- @release $Id: luadoc.lua.in,v 1.1 2008/02/17 06:42:51 jasonsantos Exp $
-------------------------------------------------------------------------------
-require "luadoc"
+--local source = debug.getinfo(1).source or ""
+--local mypath = source:match("@(.+)/[^/]+")
+
+--package.path = package.path .. ";" .. mypath .. "/?.lua;" .. mypath .. "/?/init.lua"
+
+require "luadoc.init"
-------------------------------------------------------------------------------
-- Print version number.
diff --git a/contrib/luadoc/lua/luadoc/config.lua b/build/luadoc/luadoc/config.lua
index 9e4b9de3c5..9e4b9de3c5 100644
--- a/contrib/luadoc/lua/luadoc/config.lua
+++ b/build/luadoc/luadoc/config.lua
diff --git a/contrib/luadoc/lua/luadoc/doclet/debug.lua b/build/luadoc/luadoc/doclet/debug.lua
index 0b75f84cb9..0b75f84cb9 100644
--- a/contrib/luadoc/lua/luadoc/doclet/debug.lua
+++ b/build/luadoc/luadoc/doclet/debug.lua
diff --git a/contrib/luadoc/lua/luadoc/doclet/formatter.lua b/build/luadoc/luadoc/doclet/formatter.lua
index 2d725389c9..2d725389c9 100644
--- a/contrib/luadoc/lua/luadoc/doclet/formatter.lua
+++ b/build/luadoc/luadoc/doclet/formatter.lua
diff --git a/contrib/luadoc/lua/luadoc/doclet/html.lua b/build/luadoc/luadoc/doclet/html.lua
index e77fb74417..e77fb74417 100644
--- a/contrib/luadoc/lua/luadoc/doclet/html.lua
+++ b/build/luadoc/luadoc/doclet/html.lua
diff --git a/contrib/luadoc/lua/luadoc/doclet/html/constant.lp b/build/luadoc/luadoc/doclet/html/constant.lp
index 2e35392ad6..2e35392ad6 100644
--- a/contrib/luadoc/lua/luadoc/doclet/html/constant.lp
+++ b/build/luadoc/luadoc/doclet/html/constant.lp
diff --git a/contrib/luadoc/lua/luadoc/doclet/html/file.lp b/build/luadoc/luadoc/doclet/html/file.lp
index 67926b4a75..68f486404f 100644
--- a/contrib/luadoc/lua/luadoc/doclet/html/file.lp
+++ b/build/luadoc/luadoc/doclet/html/file.lp
@@ -52,7 +52,7 @@
<%for _, func_name in ipairs(file_doc.functions) do
local func_data = file_doc.functions[func_name]%>
<tr>
- <td class="name" nowrap><%=func_data.private and "local " or ""%><a href="#<%=func_name%>"><%=func_name%></a>&nbsp;(<%=table.concat(func_data.param, ", ")%>)</td>
+ <td class="name" nowrap><%=func_data.private and "local " or ""%><a href="#<%=func_name%>"><%=func_name%></a>&nbsp;(<%=table.concat(func_data.param or {}, ", ")%>)</td>
<td class="summary"><%=func_data.summary%></td>
</tr>
<%end%>
diff --git a/contrib/luadoc/lua/luadoc/doclet/html/function.lp b/build/luadoc/luadoc/doclet/html/function.lp
index a870ff8bba..29d403e00f 100644
--- a/contrib/luadoc/lua/luadoc/doclet/html/function.lp
+++ b/build/luadoc/luadoc/doclet/html/function.lp
@@ -8,7 +8,7 @@ else
end
%>
-<dt><%=func.private and "local " or ""%><a name="<%=func.name%>"></a><strong><%=(oop and func.name:gsub("%.",":") or func.name:gsub(".+%.",""))%></strong>&nbsp;(<%=table.concat(func.param or {}, ", ")%>)</dt>
+<dt><%=func.private and "local " or ""%><a name="<%=func.name%>"></a><strong><%=func.printname%></strong>&nbsp;(<%=table.concat(func.param or {}, ", ")%>)</dt>
<dd>
<%=func.description or ""%>
@@ -59,6 +59,6 @@ end
<%=(oop and func.see[i]:gsub("%.",":") or func.see[i]:gsub(".+%.",""))%>
</a>
<%end%>
-</ul
+</ul>
<%end%>
</dd>
diff --git a/contrib/luadoc/lua/luadoc/doclet/html/index.lp b/build/luadoc/luadoc/doclet/html/index.lp
index b4b9f5c3b6..b4b9f5c3b6 100644
--- a/contrib/luadoc/lua/luadoc/doclet/html/index.lp
+++ b/build/luadoc/luadoc/doclet/html/index.lp
diff --git a/contrib/luadoc/lua/luadoc/doclet/html/luadoc.css b/build/luadoc/luadoc/doclet/html/luadoc.css
index bc0f98a5af..f9f9749519 100644
--- a/contrib/luadoc/lua/luadoc/doclet/html/luadoc.css
+++ b/build/luadoc/luadoc/doclet/html/luadoc.css
@@ -32,7 +32,7 @@ hr { color:#cccccc }
img { border-width: 0px; }
-h3 { padding-top: 1em; }
+h3 { padding: 1em 0 0.5em; }
p { margin-left: 1em; }
@@ -81,9 +81,8 @@ table.index ul { padding-top: 0em; margin-top: 0em; }
table {
border: 1px solid black;
- border-collapse: collapse;
- margin-left: auto;
- margin-right: auto;
+ border-collapse: collapse;
+ margin: 1em auto;
}
th {
border: 1px solid black;
@@ -275,8 +274,8 @@ table.table_list td.name { background-color: #f0f0f0; }
table.table_list td.summary { width: 100%; }
dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
-dl.function dd {padding-bottom: 1em;}
-dl.function h3 {padding: 0; margin: 0; font-size: medium;}
+dl.function dd {padding: 0.5em 0;}
+dl.function h3 {margin: 0; font-size: medium;}
dl.table dt {border-top: 1px solid #ccc; padding-top: 1em;}
dl.table dd {padding-bottom: 1em;}
diff --git a/contrib/luadoc/lua/luadoc/doclet/html/menu.lp b/build/luadoc/luadoc/doclet/html/menu.lp
index 0fe365202e..0fe365202e 100644
--- a/contrib/luadoc/lua/luadoc/doclet/html/menu.lp
+++ b/build/luadoc/luadoc/doclet/html/menu.lp
diff --git a/contrib/luadoc/lua/luadoc/doclet/html/module.lp b/build/luadoc/luadoc/doclet/html/module.lp
index daa708628b..0798c1be07 100644
--- a/contrib/luadoc/lua/luadoc/doclet/html/module.lp
+++ b/build/luadoc/luadoc/doclet/html/module.lp
@@ -20,7 +20,7 @@
<div id="navigation">
<%=luadoc.doclet.html.include("menu.lp", { doc=doc, module_doc=module_doc })%>
-<% oop = ( module_doc.doc[1].cstyle == "instance" ) and true or false %>
+<% oop = not not ( module_doc.doc[1] and module_doc.doc[1].cstyle == "instance" ) %>
</div><!-- id="navigation" -->
@@ -58,13 +58,34 @@
</table>
<%end%>
-<%if #module_doc.functions > 0 then %>
+<% local funcs = { }; if #module_doc.functions > 0 then %>
<h2>Functions</h2>
<table class="function_list">
-<%for _, func_name in ipairs(module_doc.functions) do
- local func_data = module_doc.functions[func_name]%>
+<%
+for _, func_name in ipairs(module_doc.functions) do
+ funcs[#funcs+1] = func_name
+end
+
+table.sort(funcs, function(a, b)
+ local func_data_a = module_doc.functions[a]
+ local func_data_b = module_doc.functions[b]
+ local x = func_data_a.sort or a
+ local y = func_data_b.sort or b
+ return x < y
+end)
+
+for _, func_name in ipairs(funcs) do
+ local func_data = module_doc.functions[func_name]
+
+ func_data.printname = func_name:gsub("^%d+#", "")
+ if oop then
+ func_data.printname = func_data.printname:gsub("%.", ":")
+ else
+ func_data.printname = func_data.printname:gsub("^.+%.", "")
+ end
+%>
<tr>
- <td class="name" nowrap><%=func_data.private and "local " or ""%><a href="#<%=func_name%>"><%=(oop and func_name:gsub("%.",":") or func_name:gsub(".+%.",""))%></a>&nbsp;(<%=table.concat(module_doc.functions[func_name].param or {}, ", ")%>)</td>
+ <td class="name" nowrap><%=func_data.private and "local " or ""%><a href="#<%=func_name%>"><%=func_data.printname%></a>&nbsp;(<%=table.concat(module_doc.functions[func_name].param or {}, ", ")%>)</td>
<td class="summary"><%=module_doc.functions[func_name].summary%></td>
</tr>
<%end%>
@@ -72,10 +93,24 @@
<%end%>
-<%if #module_doc.tables > 0 then%>
+<% local tabs = { }; if #module_doc.tables > 0 then%>
<h2>Tables</h2>
<table class="table_list">
-<%for _, tab_name in ipairs(module_doc.tables) do%>
+<%
+for _, tab_name in ipairs(module_doc.tables) do
+ tabs[#tabs+1] = tab_name
+end
+
+table.sort(tabs, function(a, b)
+ local tab_data_a = module_doc.tables[a]
+ local tab_data_b = module_doc.tables[b]
+ local x = tab_data_a.sort or a
+ local y = tab_data_b.sort or b
+ return x < y
+end)
+
+for _, tab_name in ipairs(tabs) do
+%>
<tr>
<td class="name" nowrap><a href="#<%=tab_name%>"><%=tab_name%></a></td>
<td class="summary"><%=module_doc.tables[tab_name].summary%></td>
@@ -91,7 +126,7 @@
<%if #module_doc.functions > 0 then%>
<h2><a name="functions"></a>Functions</h2>
<dl class="function">
-<%for _, func_name in ipairs(module_doc.functions) do%>
+<%for _, func_name in ipairs(funcs) do%>
<%=luadoc.doclet.html.include("function.lp", { doc=doc, module_doc=module_doc, func=module_doc.functions[func_name], oop=oop })%>
<%end%>
</dl>
@@ -100,7 +135,7 @@
<%if #module_doc.tables > 0 then%>
<h2><a name="tables"></a>Tables</h2>
<dl class="table">
-<%for _, tab_name in ipairs(module_doc.tables) do%>
+<%for _, tab_name in ipairs(tabs) do%>
<%=luadoc.doclet.html.include("table.lp", { doc=doc, module_doc=module_doc, tab=module_doc.tables[tab_name] })%>
<%end%>
</dl>
diff --git a/contrib/luadoc/lua/luadoc/doclet/html/table.lp b/build/luadoc/luadoc/doclet/html/table.lp
index 5cd023953a..5cd023953a 100644
--- a/contrib/luadoc/lua/luadoc/doclet/html/table.lp
+++ b/build/luadoc/luadoc/doclet/html/table.lp
diff --git a/contrib/luadoc/lua/luadoc/doclet/raw.lua b/build/luadoc/luadoc/doclet/raw.lua
index 1e880b8830..1e880b8830 100644
--- a/contrib/luadoc/lua/luadoc/doclet/raw.lua
+++ b/build/luadoc/luadoc/doclet/raw.lua
diff --git a/contrib/luadoc/lua/luadoc/init.lua b/build/luadoc/luadoc/init.lua
index 649515de68..649515de68 100644
--- a/contrib/luadoc/lua/luadoc/init.lua
+++ b/build/luadoc/luadoc/init.lua
diff --git a/contrib/luadoc/lua/luadoc/lp.lua b/build/luadoc/luadoc/lp.lua
index adf84f9f0e..adf84f9f0e 100644
--- a/contrib/luadoc/lua/luadoc/lp.lua
+++ b/build/luadoc/luadoc/lp.lua
diff --git a/contrib/luadoc/lua/luadoc/taglet/standard.lua b/build/luadoc/luadoc/taglet/standard.lua
index 17a305889d..ef925f8c73 100644
--- a/contrib/luadoc/lua/luadoc/taglet/standard.lua
+++ b/build/luadoc/luadoc/taglet/standard.lua
@@ -242,7 +242,7 @@ local function parse_comment (block, first_line, modulename)
currenttag = tag
currenttext = text
else
- currenttext = util.concat(currenttext, line)
+ currenttext = util.concat(currenttext, "\n" .. line)
assert(string.sub(currenttext, 1, 1) ~= " ", string.format("`%s', `%s'", currenttext, line))
end
end)
@@ -270,13 +270,15 @@ end
-- @return modulename if found
local function parse_block (f, line, modulename, first)
+ local multiline = not not (line and line:match("%[%["))
local block = {
comment = {},
code = {},
}
while line ~= nil do
- if string.find(line, "^[\t ]*%-%-") == nil then
+ if (multiline == true and string.find(line, "%]%]") ~= nil) or
+ (multiline == false and string.find(line, "^[\t ]*%-%-") == nil) then
-- reached end of comment, read the code below it
-- TODO: allow empty lines
line, block.code, modulename = parse_code(f, line, modulename)
diff --git a/contrib/luadoc/lua/luadoc/taglet/standard/tags.lua b/build/luadoc/luadoc/taglet/standard/tags.lua
index d03df82dfc..e9d0354830 100644
--- a/contrib/luadoc/lua/luadoc/taglet/standard/tags.lua
+++ b/build/luadoc/luadoc/taglet/standard/tags.lua
@@ -7,7 +7,7 @@ local luadoc = require "luadoc"
local util = require "luadoc.util"
local string = require "string"
local table = require "table"
-local assert, type, tostring = assert, type, tostring
+local assert, type, tostring, tonumber = assert, type, tostring, tonumber
module "luadoc.taglet.standard.tags"
@@ -38,6 +38,12 @@ end
-------------------------------------------------------------------------------
+local function sort (tag, block, text)
+ block[tag] = tonumber(text) or 0
+end
+
+-------------------------------------------------------------------------------
+
local function copyright (tag, block, text)
block[tag] = text
end
@@ -164,6 +170,7 @@ handlers["param"] = param
handlers["release"] = release
handlers["return"] = ret
handlers["see"] = see
+handlers["sort"] = sort
handlers["usage"] = usage
-------------------------------------------------------------------------------
@@ -173,6 +180,12 @@ function handle (tag, block, text)
luadoc.logger:error(string.format("undefined handler for tag `%s'", tag))
return
end
+
+ if text then
+ text = text:gsub("`([^\n]-)`", "<code>%1</code>")
+ text = text:gsub("`(.-)`", "<pre>%1</pre>")
+ end
+
-- assert(handlers[tag], string.format("undefined handler for tag `%s'", tag))
return handlers[tag](tag, block, text)
end
diff --git a/contrib/luadoc/lua/luadoc/util.lua b/build/luadoc/luadoc/util.lua
index acaaac8281..e1058d5906 100644
--- a/contrib/luadoc/lua/luadoc/util.lua
+++ b/build/luadoc/luadoc/util.lua
@@ -29,8 +29,9 @@ end
-- @see string.gsub
function trim_comment (s)
- s = string.gsub(s, "%-%-+(.*)$", "%1")
- return trim(s)
+ s = string.gsub(s, "^%s*%-%-+%[%[(.*)$", "%1")
+ s = string.gsub(s, "^%s*%-%-+(.*)$", "%1")
+ return s
end
-------------------------------------------------------------------------------
@@ -58,8 +59,8 @@ end
-------------------------------------------------------------------------------
-- Split text into a list consisting of the strings in text,
--- separated by strings matching delim (which may be a pattern).
--- @param delim if delim is "" then action is the same as %s+ except that
+-- separated by strings matching delim (which may be a pattern).
+-- @param delim if delim is "" then action is the same as %s+ except that
-- field 1 may be preceeded by leading whitespace
-- @usage split(",%s*", "Anna, Bob, Charlie,Dolores")
-- @usage split(""," x y") gives {"x","y"}
@@ -73,12 +74,12 @@ function split(delim, text)
delim = delim or ""
local pos = 1
-- if delim matches empty string then it would give an endless loop
- if string.find("", delim, 1) and delim ~= "" then
+ if string.find("", delim, 1) and delim ~= "" then
error("delim matches empty string!")
end
local first, last
while 1 do
- if delim ~= "" then
+ if delim ~= "" then
first, last = string.find(text, delim, pos)
else
first, last = string.find(text, "%s+", pos)
@@ -169,33 +170,32 @@ function loadlogengine(options)
require "logging"
require "logging.console"
end)
-
+
local logging = logenabled and logging
-
+
if logenabled then
if options.filelog then
logger = logging.file("luadoc.log") -- use this to get a file log
else
logger = logging.console("[%level] %message\n")
end
-
+
if options.verbose then
logger:setLevel(logging.INFO)
else
logger:setLevel(logging.WARN)
end
-
+
else
noop = {__index=function(...)
return function(...)
-- noop
end
end}
-
- logger = {}
+
+ logger = {}
setmetatable(logger, noop)
end
-
+
return logger
end
-
diff --git a/build/makedocs.sh b/build/makedocs.sh
index 2f7f573450..a9fc760e7a 100755
--- a/build/makedocs.sh
+++ b/build/makedocs.sh
@@ -1,2 +1,14 @@
-luadoc -d $2 --no-files $(for f in $(find $1 -name '*.lua' -type f); do if grep -q -- "@return" $f; then echo $f; fi; done)
-echo API-Documentation was created in $2.
+#!/bin/bash
+
+topdir=$(pwd)
+
+[ -f "$topdir/build/makedocs.sh" -a -n "$1" ] || {
+ echo "Please execute as ./build/makedocs.sh [output directory]" >&2
+ exit 1
+}
+
+(
+ cd "$topdir/build/luadoc/"
+ find "$topdir/libs/" "$topdir/modules/" -type f -name '*.lua' -or -name '*.luadoc' | \
+ xargs grep -l '@return' | xargs ./doc.lua --no-files -d "$1"
+)
diff --git a/build/zoneinfo2lua.pl b/build/zoneinfo2lua.pl
index 4a90dae355..d3f0403263 100755
--- a/build/zoneinfo2lua.pl
+++ b/build/zoneinfo2lua.pl
@@ -1,6 +1,6 @@
#!/usr/bin/perl
# zoneinfo2lua.pl - Make Lua module from /usr/share/zoneinfo
-# Execute from within /usr/share/zoneinfo
+# Execute from within root of Luci feed, usually feeds/luci
# $Id$
use strict;
@@ -51,16 +51,7 @@ open(O, "> $tzdout/tzdata.lua") || die "open($tzdout/tzdata.lua): $!\n";
print STDERR "Writing time zones to $tzdout/tzdata.lua ... ";
print O <<HEAD;
---[[
-LuCI - Autogenerated Zoneinfo Module
-
-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
-
-]]--
+-- Licensed to the public under the Apache License 2.0.
module "luci.sys.zoneinfo.tzdata"
@@ -81,16 +72,7 @@ open (O, "> $tzdout/tzoffset.lua") || die "open($tzdout/tzoffset.lua): $!\n";
print STDERR "Writing time offsets to $tzdout/tzoffset.lua ... ";
print O <<HEAD;
---[[
-LuCI - Autogenerated Zoneinfo Module
-
-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
-
-]]--
+-- Licensed to the public under the Apache License 2.0.
module "luci.sys.zoneinfo.tzoffset"
diff --git a/contrib/luadoc/Makefile b/contrib/luadoc/Makefile
deleted file mode 100644
index 81a96f6a83..0000000000
--- a/contrib/luadoc/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-include ../../build/config.mk
-include ../../build/module.mk \ No newline at end of file
diff --git a/libs/luci-lib-httpclient/luasrc/httpclient.lua b/libs/luci-lib-httpclient/luasrc/httpclient.lua
index 94c2e9ecac..c76cc542ed 100644
--- a/libs/luci-lib-httpclient/luasrc/httpclient.lua
+++ b/libs/luci-lib-httpclient/luasrc/httpclient.lua
@@ -97,7 +97,11 @@ end
function request_raw(uri, options)
options = options or {}
local pr, auth, host, port, path
-
+
+ if options.params then
+ uri = uri .. '?' .. http.urlencode_params(options.params)
+ end
+
if uri:find("%[") then
if uri:find("@") then
pr, auth, host, port, path = uri:match("(%w+)://(.+)@(%b[]):?([0-9]*)(.*)")
@@ -176,20 +180,8 @@ function request_raw(uri, options)
options.method = options.method or "POST"
end
- -- Assemble message
- local message = {(options.method or "GET") .. " " .. path .. " " .. protocol}
-
- for k, v in pairs(headers) do
- if type(v) == "string" or type(v) == "number" then
- message[#message+1] = k .. ": " .. v
- elseif type(v) == "table" then
- for i, j in ipairs(v) do
- message[#message+1] = k .. ": " .. j
- end
- end
- end
-
if options.cookies then
+ local cookiedata = {}
for _, c in ipairs(options.cookies) do
local cdo = c.flags.domain
local cpa = c.flags.path
@@ -197,11 +189,29 @@ function request_raw(uri, options)
and (cpa == path or cpa == "/" or cpa .. "/" == path:sub(#cpa+1))
and (not c.flags.secure or pr == "https")
then
- message[#message+1] = "Cookie: " .. c.key .. "=" .. c.value
+ cookiedata[#cookiedata+1] = c.key .. "=" .. c.value
end
end
+ if headers["Cookie"] then
+ headers["Cookie"] = headers["Cookie"] .. "; " .. table.concat(cookiedata, "; ")
+ else
+ headers["Cookie"] = table.concat(cookiedata, "; ")
+ end
end
+
+ -- Assemble message
+ local message = {(options.method or "GET") .. " " .. path .. " " .. protocol}
+ for k, v in pairs(headers) do
+ if type(v) == "string" or type(v) == "number" then
+ message[#message+1] = k .. ": " .. v
+ elseif type(v) == "table" then
+ for i, j in ipairs(v) do
+ message[#message+1] = k .. ": " .. j
+ end
+ end
+ end
+
message[#message+1] = ""
message[#message+1] = ""
@@ -323,7 +333,7 @@ function request_raw(uri, options)
end
end
- return response.code, response, linesrc(true), sock
+ return response.code, response, linesrc(true)..sock:readall(), sock
end
function cookie_parse(cookiestr)
diff --git a/libs/luci-lib-ip/Makefile b/libs/luci-lib-ip/Makefile
new file mode 100644
index 0000000000..eb80dcb258
--- /dev/null
+++ b/libs/luci-lib-ip/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2015 LuCI Team <luci@lists.subsignal.org>
+#
+# This is free software, licensed under the Apache License, Version 2.0 .
+#
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=Lua library for IP calculation and routing information
+LUCI_DEPENDS:=+liblua +libnl-tiny
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/libs/luci-lib-ip/src/Makefile b/libs/luci-lib-ip/src/Makefile
new file mode 100644
index 0000000000..76abd27d2a
--- /dev/null
+++ b/libs/luci-lib-ip/src/Makefile
@@ -0,0 +1,17 @@
+IP_CFLAGS = -std=gnu99 -I$(STAGING_DIR)/usr/include/libnl-tiny/
+IP_LDFLAGS = -llua -lm -lnl-tiny
+IP_OBJ = ip.o
+IP_LIB = ip.so
+
+%.o: %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LUA_CFLAGS) $(IP_CFLAGS) $(FPIC) -c -o $@ $<
+
+compile: $(IP_OBJ)
+ $(CC) $(LDFLAGS) -shared -o $(IP_LIB) $(IP_OBJ) $(IP_LDFLAGS)
+
+install: compile
+ mkdir -p $(DESTDIR)/usr/lib/lua/luci
+ cp $(IP_LIB) $(DESTDIR)/usr/lib/lua/luci/$(IP_LIB)
+
+clean:
+ rm -f *.o *.so
diff --git a/libs/luci-lib-ip/src/ip.c b/libs/luci-lib-ip/src/ip.c
new file mode 100644
index 0000000000..b91966c536
--- /dev/null
+++ b/libs/luci-lib-ip/src/ip.c
@@ -0,0 +1,1392 @@
+/*
+Copyright 2015 Jo-Philipp Wich <jow@openwrt.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
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#include <net/if.h>
+#include <netinet/ether.h>
+#include <arpa/inet.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include <netlink/socket.h>
+#include <linux/rtnetlink.h>
+
+#define LUCI_IP "luci.ip"
+#define LUCI_IP_CIDR "luci.ip.cidr"
+
+#define RTA_INT(x) (*(int *)RTA_DATA(x))
+#define RTA_U32(x) (*(uint32_t *)RTA_DATA(x))
+
+static int hz = 0;
+static struct nl_sock *sock = NULL;
+
+typedef struct {
+ union {
+ struct in_addr v4;
+ struct in6_addr v6;
+ } addr;
+ int len;
+ int bits;
+ int family;
+ bool exact;
+} cidr_t;
+
+struct dump_filter {
+ bool get;
+ int family;
+ int iif;
+ int oif;
+ int type;
+ int scope;
+ int proto;
+ int table;
+ cidr_t gw;
+ cidr_t from;
+ cidr_t src;
+ cidr_t dst;
+ struct ether_addr mac;
+};
+
+struct dump_state {
+ int index;
+ int pending;
+ int callback;
+ struct lua_State *L;
+ struct dump_filter *filter;
+};
+
+
+static int _cidr_new(lua_State *L, int index, int family, bool mask);
+
+static cidr_t *L_checkcidr (lua_State *L, int index, cidr_t *p)
+{
+ if (lua_type(L, index) == LUA_TUSERDATA)
+ return luaL_checkudata(L, index, LUCI_IP_CIDR);
+
+ if (_cidr_new(L, index, p ? p->family : 0, false))
+ return lua_touserdata(L, -1);
+
+ luaL_error(L, "Invalid operand");
+ return NULL;
+}
+
+static bool parse_mask(int family, const char *mask, int *bits)
+{
+ char *e;
+ struct in_addr m;
+ struct in6_addr m6;
+
+ if (family == AF_INET && inet_pton(AF_INET, mask, &m))
+ {
+ for (*bits = 0, m.s_addr = ntohl(m.s_addr);
+ *bits < 32 && (m.s_addr << *bits) & 0x80000000;
+ ++*bits);
+ }
+ else if (family == AF_INET6 && inet_pton(AF_INET6, mask, &m6))
+ {
+ for (*bits = 0;
+ *bits < 128 && (m6.s6_addr[*bits / 8] << (*bits % 8)) & 128;
+ ++*bits);
+ }
+ else
+ {
+ *bits = strtoul(mask, &e, 10);
+
+ if (e == mask || *e != 0 || *bits > ((family == AF_INET) ? 32 : 128))
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_cidr(const char *dest, cidr_t *pp)
+{
+ char *p, buf[INET6_ADDRSTRLEN * 2 + 2];
+ uint8_t bitlen = 0;
+
+ strncpy(buf, dest, sizeof(buf) - 1);
+
+ p = strchr(buf, '/');
+
+ if (p)
+ *p++ = 0;
+
+ if (inet_pton(AF_INET, buf, &pp->addr.v4))
+ {
+ bitlen = 32;
+ pp->family = AF_INET;
+ pp->len = sizeof(struct in_addr);
+ }
+ else if (inet_pton(AF_INET6, buf, &pp->addr.v6))
+ {
+ bitlen = 128;
+ pp->family = AF_INET6;
+ pp->len = sizeof(struct in6_addr);
+ }
+ else
+ return false;
+
+ if (p)
+ {
+ if (!parse_mask(pp->family, p, &pp->bits))
+ return false;
+ }
+ else
+ {
+ pp->bits = bitlen;
+ }
+
+ return true;
+}
+
+static int L_getint(lua_State *L, int index, const char *name)
+{
+ int rv = 0;
+
+ lua_getfield(L, index, name);
+
+ if (lua_type(L, -1) == LUA_TNUMBER)
+ rv = lua_tonumber(L, -1);
+
+ lua_pop(L, 1);
+
+ return rv;
+}
+
+static const char * L_getstr(lua_State *L, int index, const char *name)
+{
+ const char *rv = NULL;
+
+ lua_getfield(L, index, name);
+
+ if (lua_type(L, -1) == LUA_TSTRING)
+ rv = lua_tostring(L, -1);
+
+ lua_pop(L, 1);
+
+ return rv;
+}
+
+static void L_setint(struct lua_State *L, const char *name, uint32_t n)
+{
+ lua_pushinteger(L, n);
+ lua_setfield(L, -2, name);
+}
+
+static void L_setbool(struct lua_State *L, const char *name, bool val)
+{
+ lua_pushboolean(L, val);
+ lua_setfield(L, -2, name);
+}
+
+static void L_setaddr(struct lua_State *L, const char *name,
+ int family, void *addr, int bits)
+{
+ cidr_t *p;
+
+ if (!addr)
+ return;
+
+ p = lua_newuserdata(L, sizeof(*p));
+
+ if (!p)
+ return;
+
+ if (family == AF_INET)
+ {
+ p->family = AF_INET;
+ p->bits = (bits < 0) ? 32 : bits;
+ p->len = sizeof(p->addr.v4);
+ p->addr.v4 = *(struct in_addr *)addr;
+ }
+ else
+ {
+ p->family = AF_INET6;
+ p->bits = (bits < 0) ? 128 : bits;
+ p->len = sizeof(p->addr.v6);
+ p->addr.v6 = *(struct in6_addr *)addr;
+ }
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ lua_setfield(L, -2, name);
+}
+
+static void L_setstr(struct lua_State *L, const char *name, const char *val)
+{
+ lua_pushstring(L, val);
+ lua_setfield(L, -2, name);
+}
+
+static void L_setdev(struct lua_State *L, const char *name,
+ struct nlattr *attr)
+{
+ char buf[32];
+
+ if (if_indextoname(RTA_INT(attr), buf))
+ L_setstr(L, name, buf);
+}
+
+static int L_checkbits(lua_State *L, int index, cidr_t *p)
+{
+ int bits;
+
+ if (lua_gettop(L) < index || lua_isnil(L, index))
+ {
+ bits = p->bits;
+ }
+ else if (lua_type(L, index) == LUA_TNUMBER)
+ {
+ bits = lua_tointeger(L, index);
+
+ if (bits < 0 || bits > ((p->family == AF_INET) ? 32 : 128))
+ return luaL_error(L, "Invalid prefix size");
+ }
+ else if (lua_type(L, index) == LUA_TSTRING)
+ {
+ if (!parse_mask(p->family, lua_tostring(L, index), &bits))
+ return luaL_error(L, "Invalid netmask format");
+ }
+ else
+ {
+ return luaL_error(L, "Invalid data type");
+ }
+
+ return bits;
+}
+
+static int _cidr_new(lua_State *L, int index, int family, bool mask)
+{
+ uint32_t n;
+ const char *addr;
+ cidr_t cidr = { }, *cidrp;
+
+ if (lua_type(L, index) == LUA_TNUMBER)
+ {
+ n = htonl(lua_tointeger(L, index));
+
+ if (family == AF_INET6)
+ {
+ cidr.family = AF_INET6;
+ cidr.bits = 128;
+ cidr.len = sizeof(cidr.addr.v6);
+ cidr.addr.v6.s6_addr[12] = n;
+ cidr.addr.v6.s6_addr[13] = (n >> 8);
+ cidr.addr.v6.s6_addr[14] = (n >> 16);
+ cidr.addr.v6.s6_addr[15] = (n >> 24);
+ }
+ else
+ {
+ cidr.family = AF_INET;
+ cidr.bits = 32;
+ cidr.len = sizeof(cidr.addr.v4);
+ cidr.addr.v4.s_addr = n;
+ }
+ }
+ else
+ {
+ addr = luaL_checkstring(L, index);
+
+ if (!parse_cidr(addr, &cidr))
+ return 0;
+
+ if (family && cidr.family != family)
+ return 0;
+
+ if (mask)
+ cidr.bits = L_checkbits(L, index + 1, &cidr);
+ }
+
+ if (!(cidrp = lua_newuserdata(L, sizeof(*cidrp))))
+ return 0;
+
+ *cidrp = cidr;
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_new(lua_State *L)
+{
+ return _cidr_new(L, 1, 0, true);
+}
+
+static int cidr_ipv4(lua_State *L)
+{
+ return _cidr_new(L, 1, AF_INET, true);
+}
+
+static int cidr_ipv6(lua_State *L)
+{
+ return _cidr_new(L, 1, AF_INET6, true);
+}
+
+static int cidr_is4(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+
+ lua_pushboolean(L, p->family == AF_INET);
+ return 1;
+}
+
+static int cidr_is4rfc1918(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+ uint32_t a = htonl(p->addr.v4.s_addr);
+
+ lua_pushboolean(L, (p->family == AF_INET &&
+ ((a >= 0x0A000000 && a <= 0x0AFFFFFF) ||
+ (a >= 0xAC100000 && a <= 0xAC1FFFFF) ||
+ (a >= 0xC0A80000 && a <= 0xC0A8FFFF))));
+
+ return 1;
+}
+
+static int cidr_is4linklocal(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+ uint32_t a = htonl(p->addr.v4.s_addr);
+
+ lua_pushboolean(L, (p->family == AF_INET &&
+ a >= 0xA9FE0000 &&
+ a <= 0xA9FEFFFF));
+
+ return 1;
+}
+
+static bool _is_mapped4(cidr_t *p)
+{
+ return (p->family == AF_INET6 &&
+ p->addr.v6.s6_addr[0] == 0 &&
+ p->addr.v6.s6_addr[1] == 0 &&
+ p->addr.v6.s6_addr[2] == 0 &&
+ p->addr.v6.s6_addr[3] == 0 &&
+ p->addr.v6.s6_addr[4] == 0 &&
+ p->addr.v6.s6_addr[5] == 0 &&
+ p->addr.v6.s6_addr[6] == 0 &&
+ p->addr.v6.s6_addr[7] == 0 &&
+ p->addr.v6.s6_addr[8] == 0 &&
+ p->addr.v6.s6_addr[9] == 0 &&
+ p->addr.v6.s6_addr[10] == 0xFF &&
+ p->addr.v6.s6_addr[11] == 0xFF);
+}
+
+static int cidr_is6mapped4(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+
+ lua_pushboolean(L, _is_mapped4(p));
+ return 1;
+}
+
+static int cidr_is6(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+
+ lua_pushboolean(L, p->family == AF_INET6);
+ return 1;
+}
+
+static int cidr_is6linklocal(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+
+ lua_pushboolean(L, (p->family == AF_INET6 &&
+ p->addr.v6.s6_addr[0] == 0xFE &&
+ p->addr.v6.s6_addr[1] >= 0x80 &&
+ p->addr.v6.s6_addr[1] <= 0xBF));
+
+ return 1;
+}
+
+static int _cidr_cmp(lua_State *L)
+{
+ cidr_t *a = L_checkcidr(L, 1, NULL);
+ cidr_t *b = L_checkcidr(L, 2, NULL);
+
+ if (a->family != b->family)
+ return (a->family - b->family);
+
+ return memcmp(&a->addr.v6, &b->addr.v6, a->len);
+}
+
+static int cidr_lower(lua_State *L)
+{
+ lua_pushboolean(L, _cidr_cmp(L) < 0);
+ return 1;
+}
+
+static int cidr_higher(lua_State *L)
+{
+ lua_pushboolean(L, _cidr_cmp(L) > 0);
+ return 1;
+}
+
+static int cidr_equal(lua_State *L)
+{
+ lua_pushboolean(L, _cidr_cmp(L) == 0);
+ return 1;
+}
+
+static int cidr_lower_equal(lua_State *L)
+{
+ lua_pushboolean(L, _cidr_cmp(L) <= 0);
+ return 1;
+}
+
+static int cidr_prefix(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+ int bits = L_checkbits(L, 2, p);
+
+ p->bits = bits;
+ lua_pushinteger(L, p->bits);
+ return 1;
+}
+
+static void _apply_mask(cidr_t *p, int bits, bool inv)
+{
+ uint8_t b, i;
+
+ if (bits <= 0)
+ {
+ memset(&p->addr.v6, inv * 0xFF, p->len);
+ }
+ else if (p->family == AF_INET && bits <= 32)
+ {
+ if (inv)
+ p->addr.v4.s_addr |= ntohl((1 << (32 - bits)) - 1);
+ else
+ p->addr.v4.s_addr &= ntohl(~((1 << (32 - bits)) - 1));
+ }
+ else if (p->family == AF_INET6 && bits <= 128)
+ {
+ for (i = 0; i < sizeof(p->addr.v6.s6_addr); i++)
+ {
+ b = (bits > 8) ? 8 : bits;
+ if (inv)
+ p->addr.v6.s6_addr[i] |= ~((uint8_t)(0xFF << (8 - b)));
+ else
+ p->addr.v6.s6_addr[i] &= (uint8_t)(0xFF << (8 - b));
+ bits -= b;
+ }
+ }
+}
+
+static int cidr_network(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL), *p2;
+ int bits = L_checkbits(L, 2, p1);
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ *p2 = *p1;
+ p2->bits = (p1->family == AF_INET) ? 32 : 128;
+ _apply_mask(p2, bits, false);
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_host(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2 = lua_newuserdata(L, sizeof(*p2));
+
+ if (!p2)
+ return 0;
+
+ *p2 = *p1;
+ p2->bits = (p1->family == AF_INET) ? 32 : 128;
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_mask(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL), *p2;
+ int bits = L_checkbits(L, 2, p1);
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ p2->bits = (p1->family == AF_INET) ? 32 : 128;
+ p2->family = p1->family;
+
+ memset(&p2->addr.v6.s6_addr, 0xFF, sizeof(p2->addr.v6.s6_addr));
+ _apply_mask(p2, bits, false);
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_broadcast(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2;
+ int bits = L_checkbits(L, 2, p1);
+
+ if (p1->family == AF_INET6)
+ return 0;
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ *p2 = *p1;
+ p2->bits = (p1->family == AF_INET) ? 32 : 128;
+ _apply_mask(p2, bits, true);
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_mapped4(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2;
+
+ if (!_is_mapped4(p1))
+ return 0;
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ p2->family = AF_INET;
+ p2->bits = (p1->bits > 32) ? 32 : p1->bits;
+ memcpy(&p2->addr.v4, p1->addr.v6.s6_addr + 12, sizeof(p2->addr.v4));
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_contains(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2 = L_checkcidr(L, 2, NULL);
+ cidr_t a = *p1, b = *p2;
+ bool rv = false;
+
+ if (p1->family == p2->family && p1->bits <= p2->bits)
+ {
+ _apply_mask(&a, p1->bits, false);
+ _apply_mask(&b, p1->bits, false);
+
+ rv = !memcmp(&a.addr.v6, &b.addr.v6, a.len);
+ }
+
+ lua_pushboolean(L, rv);
+ return 1;
+}
+
+#define S6_BYTE(a, i) \
+ (a)->addr.v6.s6_addr[sizeof((a)->addr.v6.s6_addr) - (i) - 1]
+
+static int _cidr_add_sub(lua_State *L, bool add)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2 = L_checkcidr(L, 2, p1);
+ cidr_t r = *p1;
+ bool inplace = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : false;
+ bool ok = true;
+ uint8_t i, carry;
+ uint32_t a, b;
+
+ if (p1->family == p2->family)
+ {
+ if (p1->family == AF_INET6)
+ {
+ for (i = 0, carry = 0; i < sizeof(r.addr.v6.s6_addr); i++)
+ {
+ if (add)
+ {
+ S6_BYTE(&r, i) = S6_BYTE(p1, i) + S6_BYTE(p2, i) + carry;
+ carry = (S6_BYTE(p1, i) + S6_BYTE(p2, i) + carry) / 256;
+ }
+ else
+ {
+ S6_BYTE(&r, i) = (S6_BYTE(p1, i) - S6_BYTE(p2, i) - carry);
+ carry = (S6_BYTE(p1, i) < (S6_BYTE(p2, i) + carry));
+ }
+ }
+
+ /* would over/underflow */
+ if (carry)
+ {
+ memset(&r.addr.v6, add * 0xFF, sizeof(r.addr.v6));
+ ok = false;
+ }
+ }
+ else
+ {
+ a = ntohl(p1->addr.v4.s_addr);
+ b = ntohl(p2->addr.v4.s_addr);
+
+ /* would over/underflow */
+ if ((add && (UINT_MAX - a) < b) || (!add && a < b))
+ {
+ r.addr.v4.s_addr = add * 0xFFFFFFFF;
+ ok = false;
+ }
+ else
+ {
+ r.addr.v4.s_addr = add ? htonl(a + b) : htonl(a - b);
+ }
+ }
+ }
+ else
+ {
+ ok = false;
+ }
+
+ if (inplace)
+ {
+ *p1 = r;
+ lua_pushboolean(L, ok);
+ return 1;
+ }
+
+ if (!(p1 = lua_newuserdata(L, sizeof(*p1))))
+ return 0;
+
+ *p1 = r;
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_add(lua_State *L)
+{
+ return _cidr_add_sub(L, true);
+}
+
+static int cidr_sub(lua_State *L)
+{
+ return _cidr_add_sub(L, false);
+}
+
+static int cidr_minhost(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+ cidr_t r = *p;
+ uint8_t i, rest, carry;
+
+ _apply_mask(&r, r.bits, false);
+
+ if (r.family == AF_INET6 && r.bits < 128)
+ {
+ r.bits = 128;
+
+ for (i = 0, carry = 1; i < sizeof(r.addr.v6.s6_addr); i++)
+ {
+ rest = (S6_BYTE(&r, i) + carry) > 255;
+ S6_BYTE(&r, i) += carry;
+ carry = rest;
+ }
+ }
+ else if (r.family == AF_INET && r.bits < 32)
+ {
+ r.bits = 32;
+ r.addr.v4.s_addr = htonl(ntohl(r.addr.v4.s_addr) + 1);
+ }
+
+ if (!(p = lua_newuserdata(L, sizeof(*p))))
+ return 0;
+
+ *p = r;
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_maxhost(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+ cidr_t r = *p;
+
+ _apply_mask(&r, r.bits, true);
+
+ if (r.family == AF_INET && r.bits < 32)
+ {
+ r.bits = 32;
+ r.addr.v4.s_addr = htonl(ntohl(r.addr.v4.s_addr) - 1);
+ }
+ else if (r.family == AF_INET6)
+ {
+ r.bits = 128;
+ }
+
+ if (!(p = lua_newuserdata(L, sizeof(*p))))
+ return 0;
+
+ *p = r;
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_gc (lua_State *L)
+{
+ return 0;
+}
+
+static int cidr_tostring (lua_State *L)
+{
+ char buf[INET6_ADDRSTRLEN];
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+
+ if ((p->family == AF_INET && p->bits < 32) ||
+ (p->family == AF_INET6 && p->bits < 128))
+ {
+ lua_pushfstring(L, "%s/%d",
+ inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)),
+ p->bits);
+ }
+ else
+ {
+ lua_pushstring(L, inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)));
+ }
+
+ return 1;
+}
+
+/*
+ * route functions
+ */
+
+static bool diff_prefix(int family, void *addr, int bits, cidr_t *p)
+{
+ uint8_t i, b, r;
+ uint32_t m;
+
+ if (!p->family)
+ return false;
+
+ if (!addr || p->family != family || p->bits > bits)
+ return true;
+
+ if (family == AF_INET6)
+ {
+ for (i = 0, r = p->bits; i < sizeof(struct in6_addr); i++)
+ {
+ b = r ? (0xFF << (8 - ((r > 8) ? 8 : r))) : 0;
+
+ if ((((struct in6_addr *)addr)->s6_addr[i] & b) !=
+ (p->addr.v6.s6_addr[i] & b))
+ return true;
+
+ r -= ((r > 8) ? 8 : r);
+ }
+ }
+ else
+ {
+ m = p->bits ? htonl(~((1 << (32 - p->bits)) - 1)) : 0;
+
+ if ((((struct in_addr *)addr)->s_addr & m) != (p->addr.v4.s_addr & m))
+ return true;
+ }
+
+ return (p->exact && p->bits != bits);
+}
+
+static int cb_dump_route(struct nl_msg *msg, void *arg)
+{
+ struct dump_state *s = arg;
+ struct dump_filter *f = s->filter;
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ struct rtmsg *rt = NLMSG_DATA(hdr);
+ struct nlattr *tb[RTA_MAX+1];
+ struct in6_addr *src, *dst, *gw, *from, def = { };
+ int iif, oif, bitlen;
+ uint32_t table;
+
+ if (hdr->nlmsg_type != RTM_NEWROUTE ||
+ (rt->rtm_family != AF_INET && rt->rtm_family != AF_INET6))
+ return NL_SKIP;
+
+ nlmsg_parse(hdr, sizeof(*rt), tb, RTA_MAX, NULL);
+
+ iif = tb[RTA_IIF] ? RTA_INT(tb[RTA_IIF]) : 0;
+ oif = tb[RTA_OIF] ? RTA_INT(tb[RTA_OIF]) : 0;
+ table = tb[RTA_TABLE] ? RTA_U32(tb[RTA_TABLE]) : rt->rtm_table;
+ from = tb[RTA_SRC] ? RTA_DATA(tb[RTA_SRC]) : NULL;
+ src = tb[RTA_PREFSRC] ? RTA_DATA(tb[RTA_PREFSRC]) : NULL;
+ dst = tb[RTA_DST] ? RTA_DATA(tb[RTA_DST]) : &def;
+ gw = tb[RTA_GATEWAY] ? RTA_DATA(tb[RTA_GATEWAY]) : NULL;
+
+ bitlen = (rt->rtm_family == AF_INET6) ? 128 : 32;
+
+ if ((f->type && rt->rtm_type != f->type) ||
+ (f->family && rt->rtm_family != f->family) ||
+ (f->proto && rt->rtm_protocol != f->proto) ||
+ (f->scope && rt->rtm_scope != f->scope) ||
+ (f->iif && iif != f->iif) ||
+ (f->oif && oif != f->oif) ||
+ (f->table && table != f->table) ||
+ diff_prefix(rt->rtm_family, from, rt->rtm_src_len, &f->from) ||
+ diff_prefix(rt->rtm_family, dst, rt->rtm_dst_len, &f->dst) ||
+ diff_prefix(rt->rtm_family, gw, bitlen, &f->gw) ||
+ diff_prefix(rt->rtm_family, src, bitlen, &f->src))
+ goto out;
+
+ if (s->callback)
+ lua_pushvalue(s->L, 2);
+
+ lua_newtable(s->L);
+
+ L_setint(s->L, "type", rt->rtm_type);
+ L_setint(s->L, "family", (rt->rtm_family == AF_INET) ? 4 : 6);
+
+ L_setaddr(s->L, "dest", rt->rtm_family, dst, rt->rtm_dst_len);
+
+ if (gw)
+ L_setaddr(s->L, "gw", rt->rtm_family, gw, -1);
+
+ if (from)
+ L_setaddr(s->L, "from", rt->rtm_family, from, rt->rtm_src_len);
+
+ if (iif)
+ L_setdev(s->L, "iif", tb[RTA_IIF]);
+
+ if (oif)
+ L_setdev(s->L, "dev", tb[RTA_OIF]);
+
+ L_setint(s->L, "table", table);
+ L_setint(s->L, "proto", rt->rtm_protocol);
+ L_setint(s->L, "scope", rt->rtm_scope);
+
+ if (src)
+ L_setaddr(s->L, "src", rt->rtm_family, src, -1);
+
+ if (tb[RTA_PRIORITY])
+ L_setint(s->L, "metric", RTA_U32(tb[RTA_PRIORITY]));
+
+ if (rt->rtm_family == AF_INET6 && tb[RTA_CACHEINFO])
+ {
+ struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
+
+ if (ci->rta_expires)
+ {
+ if (ci->rta_expires)
+ L_setint(s->L, "expires", ci->rta_expires / hz);
+
+ if (ci->rta_error != 0)
+ L_setint(s->L, "error", ci->rta_error);
+ }
+ }
+
+ s->index++;
+
+ if (s->callback)
+ lua_call(s->L, 1, 0);
+ else if (hdr->nlmsg_flags & NLM_F_MULTI)
+ lua_rawseti(s->L, -2, s->index);
+
+out:
+ s->pending = !!(hdr->nlmsg_flags & NLM_F_MULTI);
+ return NL_SKIP;
+}
+
+static int
+cb_done(struct nl_msg *msg, void *arg)
+{
+ struct dump_state *s = arg;
+ s->pending = 0;
+ return NL_STOP;
+}
+
+static int
+cb_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
+{
+ struct dump_state *s = arg;
+ s->pending = 0;
+ return NL_STOP;
+}
+
+static int _error(lua_State *L, int code, const char *msg)
+{
+ lua_pushnil(L);
+ lua_pushnumber(L, code ? code : errno);
+ lua_pushstring(L, msg ? msg : strerror(errno));
+
+ return 3;
+}
+
+static int _route_dump(lua_State *L, struct dump_filter *filter)
+{
+ int flags = NLM_F_REQUEST;
+ struct dump_state s = {
+ .L = L,
+ .pending = 1,
+ .index = 0,
+ .callback = lua_isfunction(L, 2),
+ .filter = filter
+ };
+
+ if (!hz)
+ hz = sysconf(_SC_CLK_TCK);
+
+ if (!sock)
+ {
+ sock = nl_socket_alloc();
+ if (!sock)
+ return _error(L, -1, "Out of memory");
+
+ if (nl_connect(sock, NETLINK_ROUTE))
+ return _error(L, 0, NULL);
+ }
+
+ struct nl_msg *msg;
+ struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
+ struct rtmsg rtm = {
+ .rtm_family = filter->family,
+ .rtm_dst_len = filter->dst.bits,
+ .rtm_src_len = filter->src.bits
+ };
+
+ if (!filter->get)
+ flags |= NLM_F_DUMP;
+
+ msg = nlmsg_alloc_simple(RTM_GETROUTE, flags);
+ if (!msg)
+ goto out;
+
+ nlmsg_append(msg, &rtm, sizeof(rtm), 0);
+
+ if (filter->get)
+ nla_put(msg, RTA_DST, filter->dst.len, &filter->dst.addr.v6);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_dump_route, &s);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &s);
+ nl_cb_err(cb, NL_CB_CUSTOM, cb_error, &s);
+
+ nl_send_auto_complete(sock, msg);
+
+ if (!filter->get && !s.callback)
+ lua_newtable(L);
+
+ while (s.pending > 0)
+ nl_recvmsgs(sock, cb);
+
+ nlmsg_free(msg);
+
+out:
+ nl_cb_put(cb);
+ return (s.callback == 0);
+}
+
+static int route_get(lua_State *L)
+{
+ struct dump_filter filter = { .get = true };
+ const char *dest = luaL_checkstring(L, 1);
+
+ if (!parse_cidr(dest, &filter.dst))
+ return _error(L, -1, "Invalid destination");
+
+ filter.family = filter.dst.family;
+
+ return _route_dump(L, &filter);
+}
+
+static int route_dump(lua_State *L)
+{
+ const char *s;
+ cidr_t p = { };
+ struct dump_filter filter = { };
+
+ if (lua_type(L, 1) == LUA_TTABLE)
+ {
+ filter.family = L_getint(L, 1, "family");
+
+ if (filter.family == 4)
+ filter.family = AF_INET;
+ else if (filter.family == 6)
+ filter.family = AF_INET6;
+ else
+ filter.family = 0;
+
+ if ((s = L_getstr(L, 1, "iif")) != NULL)
+ filter.iif = if_nametoindex(s);
+
+ if ((s = L_getstr(L, 1, "oif")) != NULL)
+ filter.oif = if_nametoindex(s);
+
+ filter.type = L_getint(L, 1, "type");
+ filter.scope = L_getint(L, 1, "scope");
+ filter.proto = L_getint(L, 1, "proto");
+ filter.table = L_getint(L, 1, "table");
+
+ if ((s = L_getstr(L, 1, "gw")) != NULL && parse_cidr(s, &p))
+ filter.gw = p;
+
+ if ((s = L_getstr(L, 1, "from")) != NULL && parse_cidr(s, &p))
+ filter.from = p;
+
+ if ((s = L_getstr(L, 1, "src")) != NULL && parse_cidr(s, &p))
+ filter.src = p;
+
+ if ((s = L_getstr(L, 1, "dest")) != NULL && parse_cidr(s, &p))
+ filter.dst = p;
+
+ if ((s = L_getstr(L, 1, "from_exact")) != NULL && parse_cidr(s, &p))
+ filter.from = p, filter.from.exact = true;
+
+ if ((s = L_getstr(L, 1, "dest_exact")) != NULL && parse_cidr(s, &p))
+ filter.dst = p, filter.dst.exact = true;
+ }
+
+ return _route_dump(L, &filter);
+}
+
+
+static bool diff_macaddr(struct ether_addr *mac1, struct ether_addr *mac2)
+{
+ struct ether_addr empty = { };
+
+ if (!memcmp(mac2, &empty, sizeof(empty)))
+ return false;
+
+ if (!mac1 || memcmp(mac1, mac2, sizeof(empty)))
+ return true;
+
+ return false;
+}
+
+static int cb_dump_neigh(struct nl_msg *msg, void *arg)
+{
+ char buf[32];
+ struct ether_addr *mac;
+ struct in6_addr *dst;
+ struct dump_state *s = arg;
+ struct dump_filter *f = s->filter;
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ struct ndmsg *nd = NLMSG_DATA(hdr);
+ struct nlattr *tb[NDA_MAX+1];
+ int bitlen;
+
+ if (hdr->nlmsg_type != RTM_NEWNEIGH ||
+ (nd->ndm_family != AF_INET && nd->ndm_family != AF_INET6))
+ return NL_SKIP;
+
+ nlmsg_parse(hdr, sizeof(*nd), tb, NDA_MAX, NULL);
+
+ mac = tb[NDA_LLADDR] ? RTA_DATA(tb[NDA_LLADDR]) : NULL;
+ dst = tb[NDA_DST] ? RTA_DATA(tb[NDA_DST]) : NULL;
+
+ bitlen = (nd->ndm_family == AF_INET) ? 32 : 128;
+
+ if ((f->family && nd->ndm_family != f->family) ||
+ (f->iif && nd->ndm_ifindex != f->iif) ||
+ (f->type && !(f->type & nd->ndm_state)) ||
+ diff_prefix(nd->ndm_family, dst, bitlen, &f->dst) ||
+ diff_macaddr(mac, &f->mac))
+ goto out;
+
+ if (s->callback)
+ lua_pushvalue(s->L, 2);
+
+ lua_newtable(s->L);
+
+ L_setint(s->L, "family", (nd->ndm_family == AF_INET) ? 4 : 6);
+ L_setstr(s->L, "dev", if_indextoname(nd->ndm_ifindex, buf));
+
+ L_setbool(s->L, "router", (nd->ndm_flags & NTF_ROUTER));
+ L_setbool(s->L, "proxy", (nd->ndm_flags & NTF_PROXY));
+
+ L_setbool(s->L, "incomplete", (nd->ndm_state & NUD_INCOMPLETE));
+ L_setbool(s->L, "reachable", (nd->ndm_state & NUD_REACHABLE));
+ L_setbool(s->L, "stale", (nd->ndm_state & NUD_STALE));
+ L_setbool(s->L, "delay", (nd->ndm_state & NUD_DELAY));
+ L_setbool(s->L, "probe", (nd->ndm_state & NUD_PROBE));
+ L_setbool(s->L, "failed", (nd->ndm_state & NUD_FAILED));
+ L_setbool(s->L, "noarp", (nd->ndm_state & NUD_NOARP));
+ L_setbool(s->L, "permanent", (nd->ndm_state & NUD_PERMANENT));
+
+ if (dst)
+ L_setaddr(s->L, "dest", nd->ndm_family, dst, -1);
+
+ if (mac)
+ {
+ snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac->ether_addr_octet[0], mac->ether_addr_octet[1],
+ mac->ether_addr_octet[2], mac->ether_addr_octet[3],
+ mac->ether_addr_octet[4], mac->ether_addr_octet[5]);
+
+ lua_pushstring(s->L, buf);
+ lua_setfield(s->L, -2, "mac");
+ }
+
+ s->index++;
+
+ if (s->callback)
+ lua_call(s->L, 1, 0);
+ else if (hdr->nlmsg_flags & NLM_F_MULTI)
+ lua_rawseti(s->L, -2, s->index);
+
+out:
+ s->pending = !!(hdr->nlmsg_flags & NLM_F_MULTI);
+ return NL_SKIP;
+}
+
+static int neighbor_dump(lua_State *L)
+{
+ cidr_t p = { };
+ const char *s;
+ struct ether_addr *mac;
+ struct dump_filter filter = { .type = 0xFF & ~NUD_NOARP };
+ struct dump_state st = {
+ .callback = lua_isfunction(L, 2),
+ .pending = 1,
+ .filter = &filter,
+ .L = L
+ };
+
+ if (lua_type(L, 1) == LUA_TTABLE)
+ {
+ filter.family = L_getint(L, 1, "family");
+
+ if (filter.family == 4)
+ filter.family = AF_INET;
+ else if (filter.family == 6)
+ filter.family = AF_INET6;
+ else
+ filter.family = 0;
+
+ if ((s = L_getstr(L, 1, "dev")) != NULL)
+ filter.iif = if_nametoindex(s);
+
+ if ((s = L_getstr(L, 1, "dest")) != NULL && parse_cidr(s, &p))
+ filter.dst = p;
+
+ if ((s = L_getstr(L, 1, "mac")) != NULL &&
+ (mac = ether_aton(s)) != NULL)
+ filter.mac = *mac;
+ }
+
+ if (!sock)
+ {
+ sock = nl_socket_alloc();
+ if (!sock)
+ return _error(L, -1, "Out of memory");
+
+ if (nl_connect(sock, NETLINK_ROUTE))
+ return _error(L, 0, NULL);
+ }
+
+ struct nl_msg *msg;
+ struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
+ struct ndmsg ndm = {
+ .ndm_family = filter.family
+ };
+
+ msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
+ if (!msg)
+ goto out;
+
+ nlmsg_append(msg, &ndm, sizeof(ndm), 0);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_dump_neigh, &st);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st);
+ nl_cb_err(cb, NL_CB_CUSTOM, cb_error, &st);
+
+ nl_send_auto_complete(sock, msg);
+
+ if (!st.callback)
+ lua_newtable(L);
+
+ while (st.pending > 0)
+ nl_recvmsgs(sock, cb);
+
+ nlmsg_free(msg);
+
+out:
+ nl_cb_put(cb);
+ return (st.callback == 0);
+}
+
+
+static int cb_dump_link(struct nl_msg *msg, void *arg)
+{
+ char *p, *addr, buf[48];
+ struct dump_state *s = arg;
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ struct ifinfomsg *ifm = NLMSG_DATA(hdr);
+ struct nlattr *tb[IFLA_MAX+1];
+ int i, len;
+
+ if (hdr->nlmsg_type != RTM_NEWLINK)
+ return NL_SKIP;
+
+ nlmsg_parse(hdr, sizeof(*ifm), tb, IFLA_MAX, NULL);
+
+ L_setbool(s->L, "up", (ifm->ifi_flags & IFF_RUNNING));
+ L_setint(s->L, "type", ifm->ifi_type);
+ L_setstr(s->L, "name", if_indextoname(ifm->ifi_index, buf));
+
+ if (tb[IFLA_MTU])
+ L_setint(s->L, "mtu", RTA_U32(tb[IFLA_MTU]));
+
+ if (tb[IFLA_TXQLEN])
+ L_setint(s->L, "qlen", RTA_U32(tb[IFLA_TXQLEN]));
+
+ if (tb[IFLA_MASTER])
+ L_setdev(s->L, "master", tb[IFLA_MASTER]);
+
+ if (tb[IFLA_ADDRESS])
+ {
+ len = nla_len(tb[IFLA_ADDRESS]);
+ addr = nla_get_string(tb[IFLA_ADDRESS]);
+
+ if ((len * 3) <= sizeof(buf))
+ {
+ for (p = buf, i = 0; i < len; i++)
+ p += sprintf(p, "%s%02x", (i ? ":" : ""), (uint8_t)*addr++);
+
+ L_setstr(s->L, "mac", buf);
+ }
+ }
+
+ s->pending = 0;
+ return NL_SKIP;
+}
+
+static int link_get(lua_State *L)
+{
+ const char *dev = luaL_checkstring(L, 1);
+ struct dump_state st = {
+ .pending = 1,
+ .L = L
+ };
+
+ if (!sock)
+ {
+ sock = nl_socket_alloc();
+ if (!sock)
+ return _error(L, -1, "Out of memory");
+
+ if (nl_connect(sock, NETLINK_ROUTE))
+ return _error(L, 0, NULL);
+ }
+
+ struct nl_msg *msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST);
+ struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
+ struct ifinfomsg ifm = { .ifi_index = if_nametoindex(dev) };
+
+ if (!msg || !cb)
+ return 0;
+
+ nlmsg_append(msg, &ifm, sizeof(ifm), 0);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_dump_link, &st);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st);
+ nl_cb_err(cb, NL_CB_CUSTOM, cb_error, &st);
+
+ lua_newtable(L);
+
+ nl_send_auto_complete(sock, msg);
+
+ while (st.pending > 0)
+ nl_recvmsgs(sock, cb);
+
+ nlmsg_free(msg);
+ nl_cb_put(cb);
+
+ return 1;
+}
+
+
+static const luaL_reg ip_methods[] = {
+ { "new", cidr_new },
+ { "IPv4", cidr_ipv4 },
+ { "IPv6", cidr_ipv6 },
+
+ { "route", route_get },
+ { "routes", route_dump },
+
+ { "neighbors", neighbor_dump },
+
+ { "link", link_get },
+
+ { }
+};
+
+static const luaL_reg ip_cidr_methods[] = {
+ { "is4", cidr_is4 },
+ { "is4rfc1918", cidr_is4rfc1918 },
+ { "is4linklocal", cidr_is4linklocal },
+ { "is6", cidr_is6 },
+ { "is6linklocal", cidr_is6linklocal },
+ { "is6mapped4", cidr_is6mapped4 },
+ { "lower", cidr_lower },
+ { "higher", cidr_higher },
+ { "equal", cidr_equal },
+ { "prefix", cidr_prefix },
+ { "network", cidr_network },
+ { "host", cidr_host },
+ { "mask", cidr_mask },
+ { "broadcast", cidr_broadcast },
+ { "mapped4", cidr_mapped4 },
+ { "contains", cidr_contains },
+ { "add", cidr_add },
+ { "sub", cidr_sub },
+ { "minhost", cidr_minhost },
+ { "maxhost", cidr_maxhost },
+ { "string", cidr_tostring },
+
+ { "__lt", cidr_lower },
+ { "__le", cidr_lower_equal },
+ { "__eq", cidr_equal },
+ { "__add", cidr_add },
+ { "__sub", cidr_sub },
+ { "__gc", cidr_gc },
+ { "__tostring", cidr_tostring },
+
+ { }
+};
+
+int luaopen_luci_ip(lua_State *L)
+{
+ luaL_register(L, LUCI_IP, ip_methods);
+
+ luaL_newmetatable(L, LUCI_IP_CIDR);
+ luaL_register(L, NULL, ip_cidr_methods);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ lua_pop(L, 1);
+
+ return 1;
+}
diff --git a/libs/luci-lib-ip/src/ip.luadoc b/libs/luci-lib-ip/src/ip.luadoc
new file mode 100644
index 0000000000..00738832c4
--- /dev/null
+++ b/libs/luci-lib-ip/src/ip.luadoc
@@ -0,0 +1,831 @@
+--- LuCI IP calculation and netlink access library.
+module "luci.ip"
+
+---[[
+Construct a new luci.ip.cidr instance and autodetect the address family.
+Throws an error if the given strings do not represent a valid address or
+if the given optional netmask is of a different family.
+@class function
+@sort 1
+@name new
+@param address String containing a valid IPv4 or IPv6 address, optionally
+with prefix size (CIDR notation) or netmask separated by slash.
+@param netmask String containing a valid IPv4 or IPv6 netmask or number
+containing a prefix size in bits (`0..32` for IPv4,
+`0..128` for IPv6). Overrides mask embedded in the first argument
+if specified. (optional)
+@return A `luci.ip.cidr` object representing the given
+address/mask range.
+@usage `addr = luci.ip.new("10.24.0.1/24")
+addr = luci.ip.new("10.24.0.1/255.255.255.0")
+addr = luci.ip.new("10.24.0.1", "255.255.255.0") -- separate netmask
+addr = luci.ip.new("10.24.0.1/24", 16) -- override netmask
+
+addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/64")
+addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/ffff:ffff:ffff:ffff::")
+addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17", "ffff:ffff:ffff:ffff::")
+addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/64", 128) -- override netmask`
+@see IPv4
+@see IPv6
+]]
+
+---[[
+Construct a new IPv4 luci.ip.cidr instance.
+Throws an error if the given string does not represent a valid IPv4 address or
+if the given optional netmask is of a different family.
+@class function
+@sort 2
+@name IPv4
+@param address String containing a valid IPv4, optionally with prefix size
+(CIDR notation) or netmask separated by slash.
+@param netmask String containing a valid IPv4 netmask or number
+containing a prefix size between `0` and `32` bit.
+Overrides mask embedded in the first argument if specified. (optional)
+@return A `luci.ip.cidr` object representing the given IPv4 range.
+@usage `addr = luci.ip.new("10.24.0.1/24")
+addr = luci.ip.new("10.24.0.1/255.255.255.0")
+addr = luci.ip.new("10.24.0.1", "255.255.255.0") -- separate netmask
+addr = luci.ip.new("10.24.0.1/24", 16) -- override netmask`
+@see IPv6
+]]
+
+---[[
+Construct a new IPv6 luci.ip.cidr instance.
+Throws an error if the given string does not represent a valid IPv6 address or
+if the given optional netmask is of a different family.
+@class function
+@sort 3
+@name IPv6
+@param address String containing a valid IPv6, optionally with prefix size
+(CIDR notation) or netmask separated by slash.
+@param netmask String containing a valid IPv4 netmask or number
+containing a prefix size between `0` and `128` bit.
+Overrides mask embedded in the first argument if specified. (optional)
+@return A `luci.ip.cidr` object representing the given IPv6 range.
+@usage `addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/64")
+addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/ffff:ffff:ffff:ffff::")
+addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17", "ffff:ffff:ffff:ffff::")
+addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/64", 128) -- override netmask`
+@see IPv4
+]]
+
+---[[
+Determine the route leading to the given destination.
+@class function
+@sort 4
+@name route
+@param address A `luci.ip.cidr` instance or a string containing
+a valid IPv4 or IPv6 range as specified by `luci.ip.new()`.
+@return <p>Table containing the fields described below.</p>
+<table id="routetable">
+<tr><th>Field</th><th>Description</th></tr>
+<tr><td>`type`<td>
+ <p>Route type with one of the following numeric values:</p>
+ <table>
+ <tr>
+ <td>`1`</td>
+ <td>`RTN_UNICAST` - Gateway or direct route</td>
+ </tr>
+ <tr>
+ <td>`2`</td>
+ <td>`RTN_LOCAL` - Accept locally</td>
+ </tr>
+ <tr>
+ <td>`3`</td>
+ <td>`RTN_BROADCAST` -
+ Accept locally as broadcast send as broadcast</td>
+ </tr>
+ <tr>
+ <td>`4`</td>
+ <td>`RTN_ANYCAST` -
+ Accept locally as broadcast but send as unicast</td>
+ </tr>
+ <tr>
+ <td>`5`</td>
+ <td>`RTN_MULTICAST` - Multicast route</td>
+ </tr>
+ </table>
+</td></tr>
+<tr>
+ <td>`family`</td>
+ <td>Number containing the route family, `4` for IPv4 or
+ `6` for IPv6</td>
+</tr>
+<tr>
+ <td>`dest`</td>
+ <td>Destination `luci.ip.cidr` instance</td>
+</tr>
+<tr>
+ <td>`gw`</td>
+ <td>Gateway `luci.ip.cidr` instance (optional)</td>
+</tr>
+<tr>
+ <td>`from`</td>
+ <td>Source address `luci.ip.cidr` instance (optional)</td>
+</tr>
+<tr>
+ <td>`src`</td>
+ <td>Preferred source `luci.ip.cidr` instance (optional)</td>
+</tr>
+<tr>
+ <td>`dev`</td>
+ <td>String containing the name of the outgoing interface</td>
+</tr>
+<tr>
+ <td>`iif`</td>
+ <td>String containing the name of the incoming interface (optional)</td>
+</tr>
+<tr>
+ <td>`table`</td>
+ <td>Number of the associated routing table (`0..65535`)</td>
+</tr>
+<tr>
+ <td>`proto`</td>
+ <td>Number of the associated routing protocol</td>
+</tr>
+<tr>
+ <td>`scope`</td>
+ <td>Number describing the scope of the route, most commonly
+ `0` for global or `253` for on-link</td>
+</tr>
+<tr>
+ <td>`metric`</td>
+ <td>Number describing the route metric (optional)</td>
+</tr>
+<tr>
+ <td>`expires`</td>
+ <td>Number of seconds the prefix is valid (IPv6 only, optional)</td>
+</tr>
+<tr>
+ <td>`error`</td>
+ <td>Route destination error code (optional)</td>
+</tr>
+</table>
+@usage <ul>
+<li>Find default gateway by getting route to Google's public NS server
+`rt = luci.ip.route("8.8.8.8")
+if rt ~= nil then
+ print("gateway is", rt.gw)
+end`</li>
+<li>Determine IPv6 upstream interface `rt = luci.ip.route("2001::/7")
+if rt ~= nil then
+ print("ipv6 upstream device is", rt.dev)
+end`</li>
+</ul>
+@see routes
+]]
+
+---[[
+Fetch all routes, optionally matching the given criteria.
+@class function
+@sort 5
+@name routes
+@param filter <p>Table containing one or more of the possible filter
+critera described below (optional)</p><table>
+<tr><th>Field</th><th>Description</th></tr>
+<tr><td>`family`</td><td>
+ Number describing the address family to return - `4` selects
+ IPv4 routes, `6` IPv6 ones. Any other value selects both.
+</td></tr>
+<tr><td>`iif`</td><td>
+ String containing the incoming route interface to match.
+</td></tr>
+<tr><td>`oif`</td><td>
+ String containing the outgoing route interface to match.
+</td></tr>
+<tr><td>`type`</td><td>
+ Numeric type to match, e.g. `1` for unicast.
+</td></tr>
+<tr><td>`scope`</td><td>
+ Numeric scope to match, e.g. `253` for onlink.
+</td></tr>
+<tr><td>`proto`</td><td>
+ Numeric protocol to match, e.g. `2` for boot.
+</td></tr>
+<tr><td>`table`</td><td>
+ Numeric routing table to match (`0..65535`).
+</td></tr>
+<tr><td>`gw`</td><td>
+ String containing the gateway address to match. Can be in any notation
+ specified by `luci.ip.new()`. Prefix matching is performed when
+ comparing the routes, e.g. "192.168.1.0/24" would select routes with gateway
+ addresses `192.168.1.1 .. 192.168.1.255`.
+</td></tr>
+<tr><td>`dest`</td><td>
+ String containing the destination to match. Prefix matching is performed.
+</td></tr>
+<tr><td>`from`</td><td>
+ String containing the source address to match. Prefix matching is performed.
+</td></tr>
+<tr><td>`src`</td><td>
+ String containing the preferred source address to match.
+ Prefix matching is performed.
+</td></tr>
+<tr><td>`dest_exact`</td><td>
+ String containing the destination to match. Exact matching is performed,
+ e.g. `dest = "0.0.0.0/0"` would match <em>any</em> IPv4 route
+ while `dest_exact = "0.0.0.0/0"` will <em>only</em> match the
+ default route.
+</td></tr>
+<tr><td>`from_exact`</td><td>
+ String containing the source address to match. Exact matching is performed.
+</td></tr>
+</table>
+@param callback <p>Callback function to invoke for each found route
+instead of returning one table of route objects (optional)</p>
+@return If no callback function is provided, a table of routes
+<a href="#routetable">as specified by `luci.ip.route()`</a>
+is returned. If a callback function is given, it is invoked for each route
+and nothing is returned.
+@see route
+@usage <ul>
+<li>Find all IPv4 default routes:
+`luci.ip.routes({ dest_exact = "0.0.0.0/0" }, function(rt)
+ print(rt.type, rt.gw, rt.dev)
+end)`</li>
+<li>Find all global IPv6 prefixes on the current system:
+`luci.ip.routes({ from = "2001::/7" }, function(rt)
+ print(rt.from)
+end)`</li>
+<li>Fetch all IPv4 routes:
+`routes = luci.ip.routes({ family = 4 })
+for _, rt in ipairs(routes) do
+ print(rt.dest, rt.gw, rt.dev)
+end`</li>
+</ul>
+]]
+
+---[[
+Fetches entries from the IPv4 ARP and IPv6 neighbour kernel table
+@class function
+@sort 6
+@name neighbors
+@param filter <p>Table containing one or more of the possible filter
+critera described below (optional)</p><table>
+<tr><th>Field</th><th>Description</th></tr>
+<tr><td>`family`</td><td>
+ Number describing the address family to return - `4` selects
+ IPv4 ARP, `6` select IPv6 neighbour entries. Any other value
+ selects both.
+</td></tr>
+<tr><td>`dev`</td><td>
+ String containing the associated interface to match.
+</td></tr>
+<tr><td>`dest`</td><td>
+ String containing the associated address to match. Can be in any notation
+ specified by `luci.ip.new()`. Prefix matching is performed when
+ comparing the addresses, e.g. "192.168.1.0/24" would select ARP entries
+ for `192.168.1.1 .. 192.168.1.255`.
+</td></tr>
+<tr><td>`mac`</td><td>
+ String containing MAC address to match.
+</td></tr>
+</table>
+@param callback <p>Callback function to invoke for each found neighbour
+entry instead of returning one table of neighbour entries (optional)</p>
+@return If no callback function is provided, a table of neighbour entries
+is returned. If a callback function is given, it is invoked for each entry
+and nothing is returned.
+
+A neighbour entry is a table containing the following fields:
+
+<table>
+<tr><th>Field</th><th>Description</th></tr>
+<tr>
+ <td>`family`</td>
+ <td>Number containing the neighbour entry family, `4` for IPv4
+ ARP or `6` for IPv6 NDP</td>
+</tr>
+<tr>
+ <td>`dev`</td>
+ <td>String containing the associated device of the neighbour entry</td>
+</tr>
+<tr>
+ <td>`dest`</td>
+ <td>IP address `luci.ip.cidr` instance</td>
+</tr>
+<tr>
+ <td>`mac`</td>
+ <td>String containing the associated MAC address</td>
+</tr>
+<tr>
+ <td>`router`</td>
+ <td>Boolean "true" if the neighbour entry is a router (IPv6, optional)</td>
+</tr>
+<tr>
+ <td>`proxy`</td>
+ <td>Boolean "true" if this is a proxy entry (optional)</td>
+</tr>
+<tr>
+ <td>`incomplete`</td>
+ <td>Boolean "true" if the entry is in incomplete state (optional)</td>
+</tr>
+<tr>
+ <td>`reachable`</td>
+ <td>Boolean "true" if the entry is in reachable state (optional)</td>
+</tr>
+<tr>
+ <td>`stale`</td>
+ <td>Boolean "true" if the entry is stale (optional)</td>
+</tr>
+<tr>
+ <td>`delay`</td>
+ <td>Boolean "true" if the entry is delayed (optional)</td>
+</tr>
+<tr>
+ <td>`probe`</td>
+ <td>Boolean "true" if the entry is in probe state (optional)</td>
+</tr>
+<tr>
+ <td>`failed`</td>
+ <td>Boolean "true" if the entry is in failed state (optional)</td>
+</tr>
+<tr>
+ <td>`noarp`</td>
+ <td>Boolean "true" if the entry is not caused by NDP or
+ ARP (optional)</td>
+</tr>
+<tr>
+ <td>`permanent`</td>
+ <td>Boolean "true" if the entry was statically configured from
+ userspace (optional)</td>
+</tr>
+</table>
+@usage <ul>
+<li>Find all ARP neighbours in the LAN:
+`luci.ip.neighbors({ dest = "192.168.0.0/16" }, function(n)
+ print(n.dest, n.mac)
+end)`</li>
+<li>Find all active IPv6 addresses of host with given MAC:
+`luci.ip.neighbors({ family = 6, mac = "00:21:63:75:aa:17" },
+ function(n)
+ print(n.dest)
+ end)`</li>
+</ul>
+]]
+
+---[[
+Fetch basic device information
+@class function
+@sort 7
+@name link
+@param device String containing the network device to query
+@return If the given interface is found, a table containing the fields
+described below is returned, else an empty table.
+
+<table>
+<tr><th>Field</th><th>Description</th></tr>
+<tr>
+ <td>`up`</td>
+ <td>Boolean indicating whether the device is in IFF_RUNNING state</td>
+</tr>
+<tr>
+ <td>`type`</td>
+ <td>Numeric value indicating the type of the device, e.g. `1`
+ for ethernet.</td>
+</tr>
+<tr>
+ <td>`name`</td>
+ <td>String containing the name of the device</td>
+</tr>
+<tr>
+ <td>`master`</td>
+ <td>If queried device is a bridge port, string containing the name of
+ parent bridge device (optional)</td>
+</tr>
+<tr>
+ <td>`mtu`</td>
+ <td>Number containing the current MTU of the device</td>
+</tr>
+<tr>
+ <td>`qlen`</td>
+ <td>Number containing the TX queue length of the device</td>
+</tr>
+<tr>
+ <td>`mac`</td>
+ <td>String containing the link local address of the device in
+ dotted hex notation</td>
+</tr>
+</table>
+@usage <ul>
+<li>Test whether device br-lan exists:
+`print(luci.ip.link("br-lan").name ~= nil)
+`</li>
+<li>Query MAC address of eth0:
+`print(luci.ip.link("eth0").mac)
+`</li>
+</ul>
+]]
+
+
+--- IP CIDR Object.
+-- Represents an IPv4 or IPv6 address range.
+-- @cstyle instance
+module "luci.ip.cidr"
+
+---[[
+Checks whether the CIDR instance is an IPv4 address range
+
+@class function
+@sort 1
+@name cidr.is4
+@see cidr.is6
+@return `true` if the CIDR is an IPv4 range, else `false`
+]]
+
+---[[
+Checks whether the CIDR instance is within the private RFC1918 address space
+
+@class function
+@sort 2
+@name cidr.is4rfc1918
+@return `true` if the entire range of this CIDR lies within one of
+ the ranges `10.0.0.0-10.255.255.255`,
+ `172.16.0.0-172.31.0.0` or
+ `192.168.0.0-192.168.255.255`, else `false`.
+@usage `local addr = luci.ip.new("192.168.45.2/24")
+if addr:is4rfc1918() then
+ print("Is a private address")
+end`
+]]
+
+---[[
+Checks whether the CIDR instance is an IPv4 link local (Zeroconf) address
+
+@class function
+@sort 3
+@name cidr.is4linklocal
+@return `true` if the entire range of this CIDR lies within the range
+ the range `169.254.0.0-169.254.255.255`, else `false`.
+@usage `local addr = luci.ip.new("169.254.34.125")
+if addr:is4linklocal() then
+ print("Is a zeroconf address")
+end`
+]]
+
+---[[
+Checks whether the CIDR instance is an IPv6 address range
+
+@class function
+@sort 4
+@name cidr.is6
+@see cidr.is4
+@return `true` if the CIDR is an IPv6 range, else `false`
+]]
+
+---[[
+Checks whether the CIDR instance is an IPv6 link local address
+
+@class function
+@sort 5
+@name cidr.is6linklocal
+@return `true` if the entire range of this CIDR lies within the range
+ the `fe80::/10` range, else `false`.
+@usage `local addr = luci.ip.new("fe92:53a:3216:af01:221:63ff:fe75:aa17/64")
+if addr:is6linklocal() then
+ print("Is a linklocal address")
+end`
+]]
+
+---[[
+Checks whether the CIDR instance is an IPv6 mapped IPv4 address
+
+@class function
+@sort 6
+@name cidr.is6mapped4
+@return `true` if the address is an IPv6 mapped IPv4 address in the
+ form `::ffff:1.2.3.4`.
+@usage `local addr = luci.ip.new("::ffff:192.168.1.1")
+if addr:is6mapped4() then
+ print("Is a mapped IPv4 address")
+end`
+]]
+
+---[[
+Checks whether this CIDR instance is lower than the given argument.
+The comparisation follows these rules:
+<ul><li>An IPv4 address is always lower than an IPv6 address</li>
+<li>Prefix sizes are ignored</li></ul>
+
+@class function
+@sort 7
+@name cidr.lower
+@param addr A `luci.ip.cidr` instance or a string convertable by
+ `luci.ip.new()` to compare against.
+@return `true` if this CIDR is lower than the given address,
+ else `false`.
+@usage `local addr = luci.ip.new("192.168.1.1")
+print(addr:lower(addr)) -- false
+print(addr:lower("10.10.10.10/24")) -- false
+print(addr:lower(luci.ip.new("::1"))) -- true
+print(addr:lower(luci.ip.new("192.168.200.1"))) -- true`
+@see cidr.higher
+@see cidr.equal
+]]
+
+---[[
+Checks whether this CIDR instance is higher than the given argument.
+The comparisation follows these rules:
+<ul><li>An IPv4 address is always lower than an IPv6 address</li>
+<li>Prefix sizes are ignored</li></ul>
+
+@class function
+@sort 8
+@name cidr.higher
+@param addr A `luci.ip.cidr` instance or a string convertable by
+ `luci.ip.new()` to compare against.
+@return `true` if this CIDR is higher than the given address,
+ else `false`.
+@usage `local addr = luci.ip.new("192.168.1.1")
+print(addr:higher(addr)) -- false
+print(addr:higher("10.10.10.10/24")) -- true
+print(addr:higher(luci.ip.new("::1"))) -- false
+print(addr:higher(luci.ip.new("192.168.200.1"))) -- false`
+@see cidr.lower
+@see cidr.equal
+]]
+
+---[[
+Checks whether this CIDR instance is equal to the given argument.
+
+@class function
+@sort 9
+@name cidr.equal
+@param addr A `luci.ip.cidr` instance or a string convertable by
+ `luci.ip.new()` to compare against.
+@return `true` if this CIDR is equal to the given address,
+ else `false`.
+@usage `local addr = luci.ip.new("192.168.1.1")
+print(addr:equal(addr)) -- true
+print(addr:equal("192.168.1.1")) -- true
+print(addr:equal(luci.ip.new("::1"))) -- false
+
+local addr6 = luci.ip.new("::1")
+print(addr6:equal("0:0:0:0:0:0:0:1/64")) -- true
+print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false`
+@see cidr.lower
+@see cidr.higher
+]]
+
+---[[
+Get or set prefix size of CIDR instance.
+If the optional mask parameter is given, the prefix size of this CIDR is altered
+else the current prefix size is returned.
+
+@class function
+@sort 10
+@name cidr.prefix
+@param mask Either a number containing the number of bits (`0..32`
+ for IPv4, `0..128` for IPv6) or a string containing a valid
+ netmask (optional)
+@return Bit count of the current prefix size
+@usage `local range = luci.ip.new("192.168.1.1/255.255.255.0")
+print(range:prefix()) -- 24
+
+range:prefix(16)
+print(range:prefix()) -- 16
+
+range:prefix("255.255.255.255")
+print(range:prefix()) -- 32`
+]]
+
+---[[
+Derive network address of CIDR instance.
+
+Returns a new CIDR instance representing the network address of this instance
+with all host parts masked out. The used prefix size can be overridden by the
+optional mask parameter.
+
+@class function
+@sort 11
+@name cidr.network
+@param mask Either a number containing the number of bits (`0..32`
+ for IPv4, `0..128` for IPv6) or a string containing a valid
+ netmask (optional)
+@return CIDR instance representing the network address
+@usage `local range = luci.ip.new("192.168.62.243/255.255.0.0")
+print(range:network()) -- "192.168.0.0"
+print(range:network(24)) -- "192.168.62.0"
+print(range:network("255.255.255.0")) -- "192.168.62.0"
+
+local range6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
+print(range6:network()) -- "fd9b:62b3:9cc5::"`
+]]
+
+---[[
+Derive host address of CIDR instance.
+
+This function essentially constructs a copy of this CIDR with the prefix size
+set to `32` for IPv4 and `128` for IPv6.
+
+@class function
+@sort 12
+@name cidr.host
+@return CIDR instance representing the host address
+@usage `local range = luci.ip.new("172.19.37.45/16")
+print(range) -- "172.19.37.45/16"
+print(range:host()) -- "172.19.37.45"`
+]]
+
+---[[
+Derive netmask of CIDR instance.
+
+Constructs a CIDR instance representing the netmask of this instance. The used
+prefix size can be overridden by the optional mask parameter.
+
+@class function
+@sort 13
+@name cidr.mask
+@param mask Either a number containing the number of bits (`0..32`
+ for IPv4, `0..128` for IPv6) or a string containing a valid
+ netmask (optional)
+@return CIDR instance representing the netmask
+@usage `local range = luci.ip.new("172.19.37.45/16")
+print(range:mask()) -- "255.255.0.0"
+print(range:mask(24)) -- "255.255.255.0"
+print(range:mask("255.0.0.0")) -- "255.0.0.0"`
+]]
+
+---[[
+Derive broadcast address of CIDR instance.
+
+Constructs a CIDR instance representing the broadcast address of this instance.
+The used prefix size can be overridden by the optional mask parameter.
+
+This function has no effect on IPv6 instances, it will return nothing in this
+case.
+
+@class function
+@sort 14
+@name cidr.broadcast
+@param mask Either a number containing the number of bits (`0..32`
+ for IPv4, `0..128` for IPv6) or a string containing a valid
+ netmask (optional)
+@return Return a new CIDR instance representing the broadcast address if this
+ instance is an IPv4 range, else return nothing.
+@usage `local range = luci.ip.new("172.19.37.45/16")
+print(range:broadcast()) -- "172.19.255.255"
+print(range:broadcast(24)) -- "172.19.37.255"
+print(range:broadcast("255.0.0.0")) -- "172.255.255.255"`
+]]
+
+---[[
+Derive mapped IPv4 address of CIDR instance.
+
+Constructs a CIDR instance representing the IPv4 address of the IPv6 mapped
+IPv4 address in this instance.
+
+This function has no effect on IPv4 instances or IPv6 instances which are not a
+mapped address, it will return nothing in this case.
+
+@class function
+@sort 15
+@name cidr.mapped4
+@return Return a new CIDR instance representing the IPv4 address if this
+ instance is an IPv6 mapped IPv4 address, else return nothing.
+@usage `local addr = luci.ip.new("::ffff:172.16.19.1")
+print(addr:mapped4()) -- "172.16.19.1"`
+]]
+
+---[[
+Test whether CIDR contains given range.
+
+@class function
+@sort 16
+@name cidr.contains
+@param addr A `luci.ip.cidr` instance or a string convertable by
+ `luci.ip.new()` to test.
+@return `true` if this instance fully contains the given address else
+ `false`.
+@usage `local range = luci.ip.new("10.24.0.0/255.255.0.0")
+print(range:contains("10.24.5.1")) -- true
+print(range:contains("::1")) -- false
+print(range:contains("10.0.0.0/8")) -- false
+
+local range6 = luci.ip.new("fe80::/10")
+print(range6:contains("fe80::221:63f:fe75:aa17/64")) -- true
+print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false`
+]]
+
+---[[
+Add given amount to CIDR instance. If the result would overflow the maximum
+address space, the result is set to the highest possible address.
+
+@class function
+@sort 17
+@name cidr.add
+@param amount A numeric value between 0 and 0xFFFFFFFF, a
+ `luci.ip.cidr` instance or a string convertable by
+ `luci.ip.new()`.
+@param inplace If `true`, modify this instance instead of returning
+ a new derived CIDR instance.
+@return <ul>
+ <li>When adding inplace: Return `true` if the addition succeded
+ or `false` when the addition overflowed.</li>
+ <li>When deriving new CIDR: Return new instance representing the value of
+ this instance plus the added amount or the highest possible address if
+ the addition overflowed the available address space.</li></ul>
+@usage `local addr = luci.ip.new("192.168.1.1/24")
+print(addr:add(250)) -- "192.168.1.251/24"
+print(addr:add("0.0.99.0")) -- "192.168.100.1/24"
+
+addr:add(256, true) -- true
+print(addr) -- "192.168.2.1/24
+
+addr:add("255.0.0.0", true) -- false (overflow)
+print(addr) -- "255.255.255.255/24
+
+local addr6 = luci.ip.new("fe80::221:63f:fe75:aa17/64")
+print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64"
+print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64"
+
+addr:add(256, true) -- true
+print(addr) -- "fe80::221:63f:fe75:ab17/64
+
+addr:add("ffff::", true) -- false (overflow)
+print(addr) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"`
+]]
+
+---[[
+Substract given amount from CIDR instance. If the result would under, the lowest
+possible address is returned.
+
+@class function
+@sort 18
+@name cidr.sub
+@param amount A numeric value between 0 and 0xFFFFFFFF, a
+ `luci.ip.cidr` instance or a string convertable by
+ `luci.ip.new()`.
+@param inplace If `true`, modify this instance instead of returning
+ a new derived CIDR instance.
+@return <ul>
+ <li>When substracting inplace: Return `true` if the substraction
+ succeded or `false` when the substraction underflowed.</li>
+ <li>When deriving new CIDR: Return new instance representing the value of
+ this instance minus the substracted amount or the lowest address if
+ the substraction underflowed.</li></ul>
+@usage `local addr = luci.ip.new("192.168.1.1/24")
+print(addr:sub(256)) -- "192.168.0.1/24"
+print(addr:sub("0.168.0.0")) -- "192.0.1.1/24"
+
+addr:sub(256, true) -- true
+print(addr) -- "192.168.0.1/24
+
+addr:sub("255.0.0.0", true) -- false (underflow)
+print(addr) -- "0.0.0.0/24
+
+local addr6 = luci.ip.new("fe80::221:63f:fe75:aa17/64")
+print(addr6:sub(256)) -- "fe80::221:63f:fe75:a917/64"
+print(addr6:sub("::ffff:0")) -- "fe80::221:63e:fe76:aa17/64"
+
+addr:sub(256, true) -- true
+print(addr) -- "fe80::221:63f:fe75:a917/64"
+
+addr:sub("ffff::", true) -- false (underflow)
+print(addr) -- "::/64"`
+]]
+
+---[[
+Calculate the lowest possible host address within this CIDR instance.
+
+@class function
+@sort 19
+@name cidr.minhost
+@return Returns a new CIDR instance representing the lowest host address
+ within this range.
+@usage `local addr = luci.ip.new("192.168.123.56/24")
+print(addr:minhost()) -- "192.168.123.1"
+
+local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
+print(addr6:minhost()) -- "fd9b:62b3:9cc5::1"`
+]]
+
+---[[
+Calculate the highest possible host address within this CIDR instance.
+
+@class function
+@sort 20
+@name cidr.maxhost
+@return Returns a new CIDR instance representing the highest host address
+ within this range.
+@usage `local addr = luci.ip.new("192.168.123.56/24")
+print(addr:maxhost()) -- "192.168.123.254" (.255 is broadcast)
+
+local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
+print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff"`
+]]
+
+---[[
+Convert CIDR instance into string representation.
+
+If the prefix size of instance is less than 32 for IPv4 or 128 for IPv6, the
+address is returned in the form "address/prefix" otherwise just "address".
+
+It is usually not required to call this function directly as CIDR objects
+define it as __tostring function in the associated metatable.
+
+@class function
+@sort 21
+@name cidr.string
+@return Returns a string representing the range or address of this CIDR instance
+]]
diff --git a/libs/luci-lib-json/luasrc/json.lua b/libs/luci-lib-json/luasrc/json.lua
index 57b12c9405..416b25faa5 100644
--- a/libs/luci-lib-json/luasrc/json.lua
+++ b/libs/luci-lib-json/luasrc/json.lua
@@ -25,14 +25,9 @@ local char = string.char
local getmetatable = getmetatable
---- LuCI JSON-Library
--- @cstyle instance
module "luci.json"
---- Directly decode a JSON string
--- @param json JSON-String
--- @return Lua object
function decode(json, ...)
local a = ActiveDecoder(function() return nil end, ...)
a.chunk = json
@@ -41,9 +36,6 @@ function decode(json, ...)
end
---- Direcly encode a Lua object into a JSON string.
--- @param obj Lua Object
--- @return JSON string
function encode(obj, ...)
local out = {}
local e = Encoder(obj, 1, ...):source()
@@ -56,19 +48,10 @@ function encode(obj, ...)
end
---- Null replacement function
--- @return null
function null()
return null
end
---- Create a new JSON-Encoder.
--- @class function
--- @name Encoder
--- @param data Lua-Object to be encoded.
--- @param buffersize Blocksize of returned data source.
--- @param fastescape Use non-standard escaping (don't escape control chars)
--- @return JSON-Encoder
Encoder = util.class()
function Encoder.__init__(self, data, buffersize, fastescape)
@@ -80,8 +63,6 @@ function Encoder.__init__(self, data, buffersize, fastescape)
getmetatable(self).__call = Encoder.source
end
---- Create an LTN12 source providing the encoded JSON-Data.
--- @return LTN12 source
function Encoder.source(self)
local source = coroutine.create(self.dispatch)
return function()
@@ -208,11 +189,6 @@ Encoder.parsers = {
}
---- Create a new JSON-Decoder.
--- @class function
--- @name Decoder
--- @param customnull Use luci.json.null instead of nil for decoding null
--- @return JSON-Decoder
Decoder = util.class()
function Decoder.__init__(self, customnull)
@@ -220,8 +196,6 @@ function Decoder.__init__(self, customnull)
getmetatable(self).__call = Decoder.sink
end
---- Create an LTN12 sink from the decoder object which accepts the JSON-Data.
--- @return LTN12 sink
function Decoder.sink(self)
local sink = coroutine.create(self.dispatch)
return function(...)
@@ -230,8 +204,6 @@ function Decoder.sink(self)
end
---- Get the decoded data packets after the rawdata has been sent to the sink.
--- @return Decoded data
function Decoder.get(self)
return self.data
end
@@ -526,11 +498,6 @@ Decoder.parsers = {
}
---- Create a new Active JSON-Decoder.
--- @class function
--- @name ActiveDecoder
--- @param customnull Use luci.json.null instead of nil for decoding null
--- @return Active JSON-Decoder
ActiveDecoder = util.class(Decoder)
function ActiveDecoder.__init__(self, source, customnull)
@@ -541,8 +508,6 @@ function ActiveDecoder.__init__(self, source, customnull)
end
---- Fetches one JSON-object from given source
--- @return Decoded object
function ActiveDecoder.get(self)
local chunk, src_err, object
if not self.chunk then
diff --git a/libs/luci-lib-json/luasrc/json.luadoc b/libs/luci-lib-json/luasrc/json.luadoc
new file mode 100644
index 0000000000..d48dba13b9
--- /dev/null
+++ b/libs/luci-lib-json/luasrc/json.luadoc
@@ -0,0 +1,94 @@
+---[[
+LuCI JSON-Library
+
+@cstyle instance
+module "luci.json"
+]]
+
+---[[
+Directly decode a JSON string
+
+@class function
+@name decode
+@param json JSON-String
+@return Lua object
+]]
+
+---[[
+Direcly encode a Lua object into a JSON string.
+
+@class function
+@name encode
+@param obj Lua Object
+@return JSON string
+]]
+
+---[[
+Null replacement function
+
+@class function
+@name null
+@return null
+]]
+
+---[[
+Create a new JSON-Encoder.
+
+@class function
+@name Encoder
+@param data Lua-Object to be encoded.
+@param buffersize Blocksize of returned data source.
+@param fastescape Use non-standard escaping (don't escape control chars)
+@return JSON-Encoder
+]]
+
+---[[
+Create an LTN12 source providing the encoded JSON-Data.
+
+@class function
+@name Encoder.source
+@return LTN12 source
+]]
+
+---[[
+Create a new JSON-Decoder.
+
+@class function
+@name Decoder
+@param customnull Use luci.json.null instead of nil for decoding null
+@return JSON-Decoder
+]]
+
+---[[
+Create an LTN12 sink from the decoder object which accepts the JSON-Data.
+
+@class function
+@name Decoder.sink
+@return LTN12 sink
+]]
+
+---[[
+Get the decoded data packets after the rawdata has been sent to the sink.
+
+@class function
+@name Decoder.get
+@return Decoded data
+]]
+
+---[[
+Create a new Active JSON-Decoder.
+
+@class function
+@name ActiveDecoder
+@param customnull Use luci.json.null instead of nil for decoding null
+@return Active JSON-Decoder
+]]
+
+---[[
+Fetches one JSON-object from given source
+
+@class function
+@name ActiveDecoder.get
+@return Decoded object
+]]
+
diff --git a/libs/luci-lib-jsonc/Makefile b/libs/luci-lib-jsonc/Makefile
new file mode 100644
index 0000000000..6a63dab5ef
--- /dev/null
+++ b/libs/luci-lib-jsonc/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2015 LuCI Team <luci@lists.subsignal.org>
+#
+# This is free software, licensed under the Apache License, Version 2.0 .
+#
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=Lua binding for JSON-C
+LUCI_DEPENDS:=+liblua +libjson-c
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/libs/luci-lib-jsonc/src/Makefile b/libs/luci-lib-jsonc/src/Makefile
new file mode 100644
index 0000000000..e15fbac382
--- /dev/null
+++ b/libs/luci-lib-jsonc/src/Makefile
@@ -0,0 +1,17 @@
+JSONC_CFLAGS = -std=gnu99 -I$(STAGING_DIR)/usr/include/json-c/
+JSONC_LDFLAGS = -llua -lm -ljson-c
+JSONC_OBJ = jsonc.o
+JSONC_LIB = jsonc.so
+
+%.o: %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LUA_CFLAGS) $(JSONC_CFLAGS) $(FPIC) -c -o $@ $<
+
+compile: $(JSONC_OBJ)
+ $(CC) $(LDFLAGS) -shared -o $(JSONC_LIB) $(JSONC_OBJ) $(JSONC_LDFLAGS)
+
+install: compile
+ mkdir -p $(DESTDIR)/usr/lib/lua/luci
+ cp $(JSONC_LIB) $(DESTDIR)/usr/lib/lua/luci/$(JSONC_LIB)
+
+clean:
+ rm -f *.o *.so
diff --git a/libs/luci-lib-jsonc/src/jsonc.c b/libs/luci-lib-jsonc/src/jsonc.c
new file mode 100644
index 0000000000..49cb21f5bc
--- /dev/null
+++ b/libs/luci-lib-jsonc/src/jsonc.c
@@ -0,0 +1,388 @@
+/*
+Copyright 2015 Jo-Philipp Wich <jow@openwrt.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
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#define _GNU_SOURCE
+
+#include <math.h>
+#include <stdbool.h>
+#include <json-c/json.h>
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#define LUCI_JSONC "luci.jsonc"
+#define LUCI_JSONC_PARSER "luci.jsonc.parser"
+
+struct json_state {
+ struct json_object *obj;
+ struct json_tokener *tok;
+ enum json_tokener_error err;
+};
+
+static void _json_to_lua(lua_State *L, struct json_object *obj);
+static struct json_object * _lua_to_json(lua_State *L, int index);
+
+static int json_new(lua_State *L)
+{
+ struct json_state *s;
+ struct json_tokener *tok = json_tokener_new();
+
+ if (!tok)
+ return 0;
+
+ s = lua_newuserdata(L, sizeof(*s));
+
+ if (!s)
+ {
+ json_tokener_free(tok);
+ return 0;
+ }
+
+ s->tok = tok;
+ s->obj = NULL;
+ s->err = json_tokener_continue;
+
+ luaL_getmetatable(L, LUCI_JSONC_PARSER);
+ lua_setmetatable(L, -2);
+
+ return 1;
+}
+
+static int json_parse(lua_State *L)
+{
+ size_t len;
+ const char *json = luaL_checklstring(L, 1, &len);
+ struct json_state s = {
+ .tok = json_tokener_new()
+ };
+
+ if (!s.tok)
+ return 0;
+
+ s.obj = json_tokener_parse_ex(s.tok, json, len);
+ s.err = json_tokener_get_error(s.tok);
+
+ if (s.obj)
+ {
+ _json_to_lua(L, s.obj);
+ json_object_put(s.obj);
+ }
+ else
+ {
+ lua_pushnil(L);
+ }
+
+ if (s.err == json_tokener_continue)
+ s.err = json_tokener_error_parse_eof;
+
+ if (s.err)
+ lua_pushstring(L, json_tokener_error_desc(s.err));
+
+ json_tokener_free(s.tok);
+ return (1 + !!s.err);
+}
+
+static int json_stringify(lua_State *L)
+{
+ struct json_object *obj = _lua_to_json(L, 1);
+ bool pretty = lua_toboolean(L, 2);
+ int flags = 0;
+
+ if (pretty)
+ flags |= JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED;
+
+ lua_pushstring(L, json_object_to_json_string_ext(obj, flags));
+ return 1;
+}
+
+
+static int json_parse_chunk(lua_State *L)
+{
+ size_t len;
+ struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
+ const char *chunk = luaL_checklstring(L, 2, &len);
+
+ s->obj = json_tokener_parse_ex(s->tok, chunk, len);
+ s->err = json_tokener_get_error(s->tok);
+
+ if (!s->err)
+ {
+ lua_pushboolean(L, true);
+ return 1;
+ }
+ else if (s->err == json_tokener_continue)
+ {
+ lua_pushboolean(L, false);
+ return 1;
+ }
+
+ lua_pushnil(L);
+ lua_pushstring(L, json_tokener_error_desc(s->err));
+ return 2;
+}
+
+static void _json_to_lua(lua_State *L, struct json_object *obj)
+{
+ int n;
+
+ switch (json_object_get_type(obj))
+ {
+ case json_type_object:
+ lua_newtable(L);
+ json_object_object_foreach(obj, key, val)
+ {
+ _json_to_lua(L, val);
+ lua_setfield(L, -2, key);
+ }
+ break;
+
+ case json_type_array:
+ lua_newtable(L);
+ for (n = 0; n < json_object_array_length(obj); n++)
+ {
+ _json_to_lua(L, json_object_array_get_idx(obj, n));
+ lua_rawseti(L, -2, n + 1);
+ }
+ break;
+
+ case json_type_boolean:
+ lua_pushboolean(L, json_object_get_boolean(obj));
+ break;
+
+ case json_type_int:
+ lua_pushinteger(L, json_object_get_int(obj));
+ break;
+
+ case json_type_double:
+ lua_pushnumber(L, json_object_get_double(obj));
+ break;
+
+ case json_type_string:
+ lua_pushstring(L, json_object_get_string(obj));
+ break;
+
+ case json_type_null:
+ lua_pushnil(L);
+ break;
+ }
+}
+
+static int json_parse_get(lua_State *L)
+{
+ struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
+
+ if (!s->obj || s->err)
+ lua_pushnil(L);
+ else
+ _json_to_lua(L, s->obj);
+
+ return 1;
+}
+
+static int _lua_test_array(lua_State *L, int index)
+{
+ int max = 0;
+ lua_Number idx;
+
+ lua_pushnil(L);
+
+ /* check for non-integer keys */
+ while (lua_next(L, index))
+ {
+ if (lua_type(L, -2) != LUA_TNUMBER)
+ goto out;
+
+ idx = lua_tonumber(L, -2);
+
+ if (idx != (lua_Number)(lua_Integer)idx)
+ goto out;
+
+ if (idx <= 0)
+ goto out;
+
+ if (idx > max)
+ max = idx;
+
+ lua_pop(L, 1);
+ continue;
+
+out:
+ lua_pop(L, 2);
+ return 0;
+ }
+
+ /* check for holes */
+ //for (i = 1; i <= max; i++)
+ //{
+ // lua_rawgeti(L, index, i);
+ //
+ // if (lua_isnil(L, -1))
+ // {
+ // lua_pop(L, 1);
+ // return 0;
+ // }
+ //
+ // lua_pop(L, 1);
+ //}
+
+ return max;
+}
+
+static struct json_object * _lua_to_json(lua_State *L, int index)
+{
+ lua_Number nd, ni;
+ struct json_object *obj;
+ const char *key;
+ int i, max;
+
+ switch (lua_type(L, index))
+ {
+ case LUA_TTABLE:
+ max = _lua_test_array(L, index);
+
+ if (max > 0)
+ {
+ obj = json_object_new_array();
+
+ if (!obj)
+ return NULL;
+
+ for (i = 1; i <= max; i++)
+ {
+ lua_rawgeti(L, index, i);
+
+ json_object_array_put_idx(obj, i - 1,
+ _lua_to_json(L, lua_gettop(L)));
+
+ lua_pop(L, 1);
+ }
+
+ return obj;
+ }
+
+ obj = json_object_new_object();
+
+ if (!obj)
+ return NULL;
+
+ lua_pushnil(L);
+
+ while (lua_next(L, index))
+ {
+ lua_pushvalue(L, -2);
+ key = lua_tostring(L, -1);
+
+ json_object_object_add(obj, key,
+ _lua_to_json(L, lua_gettop(L) - 1));
+
+ lua_pop(L, 2);
+ }
+
+ return obj;
+
+ case LUA_TNIL:
+ return NULL;
+
+ case LUA_TBOOLEAN:
+ return json_object_new_boolean(lua_toboolean(L, index));
+
+ case LUA_TNUMBER:
+ nd = lua_tonumber(L, index);
+ ni = lua_tointeger(L, index);
+
+ if (nd == ni)
+ return json_object_new_int(nd);
+
+ return json_object_new_double(nd);
+
+ case LUA_TSTRING:
+ return json_object_new_string(lua_tostring(L, index));
+ }
+
+ return NULL;
+}
+
+static int json_parse_set(lua_State *L)
+{
+ struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
+
+ s->err = 0;
+ s->obj = _lua_to_json(L, 2);
+
+ return 0;
+}
+
+static int json_tostring(lua_State *L)
+{
+ struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
+ bool pretty = lua_toboolean(L, 2);
+ int flags = 0;
+
+ if (pretty)
+ flags |= JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED;
+
+ lua_pushstring(L, json_object_to_json_string_ext(s->obj, flags));
+ return 1;
+}
+
+static int json_gc(lua_State *L)
+{
+ struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
+
+ if (s->obj)
+ json_object_put(s->obj);
+
+ if (s->tok)
+ json_tokener_free(s->tok);
+
+ return 0;
+}
+
+
+static const luaL_reg jsonc_methods[] = {
+ { "new", json_new },
+ { "parse", json_parse },
+ { "stringify", json_stringify },
+
+ { }
+};
+
+static const luaL_reg jsonc_parser_methods[] = {
+ { "parse", json_parse_chunk },
+ { "get", json_parse_get },
+ { "set", json_parse_set },
+ { "stringify", json_tostring },
+
+ { "__gc", json_gc },
+ { "__tostring", json_tostring },
+
+ { }
+};
+
+
+int luaopen_luci_jsonc(lua_State *L)
+{
+ luaL_register(L, LUCI_JSONC, jsonc_methods);
+
+ luaL_newmetatable(L, LUCI_JSONC_PARSER);
+ luaL_register(L, NULL, jsonc_parser_methods);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ lua_pop(L, 1);
+
+ return 1;
+}
diff --git a/libs/luci-lib-jsonc/src/jsonc.luadoc b/libs/luci-lib-jsonc/src/jsonc.luadoc
new file mode 100644
index 0000000000..2ee9cebdc8
--- /dev/null
+++ b/libs/luci-lib-jsonc/src/jsonc.luadoc
@@ -0,0 +1,134 @@
+--- LuCI JSON parsing and serialization library.
+-- The luci.jsonc class is a high level Lua binding to the JSON-C library to
+-- allow reading and writing JSON data with minimal overhead.
+module "luci.jsonc"
+
+---[[
+Construct a new luci.jsonc.parser instance.
+@class function
+@sort 1
+@name new
+@return A `luci.jsonc.parser` object representing a JSON-C tokener.
+@usage `parser = luci.jsonc.new()`
+]]
+
+---[[
+Parse a complete JSON string and convert it into a Lua data structure.
+@class function
+@sort 2
+@name parse
+@param json A string containing the JSON data to parse, must be either a
+ JSON array or a JSON object.
+@return On success, a table containing the parsed JSON data is returned, on
+ failure the function returns `nil` and a string containing the reason of
+ the parse error.
+@usage `data = luci.jsonc.parse('{ "name": "John", "age": 34 }')
+print(data.name) -- "John"`
+@see stringify
+]]
+
+---[[
+Convert given Lua data into a JSON string.
+
+This function recursively converts the given Lua data into a JSON string,
+ignoring any unsupported data. Lua tables are converted into JSON arrays if they
+only contain integer keys, mixed tables are turned into JSON objects with any
+existing numeric keys converted into strings.
+
+Lua functions, coroutines and userdata objects are ignored and Lua numbers are
+converted to integers if they do not contain fractional values.
+
+@class function
+@sort 3
+@name stringify
+@param data The Lua data to convert, can be a table, string, boolean or number.
+@param pretty A boolean value indicating whether the resulting JSON should be
+ pretty printed.
+@return Returns a string containing the JSON representation of the given Lua
+ data.
+@usage `json = luci.jsonc.stringify({ item = true, values = { 1, 2, 3 } })
+print(json) -- '{"item":true,"values":[1,2,3]}'`
+@see parse
+]]
+
+
+--- LuCI JSON parser instance.
+-- A JSON parser instance is useful to parse JSON data chunk by chunk, without
+-- the need to assemble all data in advance.
+-- @cstyle instance
+module "luci.jsonc.parser"
+
+---[[
+Parses one chunk of JSON data.
+
+@class function
+@sort 1
+@name parser.parse
+@see parser.get
+@param json String containing the JSON fragment to parse
+@return <ul>
+ <li>`true` if a complete JSON object has been parsed and no further input is
+ expected.</li>
+ <li>`false` if further input is required</li>
+ <li>`nil` if an error was encountered while parsing the current chunk.
+ In this case a string describing the parse error is returned as second
+ value.</li></ul>
+@usage `parser = luci.jsonc.new()
+
+while true do
+ chunk = ... -- fetch a cunk of data, e.g. from a socket
+ finish, errmsg = <b>parser.parse(chunk)</b>
+
+ if finish == nil then
+ error("Cannot parse JSON: " .. errmsg)
+ end
+
+ if finish == true then
+ break
+ end
+end`
+]]
+
+---[[
+Convert parsed JSON data into Lua table.
+
+@class function
+@sort 2
+@name parser.get
+@see parser.parse
+@return Parsed JSON object converted into a Lua table or `nil` if the parser
+ didn't finish or encountered an error.
+@usage `parser = luci.jsonc.new()
+parser:parse('{ "example": "test" }')
+
+data = parser:get()
+print(data.example) -- "test"`
+]]
+
+---[[
+Put Lua data into the parser.
+
+@class function
+@sort 3
+@name parser.set
+@see parser.stringify
+@param data Lua data to put into the parser object. The data is converted to an
+ internal JSON representation that can be dumped with `stringify()`.
+ The conversion follows the rules described in `luci.jsonc.stringify`.
+@return Nothing is returned.
+@usage `parser = luci.jsonc.new()
+parser:set({ "some", "data" })`
+]]
+
+---[[
+Serialize current parser state as JSON.
+
+@class function
+@sort 4
+@name parser.stringify
+@param pretty A boolean value indicating whether the resulting JSON should be pretty printed.
+@return Returns the serialized JSON data of this parser instance.
+@usage `parser = luci.jsonc.new()
+parser:parse('{ "example": "test" }')
+print(parser:serialize()) -- '{"example":"test"}'`
+]]
diff --git a/libs/luci-lib-nixio/docsrc/CHANGELOG.lua b/libs/luci-lib-nixio/docsrc/CHANGELOG.lua
index fb1cf160b6..aa31841402 100644
--- a/libs/luci-lib-nixio/docsrc/CHANGELOG.lua
+++ b/libs/luci-lib-nixio/docsrc/CHANGELOG.lua
@@ -1,5 +1,5 @@
--- Changes and improvements.
-module "CHANGELOG"
+module "nixio.CHANGELOG"
--- Service Release.
-- <ul>
@@ -26,4 +26,4 @@ module "CHANGELOG"
-- </ul>
-- @class table
-- @name 0.2
--- @return ! \ No newline at end of file
+-- @return !
diff --git a/libs/luci-lib-nixio/docsrc/README.lua b/libs/luci-lib-nixio/docsrc/README.lua
index b957a69903..ee3e3a216c 100644
--- a/libs/luci-lib-nixio/docsrc/README.lua
+++ b/libs/luci-lib-nixio/docsrc/README.lua
@@ -1,5 +1,5 @@
--- General Information.
-module "README"
+module "nixio.README"
--- General error handling information.
-- <ul>
@@ -92,4 +92,4 @@ module "README"
-- @usage Tes
-- @class table
-- @name TLS-Crypto
--- @return ! \ No newline at end of file
+-- @return !
diff --git a/libs/luci-lib-nixio/src/Makefile b/libs/luci-lib-nixio/src/Makefile
index aaa4292bd9..a7e9a77d99 100644
--- a/libs/luci-lib-nixio/src/Makefile
+++ b/libs/luci-lib-nixio/src/Makefile
@@ -1,4 +1,4 @@
-OS = $(shell uname)
+OS = Linux
AXTLS_VERSION = 1.2.1
AXTLS_DIR = axTLS
AXTLS_FILE = $(AXTLS_DIR)-$(AXTLS_VERSION).tar.gz
diff --git a/libs/luci-lib-rpcc/luasrc/rpcc.lua b/libs/luci-lib-rpcc/luasrc/rpcc.lua
index fc52b7eb07..5558910bf1 100644
--- a/libs/luci-lib-rpcc/luasrc/rpcc.lua
+++ b/libs/luci-lib-rpcc/luasrc/rpcc.lua
@@ -9,17 +9,10 @@ local nixio = require "nixio", require "nixio.util"
local tostring, assert, setmetatable = tostring, assert, setmetatable
local error = error
---- LuCI RPC Client.
--- @cstyle instance
module "luci.rpcc"
RQLIMIT = 32 * nixio.const.buffersize
---- Create a new JSON-RPC stream client.
--- @class function
--- @param fd File descriptor
--- @param v1 Use protocol version 1.0
--- @return RPC Client
Client = util.class()
function Client.__init__(self, fd, v1)
@@ -29,11 +22,6 @@ function Client.__init__(self, fd, v1)
self.v1 = v1
end
---- Request an RP call and get the response.
--- @param method Remote method
--- @param params Parameters
--- @param notification Notification only?
--- @return response
function Client.request(self, method, params, notification)
local oldchunk = self.decoder and self.decoder.chunk
self.decoder = json.ActiveDecoder(self.fd:blocksource(nil, RQLIMIT))
@@ -58,9 +46,6 @@ function Client.request(self, method, params, notification)
end
end
---- Create a transparent RPC proxy.
--- @param prefix Method prefix
--- @return RPC Proxy object
function Client.proxy(self, prefix)
prefix = prefix or ""
return setmetatable({}, {
diff --git a/libs/luci-lib-rpcc/luasrc/rpcc.luadoc b/libs/luci-lib-rpcc/luasrc/rpcc.luadoc
new file mode 100644
index 0000000000..8c90ab5247
--- /dev/null
+++ b/libs/luci-lib-rpcc/luasrc/rpcc.luadoc
@@ -0,0 +1,36 @@
+---[[
+LuCI RPC Client.
+
+@cstyle instance
+module "luci.rpcc"
+]]
+
+---[[
+Create a new JSON-RPC stream client.
+
+@class function
+@param fd File descriptor
+@param v1 Use protocol version 1.0
+@return RPC Client
+]]
+
+---[[
+Request an RP call and get the response.
+
+@class function
+@name Client.request
+@param method Remote method
+@param params Parameters
+@param notification Notification only?
+@return response
+]]
+
+---[[
+Create a transparent RPC proxy.
+
+@class function
+@name Client.proxy
+@param prefix Method prefix
+@return RPC Proxy object
+]]
+
diff --git a/libs/luci-lib-rpcc/luasrc/rpcc/ruci.lua b/libs/luci-lib-rpcc/luasrc/rpcc/ruci.lua
index 666d58585f..275c396992 100644
--- a/libs/luci-lib-rpcc/luasrc/rpcc/ruci.lua
+++ b/libs/luci-lib-rpcc/luasrc/rpcc/ruci.lua
@@ -5,16 +5,11 @@ local util = require "luci.util"
local rawget, setmetatable = rawget, setmetatable
local ipairs = ipairs
---- Transparent UCI over RPC client.
--- @cstyle instance
module "luci.rpcc.ruci"
local Proxy = util.class()
---- Create a new UCI over RPC proxy.
--- @param rpccl RPC client
--- @return Network transparent UCI module
function factory(rpccl)
return {
cursor = function(...)
diff --git a/libs/luci-lib-rpcc/luasrc/rpcc/ruci.luadoc b/libs/luci-lib-rpcc/luasrc/rpcc/ruci.luadoc
new file mode 100644
index 0000000000..980ef46d97
--- /dev/null
+++ b/libs/luci-lib-rpcc/luasrc/rpcc/ruci.luadoc
@@ -0,0 +1,16 @@
+---[[
+Transparent UCI over RPC client.
+
+@cstyle instance
+module "luci.rpcc.ruci"
+]]
+
+---[[
+Create a new UCI over RPC proxy.
+
+@class function
+@name factory
+@param rpccl RPC client
+@return Network transparent UCI module
+]]
+
diff --git a/luci.mk b/luci.mk
index 0aba5c5ae6..ab09f0f4f5 100644
--- a/luci.mk
+++ b/luci.mk
@@ -147,6 +147,7 @@ define Package/$(PKG_NAME)/install
if [ -d $(PKG_BUILD_DIR)/luasrc ]; then \
$(INSTALL_DIR) $(1)$(LUCI_LIBRARYDIR); \
cp -pR $(PKG_BUILD_DIR)/luasrc/* $(1)$(LUCI_LIBRARYDIR)/; \
+ $(FIND) $(1)$(LUCI_LIBRARYDIR)/ -type f -name '*.luadoc' | $(XARGS) rm; \
$(if $(CONFIG_LUCI_SRCDIET),$(call SrcDiet,$(1)$(LUCI_LIBRARYDIR)/),true); \
else true; fi
if [ -d $(PKG_BUILD_DIR)/htdocs ]; then \
diff --git a/modules/luci-base/Makefile b/modules/luci-base/Makefile
index 8337fea711..80bbda107a 100644
--- a/modules/luci-base/Makefile
+++ b/modules/luci-base/Makefile
@@ -12,7 +12,7 @@ LUCI_TYPE:=mod
LUCI_BASENAME:=base
LUCI_TITLE:=LuCI core libraries
-LUCI_DEPENDS:=+lua +libuci-lua +luci-lib-nixio +rpcd
+LUCI_DEPENDS:=+lua +libuci-lua +luci-lib-nixio +luci-lib-ip +rpcd
PKG_SOURCE:=LuaSrcDiet-0.12.1.tar.bz2
PKG_SOURCE_URL:=https://luasrcdiet.googlecode.com/files
diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua
index 155d31b10f..795b62bedb 100644
--- a/modules/luci-base/luasrc/dispatcher.lua
+++ b/modules/luci-base/luasrc/dispatcher.lua
@@ -1,7 +1,6 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
---- LuCI web dispatcher.
local fs = require "nixio.fs"
local sys = require "luci.sys"
local util = require "luci.util"
@@ -23,9 +22,6 @@ local index = nil
local fi
---- Build the URL relative to the server webroot from given virtual path.
--- @param ... Virtual path
--- @return Relative URL
function build_url(...)
local path = {...}
local url = { http.getenv("SCRIPT_NAME") or "" }
@@ -49,9 +45,6 @@ function build_url(...)
return table.concat(url, "")
end
---- Check whether a dispatch node shall be visible
--- @param node Dispatch node
--- @return Boolean indicating whether the node should be visible
function node_visible(node)
if node then
return not (
@@ -64,9 +57,6 @@ function node_visible(node)
return false
end
---- Return a sorted table of visible childs within a given node
--- @param node Dispatch node
--- @return Ordered table of child node names
function node_childs(node)
local rv = { }
if node then
@@ -86,9 +76,6 @@ function node_childs(node)
end
---- Send a 404 error code and render the "error404" template if available.
--- @param message Custom error message (optional)
--- @return false
function error404(message)
http.status(404, "Not Found")
message = message or "Not Found"
@@ -101,9 +88,6 @@ function error404(message)
return false
end
---- Send a 500 error code and render the "error500" template if available.
--- @param message Custom error message (optional)#
--- @return false
function error500(message)
util.perror(message)
if not context.template_header_sent then
@@ -128,16 +112,22 @@ function authenticator.htmlauth(validator, accs, default)
return user
end
- require("luci.i18n")
- require("luci.template")
- context.path = {}
- luci.template.render("sysauth", {duser=default, fuser=user})
+ if context.urltoken.stok then
+ context.urltoken.stok = nil
+ http.header("Set-Cookie", "sysauth=; path="..build_url())
+ http.redirect(build_url())
+ else
+ require("luci.i18n")
+ require("luci.template")
+ context.path = {}
+ http.status(403, "Forbidden")
+ luci.template.render("sysauth", {duser=default, fuser=user})
+ end
+
return false
end
---- Dispatch an HTTP request.
--- @param request LuCI HTTP Request object
function httpdispatch(request, prefix)
http.context.request = request
@@ -176,8 +166,6 @@ function httpdispatch(request, prefix)
--context._disable_memtrace()
end
---- Dispatches a LuCI virtual path.
--- @param request Virtual path
function dispatch(request)
--context._disable_memtrace = require "luci.debug".trap_memtrace("l")
local ctx = context
@@ -340,7 +328,6 @@ function dispatch(request)
if not util.contains(accs, user) then
if authen then
- ctx.urltoken.stok = nil
local user, sess = authen(sys.user.checkpasswd, accs, def)
if not user or not util.contains(accs, user) then
return
@@ -364,6 +351,7 @@ function dispatch(request)
if sess then
http.header("Set-Cookie", "sysauth=" .. sess.."; path="..build_url())
+ http.redirect(build_url(unpack(ctx.requestpath)))
ctx.authsession = sess
ctx.authuser = user
end
@@ -445,7 +433,6 @@ function dispatch(request)
end
end
---- Generate the dispatching index using the native file-cache based strategy.
function createindex()
local controllers = { }
local base = "%s/controller/" % util.libpath()
@@ -509,7 +496,6 @@ function createindex()
end
end
---- Create the dispatching tree from the index.
-- Build the index before if it does not exist yet.
function createtree()
if not index then
@@ -548,9 +534,6 @@ function createtree()
return tree
end
---- Register a tree modifier.
--- @param func Modifier function
--- @param order Modifier order value (optional)
function modifier(func, order)
context.modifiers[#context.modifiers+1] = {
func = func,
@@ -560,12 +543,6 @@ function modifier(func, order)
}
end
---- Clone a node of the dispatching tree to another position.
--- @param path Virtual path destination
--- @param clone Virtual path source
--- @param title Destination node title (optional)
--- @param order Destination node order value (optional)
--- @return Dispatching tree node
function assign(path, clone, title, order)
local obj = node(unpack(path))
obj.nodes = nil
@@ -579,12 +556,6 @@ function assign(path, clone, title, order)
return obj
end
---- Create a new dispatching node and define common parameters.
--- @param path Virtual path
--- @param target Target function to call when dispatched.
--- @param title Destination node title
--- @param order Destination node order value (optional)
--- @return Dispatching tree node
function entry(path, target, title, order)
local c = node(unpack(path))
@@ -596,17 +567,11 @@ function entry(path, target, title, order)
return c
end
---- Fetch or create a dispatching node without setting the target module or
-- enabling the node.
--- @param ... Virtual path
--- @return Dispatching tree node
function get(...)
return _create_node({...})
end
---- Fetch or create a new dispatching node.
--- @param ... Virtual path
--- @return Dispatching tree node
function node(...)
local c = _create_node({...})
@@ -666,13 +631,10 @@ function _firstchild()
dispatch(path)
end
---- Alias the first (lowest order) page automatically
function firstchild()
return { type = "firstchild", target = _firstchild }
end
---- Create a redirect to another dispatching node.
--- @param ... Virtual path destination
function alias(...)
local req = {...}
return function(...)
@@ -684,9 +646,6 @@ function alias(...)
end
end
---- Rewrite the first x path values of the request.
--- @param n Number of path values to replace
--- @param ... Virtual path to replace removed path values with
function rewrite(n, ...)
local req = {...}
return function(...)
@@ -725,9 +684,6 @@ local function _call(self, ...)
end
end
---- Create a function-call dispatching target.
--- @param name Target function of local controller
--- @param ... Additional parameters passed to the function
function call(name, ...)
return {type = "call", argv = {...}, name = name, target = _call}
end
@@ -737,8 +693,6 @@ local _template = function(self, ...)
require "luci.template".render(self.view)
end
---- Create a template render dispatching target.
--- @param name Template to be rendered
function template(name)
return {type = "template", view = name, target = _template}
end
@@ -844,8 +798,6 @@ local function _cbi(self, ...)
end
end
---- Create a CBI model dispatching target.
--- @param model CBI model to be rendered
function cbi(model, config)
return {type = "cbi", config = config, model = model, target = _cbi}
end
@@ -858,9 +810,6 @@ local function _arcombine(self, ...)
target:target(unpack(argv))
end
---- Create a combined dispatching target for non argv and argv requests.
--- @param trg1 Overview Target
--- @param trg2 Detail Target
function arcombine(trg1, trg2)
return {type = "arcombine", env = getfenv(), target = _arcombine, targets = {trg1, trg2}}
end
@@ -889,19 +838,12 @@ local function _form(self, ...)
tpl.render("footer")
end
---- Create a CBI form model dispatching target.
--- @param model CBI form model tpo be rendered
function form(model)
return {type = "cbi", model = model, target = _form}
end
---- Access the luci.i18n translate() api.
--- @class function
--- @name translate
--- @param text Text to translate
translate = i18n.translate
---- No-op function used to mark translation entries for menu labels.
-- This function does not actually translate the given argument but
-- is used by build/i18n-scan.pl to find translatable entries.
function _(text)
diff --git a/modules/luci-base/luasrc/dispatcher.luadoc b/modules/luci-base/luasrc/dispatcher.luadoc
new file mode 100644
index 0000000000..743463c74f
--- /dev/null
+++ b/modules/luci-base/luasrc/dispatcher.luadoc
@@ -0,0 +1,220 @@
+---[[
+LuCI web dispatcher.
+]]
+module "luci.dispatcher"
+
+---[[
+Build the URL relative to the server webroot from given virtual path.
+
+@class function
+@name build_url
+@param ... Virtual path
+@return Relative URL
+]]
+
+---[[
+Check whether a dispatch node shall be visible
+
+@class function
+@name node_visible
+@param node Dispatch node
+@return Boolean indicating whether the node should be visible
+]]
+
+---[[
+Return a sorted table of visible childs within a given node
+
+@class function
+@name node_childs
+@param node Dispatch node
+@return Ordered table of child node names
+]]
+
+---[[
+Send a 404 error code and render the "error404" template if available.
+
+@class function
+@name error404
+@param message Custom error message (optional)
+@return false
+]]
+
+---[[
+Send a 500 error code and render the "error500" template if available.
+
+@class function
+@name error500
+@param message Custom error message (optional)#
+@return false
+]]
+
+---[[
+Dispatch an HTTP request.
+
+@class function
+@name httpdispatch
+@param request LuCI HTTP Request object
+]]
+
+---[[
+Dispatches a LuCI virtual path.
+
+@class function
+@name dispatch
+@param request Virtual path
+]]
+
+---[[
+Generate the dispatching index using the native file-cache based strategy.
+
+
+@class function
+@name createindex
+]]
+
+---[[
+Create the dispatching tree from the index.
+
+Build the index before if it does not exist yet.
+
+@class function
+@name createtree
+]]
+
+---[[
+Register a tree modifier.
+
+@class function
+@name modifier
+@param func Modifier function
+@param order Modifier order value (optional)
+]]
+
+---[[
+Clone a node of the dispatching tree to another position.
+
+@class function
+@name assign
+@param path Virtual path destination
+@param clone Virtual path source
+@param title Destination node title (optional)
+@param order Destination node order value (optional)
+@return Dispatching tree node
+]]
+
+---[[
+Create a new dispatching node and define common parameters.
+
+@class function
+@name entry
+@param path Virtual path
+@param target Target function to call when dispatched.
+@param title Destination node title
+@param order Destination node order value (optional)
+@return Dispatching tree node
+]]
+
+---[[
+Fetch or create a dispatching node without setting the target module or
+
+enabling the node.
+@class function
+@name get
+@param ... Virtual path
+@return Dispatching tree node
+]]
+
+---[[
+Fetch or create a new dispatching node.
+
+@class function
+@name node
+@param ... Virtual path
+@return Dispatching tree node
+]]
+
+---[[
+Alias the first (lowest order) page automatically
+
+
+@class function
+@name firstchild
+]]
+
+---[[
+Create a redirect to another dispatching node.
+
+@class function
+@name alias
+@param ... Virtual path destination
+]]
+
+---[[
+Rewrite the first x path values of the request.
+
+@class function
+@name rewrite
+@param n Number of path values to replace
+@param ... Virtual path to replace removed path values with
+]]
+
+---[[
+Create a function-call dispatching target.
+
+@class function
+@name call
+@param name Target function of local controller
+@param ... Additional parameters passed to the function
+]]
+
+---[[
+Create a template render dispatching target.
+
+@class function
+@name template
+@param name Template to be rendered
+]]
+
+---[[
+Create a CBI model dispatching target.
+
+@class function
+@name cbi
+@param model CBI model to be rendered
+]]
+
+---[[
+Create a combined dispatching target for non argv and argv requests.
+
+@class function
+@name arcombine
+@param trg1 Overview Target
+@param trg2 Detail Target
+]]
+
+---[[
+Create a CBI form model dispatching target.
+
+@class function
+@name form
+@param model CBI form model tpo be rendered
+]]
+
+---[[
+Access the luci.i18n translate() api.
+
+@class function
+@name translate
+@param text Text to translate
+]]
+
+---[[
+No-op function used to mark translation entries for menu labels.
+
+This function does not actually translate the given argument but
+is used by build/i18n-scan.pl to find translatable entries.
+
+@class function
+@name _
+]]
+
diff --git a/modules/luci-base/luasrc/http.lua b/modules/luci-base/luasrc/http.lua
index a5329e51d6..a92d8affb6 100644
--- a/modules/luci-base/luasrc/http.lua
+++ b/modules/luci-base/luasrc/http.lua
@@ -11,7 +11,6 @@ local table = require "table"
local ipairs, pairs, next, type, tostring, error =
ipairs, pairs, next, type, tostring, error
---- LuCI Web Framework high-level HTTP functions.
module "luci.http"
context = util.threadlocal()
@@ -101,7 +100,6 @@ function Request._parse_input(self)
self.parsed_input = true
end
---- Close the HTTP-Connection.
function close()
if not context.eoh then
context.eoh = true
@@ -114,52 +112,31 @@ function close()
end
end
---- Return the request content if the request was of unknown type.
--- @return HTTP request body
--- @return HTTP request body length
function content()
return context.request:content()
end
---- Get a certain HTTP input value or a table of all input values.
--- @param name Name of the GET or POST variable to fetch
--- @param noparse Don't parse POST data before getting the value
--- @return HTTP input value or table of all input value
function formvalue(name, noparse)
return context.request:formvalue(name, noparse)
end
---- Get a table of all HTTP input values with a certain prefix.
--- @param prefix Prefix
--- @return Table of all HTTP input values with given prefix
function formvaluetable(prefix)
return context.request:formvaluetable(prefix)
end
---- Get the value of a certain HTTP-Cookie.
--- @param name Cookie Name
--- @return String containing cookie data
function getcookie(name)
return context.request:getcookie(name)
end
---- Get the value of a certain HTTP environment variable
-- or the environment table itself.
--- @param name Environment variable
--- @return HTTP environment value or environment table
function getenv(name)
return context.request:getenv(name)
end
---- Set a handler function for incoming user file uploads.
--- @param callback Handler function
function setfilehandler(callback)
return context.request:setfilehandler(callback)
end
---- Send a HTTP-Header.
--- @param key Header key
--- @param value Header value
function header(key, value)
if not context.headers then
context.headers = {}
@@ -168,8 +145,6 @@ function header(key, value)
coroutine.yield(2, key, value)
end
---- Set the mime type of following content data.
--- @param mime Mimetype of following content
function prepare_content(mime)
if not context.headers or not context.headers["content-type"] then
if mime == "application/xhtml+xml" then
@@ -183,15 +158,10 @@ function prepare_content(mime)
end
end
---- Get the RAW HTTP input source
--- @return HTTP LTN12 source
function source()
return context.request.input
end
---- Set the HTTP status code and status message.
--- @param code Status code
--- @param message Status message
function status(code, message)
code = code or 200
message = message or "OK"
@@ -199,12 +169,8 @@ function status(code, message)
coroutine.yield(1, code, message)
end
---- Send a chunk of content data to the client.
-- This function is as a valid LTN12 sink.
-- If the content chunk is nil this function will automatically invoke close.
--- @param content Content chunk
--- @param src_err Error object from source (optional)
--- @see close
function write(content, src_err)
if not content then
if src_err then
@@ -237,24 +203,16 @@ function write(content, src_err)
end
end
---- Splice data from a filedescriptor to the client.
--- @param fp File descriptor
--- @param size Bytes to splice (optional)
function splice(fd, size)
coroutine.yield(6, fd, size)
end
---- Redirects the client to a new URL and closes the connection.
--- @param url Target URL
function redirect(url)
status(302, "Found")
header("Location", url)
close()
end
---- Create a querystring out of a table of key - value pairs.
--- @param table Query string source table
--- @return Encoded HTTP query string
function build_querystring(q)
local s = { "?" }
@@ -269,56 +227,10 @@ function build_querystring(q)
return table.concat(s, "")
end
---- Return the URL-decoded equivalent of a string.
--- @param str URL-encoded string
--- @param no_plus Don't decode + to " "
--- @return URL-decoded string
--- @see urlencode
urldecode = protocol.urldecode
---- Return the URL-encoded equivalent of a string.
--- @param str Source string
--- @return URL-encoded string
--- @see urldecode
urlencode = protocol.urlencode
---- Send the given data as JSON encoded string.
--- @param data Data to send
function write_json(x)
- if x == nil then
- write("null")
- elseif type(x) == "table" then
- local k, v
- if type(next(x)) == "number" then
- write("[ ")
- for k, v in ipairs(x) do
- write_json(v)
- if next(x, k) then
- write(", ")
- end
- end
- write(" ]")
- else
- write("{ ")
- for k, v in pairs(x) do
- write("%q: " % k)
- write_json(v)
- if next(x, k) then
- write(", ")
- end
- end
- write(" }")
- end
- elseif type(x) == "number" or type(x) == "boolean" then
- if (x ~= x) then
- -- NaN is the only value that doesn't equal to itself.
- write("Number.NaN")
- else
- write(tostring(x))
- end
- else
- write('"%s"' % tostring(x):gsub('["%z\1-\31]', function(c)
- return '\\u%04x' % c:byte(1)
- end))
- end
+ util.serialize_json(x, write)
end
diff --git a/modules/luci-base/luasrc/http.luadoc b/modules/luci-base/luasrc/http.luadoc
new file mode 100644
index 0000000000..4e31216a1e
--- /dev/null
+++ b/modules/luci-base/luasrc/http.luadoc
@@ -0,0 +1,166 @@
+---[[
+LuCI Web Framework high-level HTTP functions.
+
+module "luci.http"
+]]
+
+---[[
+Close the HTTP-Connection.
+
+
+@class function
+@name close
+]]
+
+---[[
+Return the request content if the request was of unknown type.
+
+@class function
+@name content
+@return HTTP request body
+@return HTTP request body length
+]]
+
+---[[
+Get a certain HTTP input value or a table of all input values.
+
+@class function
+@name formvalue
+@param name Name of the GET or POST variable to fetch
+@param noparse Don't parse POST data before getting the value
+@return HTTP input value or table of all input value
+]]
+
+---[[
+Get a table of all HTTP input values with a certain prefix.
+
+@class function
+@name formvaluetable
+@param prefix Prefix
+@return Table of all HTTP input values with given prefix
+]]
+
+---[[
+Get the value of a certain HTTP-Cookie.
+
+@class function
+@name getcookie
+@param name Cookie Name
+@return String containing cookie data
+]]
+
+---[[
+Get the value of a certain HTTP environment variable
+
+or the environment table itself.
+@class function
+@name getenv
+@param name Environment variable
+@return HTTP environment value or environment table
+]]
+
+---[[
+Set a handler function for incoming user file uploads.
+
+@class function
+@name setfilehandler
+@param callback Handler function
+]]
+
+---[[
+Send a HTTP-Header.
+
+@class function
+@name header
+@param key Header key
+@param value Header value
+]]
+
+---[[
+Set the mime type of following content data.
+
+@class function
+@name prepare_content
+@param mime Mimetype of following content
+]]
+
+---[[
+Get the RAW HTTP input source
+
+@class function
+@name source
+@return HTTP LTN12 source
+]]
+
+---[[
+Set the HTTP status code and status message.
+
+@class function
+@name status
+@param code Status code
+@param message Status message
+]]
+
+---[[
+Send a chunk of content data to the client.
+
+This function is as a valid LTN12 sink.
+If the content chunk is nil this function will automatically invoke close.
+@class function
+@name write
+@param content Content chunk
+@param src_err Error object from source (optional)
+@see close
+]]
+
+---[[
+Splice data from a filedescriptor to the client.
+
+@class function
+@name splice
+@param fp File descriptor
+@param size Bytes to splice (optional)
+]]
+
+---[[
+Redirects the client to a new URL and closes the connection.
+
+@class function
+@name redirect
+@param url Target URL
+]]
+
+---[[
+Create a querystring out of a table of key - value pairs.
+
+@class function
+@name build_querystring
+@param table Query string source table
+@return Encoded HTTP query string
+]]
+
+---[[
+Return the URL-decoded equivalent of a string.
+
+@param str URL-encoded string
+@param no_plus Don't decode + to " "
+@return URL-decoded string
+@see urlencode
+]]
+
+---[[
+Return the URL-encoded equivalent of a string.
+
+@param str Source string
+@return URL-encoded string
+@see urldecode
+]]
+
+---[[
+Send the given data as JSON encoded string.
+
+@class function
+@name write_json
+@param data Data to send
+]]
+
diff --git a/modules/luci-base/luasrc/http/protocol.lua b/modules/luci-base/luasrc/http/protocol.lua
index aeb7ea6211..e9efb44cfa 100644
--- a/modules/luci-base/luasrc/http/protocol.lua
+++ b/modules/luci-base/luasrc/http/protocol.lua
@@ -1,7 +1,6 @@
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
---- LuCI http protocol class.
-- This class contains several functions useful for http message- and content
-- decoding and to retrive form data from raw http messages.
module("luci.http.protocol", package.seeall)
@@ -10,12 +9,7 @@ local ltn12 = require("luci.ltn12")
HTTP_MAX_CONTENT = 1024*8 -- 8 kB maximum content size
---- Decode an urlencoded string - optionally without decoding
-- the "+" sign to " " - and return the decoded string.
--- @param str Input string in x-www-urlencoded format
--- @param no_plus Don't decode "+" signs to spaces
--- @return The decoded string
--- @see urlencode
function urldecode( str, no_plus )
local function __chrdec( hex )
@@ -33,15 +27,10 @@ function urldecode( str, no_plus )
return str
end
---- Extract and split urlencoded data pairs, separated bei either "&" or ";"
-- from given url or string. Returns a table with urldecoded values.
-- Simple parameters are stored as string values associated with the parameter
-- name within the table. Parameters with multiple values are stored as array
-- containing the corresponding values.
--- @param url The url or string which contains x-www-urlencoded form data
--- @param tbl Use the given table for storing values (optional)
--- @return Table containing the urldecoded parameters
--- @see urlencode_params
function urldecode_params( url, tbl )
local params = tbl or { }
@@ -73,10 +62,6 @@ function urldecode_params( url, tbl )
return params
end
---- Encode given string to x-www-urlencoded format.
--- @param str String to encode
--- @return String containing the encoded data
--- @see urldecode
function urlencode( str )
local function __chrenc( chr )
@@ -95,12 +80,8 @@ function urlencode( str )
return str
end
---- Encode each key-value-pair in given table to x-www-urlencoded format,
-- separated by "&". Tables are encoded as parameters with multiple values by
-- repeating the parameter name with each value.
--- @param tbl Table with the values
--- @return String containing encoded values
--- @see urldecode_params
function urlencode_params( tbl )
local enc = ""
@@ -122,9 +103,6 @@ end
-- (Internal function)
-- Initialize given parameter and coerce string into table when the parameter
-- already exists.
--- @param tbl Table where parameter should be created
--- @param key Parameter name
--- @return Always nil
local function __initval( tbl, key )
if tbl[key] == nil then
tbl[key] = ""
@@ -138,11 +116,6 @@ end
-- (Internal function)
-- Append given data to given parameter, either by extending the string value
-- or by appending it to the last string in the parameter's value table.
--- @param tbl Table containing the previously initialized parameter value
--- @param key Parameter name
--- @param chunk String containing the data to append
--- @return Always nil
--- @see __initval
local function __appendval( tbl, key, chunk )
if type(tbl[key]) == "table" then
tbl[key][#tbl[key]] = tbl[key][#tbl[key]] .. chunk
@@ -155,12 +128,6 @@ end
-- Finish the value of given parameter, either by transforming the string value
-- or - in the case of multi value parameters - the last element in the
-- associated values table.
--- @param tbl Table containing the previously initialized parameter value
--- @param key Parameter name
--- @param handler Function which transforms the parameter value
--- @return Always nil
--- @see __initval
--- @see __appendval
local function __finishval( tbl, key, handler )
if handler then
if type(tbl[key]) == "table" then
@@ -259,10 +226,7 @@ process_states['headers'] = function( msg, chunk )
end
---- Creates a ltn12 source from the given socket. The source will return it's
-- data line by line with the trailing \r\n stripped of.
--- @param sock Readable network socket
--- @return Ltn12 source function
function header_source( sock )
return ltn12.source.simplify( function()
@@ -289,7 +253,6 @@ function header_source( sock )
end )
end
---- Decode a mime encoded http message body with multipart/form-data
-- Content-Type. Stores all extracted data associated with its parameter name
-- in the params table withing the given message object. Multiple parameter
-- values are stored as tables, ordinary ones as strings.
@@ -300,12 +263,6 @@ end
-- o Table containing decoded (name, file) and raw (headers) mime header data
-- o String value containing a chunk of the file data
-- o Boolean which indicates wheather the current chunk is the last one (eof)
--- @param src Ltn12 source function
--- @param msg HTTP message object
--- @param filecb File callback function (optional)
--- @return Value indicating successful operation (not nil means "ok")
--- @return String containing the error if unsuccessful
--- @see parse_message_header
function mimedecode_message_body( src, msg, filecb )
if msg and msg.env.CONTENT_TYPE then
@@ -449,15 +406,9 @@ function mimedecode_message_body( src, msg, filecb )
return ltn12.pump.all( src, snk )
end
---- Decode an urlencoded http message body with application/x-www-urlencoded
-- Content-Type. Stores all extracted data associated with its parameter name
-- in the params table withing the given message object. Multiple parameter
-- values are stored as tables, ordinary ones as strings.
--- @param src Ltn12 source function
--- @param msg HTTP message object
--- @return Value indicating successful operation (not nil means "ok")
--- @return String containing the error if unsuccessful
--- @see parse_message_header
function urldecode_message_body( src, msg )
local tlen = 0
@@ -507,12 +458,8 @@ function urldecode_message_body( src, msg )
return ltn12.pump.all( src, snk )
end
---- Try to extract an http message header including information like protocol
-- version, message headers and resulting CGI environment variables from the
-- given ltn12 source.
--- @param src Ltn12 source function
--- @return HTTP message object
--- @see parse_message_body
function parse_message_header( src )
local ok = true
@@ -582,19 +529,12 @@ function parse_message_header( src )
return msg
end
---- Try to extract and decode a http message body from the given ltn12 source.
-- This function will examine the Content-Type within the given message object
-- to select the appropriate content decoder.
-- Currently the application/x-www-urlencoded and application/form-data
-- mime types are supported. If the encountered content encoding can't be
-- handled then the whole message body will be stored unaltered as "content"
-- property within the given message object.
--- @param src Ltn12 source function
--- @param msg HTTP message object
--- @param filecb File data callback (optional, see mimedecode_message_body())
--- @return Value indicating successful operation (not nil means "ok")
--- @return String containing the error if unsuccessful
--- @see parse_message_header
function parse_message_body( src, msg, filecb )
-- Is it multipart/mime ?
if msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and
@@ -655,8 +595,6 @@ function parse_message_body( src, msg, filecb )
end
end
---- Table containing human readable messages for several http status codes.
--- @class table
statusmsg = {
[200] = "OK",
[206] = "Partial Content",
diff --git a/modules/luci-base/luasrc/http/protocol.luadoc b/modules/luci-base/luasrc/http/protocol.luadoc
new file mode 100644
index 0000000000..67a60d9e7a
--- /dev/null
+++ b/modules/luci-base/luasrc/http/protocol.luadoc
@@ -0,0 +1,142 @@
+---[[
+LuCI http protocol class.
+
+This class contains several functions useful for http message- and content
+decoding and to retrive form data from raw http messages.
+]]
+module "luci.http.protocol"
+
+---[[
+Decode an urlencoded string - optionally without decoding
+
+the "+" sign to " " - and return the decoded string.
+@class function
+@name urldecode
+@param str Input string in x-www-urlencoded format
+@param no_plus Don't decode "+" signs to spaces
+@return The decoded string
+@see urlencode
+]]
+
+---[[
+Extract and split urlencoded data pairs, separated bei either "&" or ";"
+
+from given url or string. Returns a table with urldecoded values.
+Simple parameters are stored as string values associated with the parameter
+name within the table. Parameters with multiple values are stored as array
+containing the corresponding values.
+@class function
+@name urldecode_params
+@param url The url or string which contains x-www-urlencoded form data
+@param tbl Use the given table for storing values (optional)
+@return Table containing the urldecoded parameters
+@see urlencode_params
+]]
+
+---[[
+Encode given string to x-www-urlencoded format.
+
+@class function
+@name urlencode
+@param str String to encode
+@return String containing the encoded data
+@see urldecode
+]]
+
+---[[
+Encode each key-value-pair in given table to x-www-urlencoded format,
+
+separated by "&". Tables are encoded as parameters with multiple values by
+repeating the parameter name with each value.
+@class function
+@name urlencode_params
+@param tbl Table with the values
+@return String containing encoded values
+@see urldecode_params
+]]
+
+---[[
+Creates a ltn12 source from the given socket. The source will return it's
+
+data line by line with the trailing \r\n stripped of.
+@class function
+@name header_source
+@param sock Readable network socket
+@return Ltn12 source function
+]]
+
+---[[
+Decode a mime encoded http message body with multipart/form-data
+
+Content-Type. Stores all extracted data associated with its parameter name
+in the params table withing the given message object. Multiple parameter
+values are stored as tables, ordinary ones as strings.
+If an optional file callback function is given then it is feeded with the
+file contents chunk by chunk and only the extracted file name is stored
+within the params table. The callback function will be called subsequently
+with three arguments:
+ o Table containing decoded (name, file) and raw (headers) mime header data
+ o String value containing a chunk of the file data
+ o Boolean which indicates wheather the current chunk is the last one (eof)
+@class function
+@name mimedecode_message_body
+@param src Ltn12 source function
+@param msg HTTP message object
+@param filecb File callback function (optional)
+@return Value indicating successful operation (not nil means "ok")
+@return String containing the error if unsuccessful
+@see parse_message_header
+]]
+
+---[[
+Decode an urlencoded http message body with application/x-www-urlencoded
+
+Content-Type. Stores all extracted data associated with its parameter name
+in the params table withing the given message object. Multiple parameter
+values are stored as tables, ordinary ones as strings.
+@class function
+@name urldecode_message_body
+@param src Ltn12 source function
+@param msg HTTP message object
+@return Value indicating successful operation (not nil means "ok")
+@return String containing the error if unsuccessful
+@see parse_message_header
+]]
+
+---[[
+Try to extract an http message header including information like protocol
+
+version, message headers and resulting CGI environment variables from the
+given ltn12 source.
+@class function
+@name parse_message_header
+@param src Ltn12 source function
+@return HTTP message object
+@see parse_message_body
+]]
+
+---[[
+Try to extract and decode a http message body from the given ltn12 source.
+
+This function will examine the Content-Type within the given message object
+to select the appropriate content decoder.
+Currently the application/x-www-urlencoded and application/form-data
+mime types are supported. If the encountered content encoding can't be
+handled then the whole message body will be stored unaltered as "content"
+property within the given message object.
+@class function
+@name parse_message_body
+@param src Ltn12 source function
+@param msg HTTP message object
+@param filecb File data callback (optional, see mimedecode_message_body())
+@return Value indicating successful operation (not nil means "ok")
+@return String containing the error if unsuccessful
+@see parse_message_header
+]]
+
+---[[
+Table containing human readable messages for several http status codes.
+
+@class table
+]]
+
diff --git a/modules/luci-base/luasrc/http/protocol/conditionals.lua b/modules/luci-base/luasrc/http/protocol/conditionals.lua
index 1d40425ff9..d31a4e38a4 100644
--- a/modules/luci-base/luasrc/http/protocol/conditionals.lua
+++ b/modules/luci-base/luasrc/http/protocol/conditionals.lua
@@ -1,7 +1,6 @@
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
---- LuCI http protocol implementation - HTTP/1.1 bits.
-- This class provides basic ETag handling and implements most of the
-- conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 .
module("luci.http.protocol.conditionals", package.seeall)
@@ -9,22 +8,14 @@ module("luci.http.protocol.conditionals", package.seeall)
local date = require("luci.http.protocol.date")
---- Implement 14.19 / ETag.
--- @param stat A file.stat structure
--- @return String containing the generated tag suitable for ETag headers
function mk_etag( stat )
if stat ~= nil then
return string.format( '"%x-%x-%x"', stat.ino, stat.size, stat.mtime )
end
end
---- 14.24 / If-Match
-- Test whether the given message object contains an "If-Match" header and
-- compare it against the given stat object.
--- @param req HTTP request message object
--- @param stat A file.stat object
--- @return Boolean indicating whether the precondition is ok
--- @return Alternative status code if the precondition failed
function if_match( req, stat )
local h = req.headers
local etag = mk_etag( stat )
@@ -43,14 +34,8 @@ function if_match( req, stat )
return true
end
---- 14.25 / If-Modified-Since
-- Test whether the given message object contains an "If-Modified-Since" header
-- and compare it against the given stat object.
--- @param req HTTP request message object
--- @param stat A file.stat object
--- @return Boolean indicating whether the precondition is ok
--- @return Alternative status code if the precondition failed
--- @return Table containing extra HTTP headers if the precondition failed
function if_modified_since( req, stat )
local h = req.headers
@@ -72,14 +57,8 @@ function if_modified_since( req, stat )
return true
end
---- 14.26 / If-None-Match
-- Test whether the given message object contains an "If-None-Match" header and
-- compare it against the given stat object.
--- @param req HTTP request message object
--- @param stat A file.stat object
--- @return Boolean indicating whether the precondition is ok
--- @return Alternative status code if the precondition failed
--- @return Table containing extra HTTP headers if the precondition failed
function if_none_match( req, stat )
local h = req.headers
local etag = mk_etag( stat )
@@ -105,26 +84,16 @@ function if_none_match( req, stat )
return true
end
---- 14.27 / If-Range
-- The If-Range header is currently not implemented due to the lack of general
-- byte range stuff in luci.http.protocol . This function will always return
-- false, 412 to indicate a failed precondition.
--- @param req HTTP request message object
--- @param stat A file.stat object
--- @return Boolean indicating whether the precondition is ok
--- @return Alternative status code if the precondition failed
function if_range( req, stat )
-- Sorry, no subranges (yet)
return false, 412
end
---- 14.28 / If-Unmodified-Since
-- Test whether the given message object contains an "If-Unmodified-Since"
-- header and compare it against the given stat object.
--- @param req HTTP request message object
--- @param stat A file.stat object
--- @return Boolean indicating whether the precondition is ok
--- @return Alternative status code if the precondition failed
function if_unmodified_since( req, stat )
local h = req.headers
diff --git a/modules/luci-base/luasrc/http/protocol/conditionals.luadoc b/modules/luci-base/luasrc/http/protocol/conditionals.luadoc
new file mode 100644
index 0000000000..9cfe02dd50
--- /dev/null
+++ b/modules/luci-base/luasrc/http/protocol/conditionals.luadoc
@@ -0,0 +1,85 @@
+---[[
+LuCI http protocol implementation - HTTP/1.1 bits.
+
+This class provides basic ETag handling and implements most of the
+conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 .
+]]
+module "luci.http.protocol.conditionals"
+
+---[[
+Implement 14.19 / ETag.
+
+@class function
+@name mk_etag
+@param stat A file.stat structure
+@return String containing the generated tag suitable for ETag headers
+]]
+
+---[[
+14.24 / If-Match
+
+Test whether the given message object contains an "If-Match" header and
+compare it against the given stat object.
+@class function
+@name if_match
+@param req HTTP request message object
+@param stat A file.stat object
+@return Boolean indicating whether the precondition is ok
+@return Alternative status code if the precondition failed
+]]
+
+---[[
+14.25 / If-Modified-Since
+
+Test whether the given message object contains an "If-Modified-Since" header
+and compare it against the given stat object.
+@class function
+@name if_modified_since
+@param req HTTP request message object
+@param stat A file.stat object
+@return Boolean indicating whether the precondition is ok
+@return Alternative status code if the precondition failed
+@return Table containing extra HTTP headers if the precondition failed
+]]
+
+---[[
+14.26 / If-None-Match
+
+Test whether the given message object contains an "If-None-Match" header and
+compare it against the given stat object.
+@class function
+@name if_none_match
+@param req HTTP request message object
+@param stat A file.stat object
+@return Boolean indicating whether the precondition is ok
+@return Alternative status code if the precondition failed
+@return Table containing extra HTTP headers if the precondition failed
+]]
+
+---[[
+14.27 / If-Range
+
+The If-Range header is currently not implemented due to the lack of general
+byte range stuff in luci.http.protocol . This function will always return
+false, 412 to indicate a failed precondition.
+@class function
+@name if_range
+@param req HTTP request message object
+@param stat A file.stat object
+@return Boolean indicating whether the precondition is ok
+@return Alternative status code if the precondition failed
+]]
+
+---[[
+14.28 / If-Unmodified-Since
+
+Test whether the given message object contains an "If-Unmodified-Since"
+header and compare it against the given stat object.
+@class function
+@name if_unmodified_since
+@param req HTTP request message object
+@param stat A file.stat object
+@return Boolean indicating whether the precondition is ok
+@return Alternative status code if the precondition failed
+]]
+
diff --git a/modules/luci-base/luasrc/http/protocol/date.lua b/modules/luci-base/luasrc/http/protocol/date.lua
index 3105f37f63..e440219a9c 100644
--- a/modules/luci-base/luasrc/http/protocol/date.lua
+++ b/modules/luci-base/luasrc/http/protocol/date.lua
@@ -1,7 +1,6 @@
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
---- LuCI http protocol implementation - date helper class.
-- This class contains functions to parse, compare and format http dates.
module("luci.http.protocol.date", package.seeall)
@@ -13,9 +12,6 @@ MONTHS = {
"Sep", "Oct", "Nov", "Dec"
}
---- Return the time offset in seconds between the UTC and given time zone.
--- @param tz Symbolic or numeric timezone specifier
--- @return Time offset to UTC in seconds
function tz_offset(tz)
if type(tz) == "string" then
@@ -39,9 +35,6 @@ function tz_offset(tz)
return 0
end
---- Parse given HTTP date string and convert it to unix epoch time.
--- @param data String containing the date
--- @return Unix epoch time
function to_unix(date)
local wd, day, mon, yr, hr, min, sec, tz = date:match(
@@ -75,19 +68,10 @@ function to_unix(date)
return 0
end
---- Convert the given unix epoch time to valid HTTP date string.
--- @param time Unix epoch time
--- @return String containing the formatted date
function to_http(time)
return os.date( "%a, %d %b %Y %H:%M:%S GMT", time )
end
---- Compare two dates which can either be unix epoch times or HTTP date strings.
--- @param d1 The first date or epoch time to compare
--- @param d2 The first date or epoch time to compare
--- @return -1 - if d1 is lower then d2
--- @return 0 - if both dates are equal
--- @return 1 - if d1 is higher then d2
function compare(d1, d2)
if d1:match("[^0-9]") then d1 = to_unix(d1) end
diff --git a/modules/luci-base/luasrc/http/protocol/date.luadoc b/modules/luci-base/luasrc/http/protocol/date.luadoc
new file mode 100644
index 0000000000..d6f1c8d658
--- /dev/null
+++ b/modules/luci-base/luasrc/http/protocol/date.luadoc
@@ -0,0 +1,46 @@
+---[[
+LuCI http protocol implementation - date helper class.
+
+This class contains functions to parse, compare and format http dates.
+]]
+module "luci.http.protocol.date"
+
+---[[
+Return the time offset in seconds between the UTC and given time zone.
+
+@class function
+@name tz_offset
+@param tz Symbolic or numeric timezone specifier
+@return Time offset to UTC in seconds
+]]
+
+---[[
+Parse given HTTP date string and convert it to unix epoch time.
+
+@class function
+@name to_unix
+@param data String containing the date
+@return Unix epoch time
+]]
+
+---[[
+Convert the given unix epoch time to valid HTTP date string.
+
+@class function
+@name to_http
+@param time Unix epoch time
+@return String containing the formatted date
+]]
+
+---[[
+Compare two dates which can either be unix epoch times or HTTP date strings.
+
+@class function
+@name compare
+@param d1 The first date or epoch time to compare
+@param d2 The first date or epoch time to compare
+@return -1 - if d1 is lower then d2
+@return 0 - if both dates are equal
+@return 1 - if d1 is higher then d2
+]]
+
diff --git a/modules/luci-base/luasrc/http/protocol/mime.lua b/modules/luci-base/luasrc/http/protocol/mime.lua
index 15da15cf8b..2b99d8e74e 100644
--- a/modules/luci-base/luasrc/http/protocol/mime.lua
+++ b/modules/luci-base/luasrc/http/protocol/mime.lua
@@ -1,15 +1,12 @@
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
---- LuCI http protocol implementation - mime helper class.
-- This class provides functions to guess mime types from file extensions and
-- vice versa.
module("luci.http.protocol.mime", package.seeall)
require("luci.util")
---- MIME mapping table containg extension - mimetype relations.
--- @class table
MIME_TYPES = {
["txt"] = "text/plain";
["js"] = "text/javascript";
@@ -54,10 +51,7 @@ MIME_TYPES = {
["avi"] = "video/x-msvideo";
}
---- Extract extension from a filename and return corresponding mime-type or
-- "application/octet-stream" if the extension is unknown.
--- @param filename The filename for which the mime type is guessed
--- @return String containign the determined mime type
function to_mime(filename)
if type(filename) == "string" then
local ext = filename:match("[^%.]+$")
@@ -70,10 +64,7 @@ function to_mime(filename)
return "application/octet-stream"
end
---- Return corresponding extension for a given mime type or nil if the
-- given mime-type is unknown.
--- @param mimetype The mimetype to retrieve the extension from
--- @return String with the extension or nil for unknown type
function to_ext(mimetype)
if type(mimetype) == "string" then
for ext, type in luci.util.kspairs( MIME_TYPES ) do
diff --git a/modules/luci-base/luasrc/http/protocol/mime.luadoc b/modules/luci-base/luasrc/http/protocol/mime.luadoc
new file mode 100644
index 0000000000..195b5fcc89
--- /dev/null
+++ b/modules/luci-base/luasrc/http/protocol/mime.luadoc
@@ -0,0 +1,34 @@
+---[[
+LuCI http protocol implementation - mime helper class.
+
+This class provides functions to guess mime types from file extensions and
+vice versa.
+]]
+module "luci.http.protocol.mime"
+
+---[[
+MIME mapping table containg extension - mimetype relations.
+
+@class table
+]]
+
+---[[
+Extract extension from a filename and return corresponding mime-type or
+
+"application/octet-stream" if the extension is unknown.
+@class function
+@name to_mime
+@param filename The filename for which the mime type is guessed
+@return String containign the determined mime type
+]]
+
+---[[
+Return corresponding extension for a given mime type or nil if the
+
+given mime-type is unknown.
+@class function
+@name to_ext
+@param mimetype The mimetype to retrieve the extension from
+@return String with the extension or nil for unknown type
+]]
+
diff --git a/modules/luci-base/luasrc/i18n.lua b/modules/luci-base/luasrc/i18n.lua
index dd84a59f84..bcb16d5c04 100644
--- a/modules/luci-base/luasrc/i18n.lua
+++ b/modules/luci-base/luasrc/i18n.lua
@@ -1,7 +1,6 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
---- LuCI translation library.
module("luci.i18n", package.seeall)
require("luci.util")
@@ -13,27 +12,16 @@ loaded = {}
context = luci.util.threadlocal()
default = "en"
---- Clear the translation table.
function clear()
end
---- Load a translation and copy its data into the translation table.
--- @param file Language file
--- @param lang Two-letter language code
--- @param force Force reload even if already loaded (optional)
--- @return Success status
function load(file, lang, force)
end
---- Load a translation file using the default translation language.
-- Alternatively load the translation of the fallback language.
--- @param file Language file
--- @param force Force reload even if already loaded (optional)
function loadc(file, force)
end
---- Set the context default translation language.
--- @param lang Two-letter language code
function setlanguage(lang)
context.lang = lang:gsub("_", "-")
context.parent = (context.lang:match("^([a-z][a-z])_"))
@@ -46,36 +34,22 @@ function setlanguage(lang)
return context.lang
end
---- Return the translated value for a specific translation key.
--- @param key Default translation text
--- @return Translated string
function translate(key)
return tparser.translate(key) or key
end
---- Return the translated value for a specific translation key and use it as sprintf pattern.
--- @param key Default translation text
--- @param ... Format parameters
--- @return Translated and formatted string
function translatef(key, ...)
return tostring(translate(key)):format(...)
end
---- Return the translated value for a specific translation key
-- and ensure that the returned value is a Lua string value.
-- This is the same as calling <code>tostring(translate(...))</code>
--- @param key Default translation text
--- @return Translated string
function string(key)
return tostring(translate(key))
end
---- Return the translated value for a specific translation key and use it as sprintf pattern.
-- Ensure that the returned value is a Lua string value.
-- This is the same as calling <code>tostring(translatef(...))</code>
--- @param key Default translation text
--- @param ... Format parameters
--- @return Translated and formatted string
function stringf(key, ...)
return tostring(translate(key)):format(...)
end
diff --git a/modules/luci-base/luasrc/i18n.luadoc b/modules/luci-base/luasrc/i18n.luadoc
new file mode 100644
index 0000000000..aa38841e17
--- /dev/null
+++ b/modules/luci-base/luasrc/i18n.luadoc
@@ -0,0 +1,84 @@
+---[[
+LuCI translation library.
+]]
+module "luci.i18n"
+
+---[[
+Clear the translation table.
+
+
+@class function
+@name clear
+]]
+
+---[[
+Load a translation and copy its data into the translation table.
+
+@class function
+@name load
+@param file Language file
+@param lang Two-letter language code
+@param force Force reload even if already loaded (optional)
+@return Success status
+]]
+
+---[[
+Load a translation file using the default translation language.
+
+Alternatively load the translation of the fallback language.
+@class function
+@name loadc
+@param file Language file
+@param force Force reload even if already loaded (optional)
+]]
+
+---[[
+Set the context default translation language.
+
+@class function
+@name setlanguage
+@param lang Two-letter language code
+]]
+
+---[[
+Return the translated value for a specific translation key.
+
+@class function
+@name translate
+@param key Default translation text
+@return Translated string
+]]
+
+---[[
+Return the translated value for a specific translation key and use it as sprintf pattern.
+
+@class function
+@name translatef
+@param key Default translation text
+@param ... Format parameters
+@return Translated and formatted string
+]]
+
+---[[
+Return the translated value for a specific translation key
+
+and ensure that the returned value is a Lua string value.
+This is the same as calling <code>tostring(translate(...))</code>
+@class function
+@name string
+@param key Default translation text
+@return Translated string
+]]
+
+---[[
+Return the translated value for a specific translation key and use it as sprintf pattern.
+
+Ensure that the returned value is a Lua string value.
+This is the same as calling <code>tostring(translatef(...))</code>
+@class function
+@name stringf
+@param key Default translation text
+@param ... Format parameters
+@return Translated and formatted string
+]]
+
diff --git a/modules/luci-base/luasrc/ip.lua b/modules/luci-base/luasrc/ip.lua
deleted file mode 100644
index d8aaea91d2..0000000000
--- a/modules/luci-base/luasrc/ip.lua
+++ /dev/null
@@ -1,661 +0,0 @@
--- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
--- Copyright 2008 Steven Barth <steven@midlink.org>
--- Licensed to the public under the Apache License 2.0.
-
---- LuCI IP calculation library.
-module( "luci.ip", package.seeall )
-
-require "nixio"
-local bit = nixio.bit
-local util = require "luci.util"
-
---- Boolean; true if system is little endian
-LITTLE_ENDIAN = not util.bigendian()
-
---- Boolean; true if system is big endian
-BIG_ENDIAN = not LITTLE_ENDIAN
-
---- Specifier for IPv4 address family
-FAMILY_INET4 = 0x04
-
---- Specifier for IPv6 address family
-FAMILY_INET6 = 0x06
-
-
-local function __bless(x)
- return setmetatable( x, {
- __index = luci.ip.cidr,
- __add = luci.ip.cidr.add,
- __sub = luci.ip.cidr.sub,
- __lt = luci.ip.cidr.lower,
- __eq = luci.ip.cidr.equal,
- __le =
- function(...)
- return luci.ip.cidr.equal(...) or luci.ip.cidr.lower(...)
- end
- } )
-end
-
-local function __array16( x, family )
- local list
-
- if type(x) == "number" then
- list = { bit.rshift(x, 16), bit.band(x, 0xFFFF) }
-
- elseif type(x) == "string" then
- if x:find(":") then x = IPv6(x) else x = IPv4(x) end
- if x then
- assert( x[1] == family, "Can't mix IPv4 and IPv6 addresses" )
- list = { unpack(x[2]) }
- end
-
- elseif type(x) == "table" and type(x[2]) == "table" then
- assert( x[1] == family, "Can't mix IPv4 and IPv6 addresses" )
- list = { unpack(x[2]) }
-
- elseif type(x) == "table" then
- list = { unpack(x) }
- end
-
- assert( list, "Invalid operand" )
-
- return list
-end
-
-local function __mask16(bits)
- return bit.lshift( bit.rshift( 0xFFFF, 16 - bits % 16 ), 16 - bits % 16 )
-end
-
-local function __not16(bits)
- return bit.band( bit.bnot( __mask16(bits) ), 0xFFFF )
-end
-
-local function __maxlen(family)
- return ( family == FAMILY_INET4 ) and 32 or 128
-end
-
-local function __sublen(family)
- return ( family == FAMILY_INET4 ) and 30 or 127
-end
-
-
---- Convert given short value to network byte order on little endian hosts
--- @param x Unsigned integer value between 0x0000 and 0xFFFF
--- @return Byte-swapped value
--- @see htonl
--- @see ntohs
-function htons(x)
- if LITTLE_ENDIAN then
- return bit.bor(
- bit.rshift( x, 8 ),
- bit.band( bit.lshift( x, 8 ), 0xFF00 )
- )
- else
- return x
- end
-end
-
---- Convert given long value to network byte order on little endian hosts
--- @param x Unsigned integer value between 0x00000000 and 0xFFFFFFFF
--- @return Byte-swapped value
--- @see htons
--- @see ntohl
-function htonl(x)
- if LITTLE_ENDIAN then
- return bit.bor(
- bit.lshift( htons( bit.band( x, 0xFFFF ) ), 16 ),
- htons( bit.rshift( x, 16 ) )
- )
- else
- return x
- end
-end
-
---- Convert given short value to host byte order on little endian hosts
--- @class function
--- @name ntohs
--- @param x Unsigned integer value between 0x0000 and 0xFFFF
--- @return Byte-swapped value
--- @see htonl
--- @see ntohs
-ntohs = htons
-
---- Convert given short value to host byte order on little endian hosts
--- @class function
--- @name ntohl
--- @param x Unsigned integer value between 0x00000000 and 0xFFFFFFFF
--- @return Byte-swapped value
--- @see htons
--- @see ntohl
-ntohl = htonl
-
-
---- Parse given IPv4 address in dotted quad or CIDR notation. If an optional
--- netmask is given as second argument and the IP address is encoded in CIDR
--- notation then the netmask parameter takes precedence. If neither a CIDR
--- encoded prefix nor a netmask parameter is given, then a prefix length of
--- 32 bit is assumed.
--- @param address IPv4 address in dotted quad or CIDR notation
--- @param netmask IPv4 netmask in dotted quad notation (optional)
--- @return luci.ip.cidr instance or nil if given address was invalid
--- @see IPv6
--- @see Hex
-function IPv4(address, netmask)
- address = address or "0.0.0.0/0"
-
- local obj = __bless({ FAMILY_INET4 })
-
- local data = {}
- local prefix = address:match("/(.+)")
- address = address:gsub("/.+","")
- address = address:gsub("^%[(.*)%]$", "%1"):upper():gsub("^::FFFF:", "")
-
- if netmask then
- prefix = obj:prefix(netmask)
- elseif prefix then
- prefix = tonumber(prefix)
- if not prefix or prefix < 0 or prefix > 32 then return nil end
- else
- prefix = 32
- end
-
- local b1, b2, b3, b4 = address:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")
-
- b1 = tonumber(b1)
- b2 = tonumber(b2)
- b3 = tonumber(b3)
- b4 = tonumber(b4)
-
- if b1 and b1 <= 255 and
- b2 and b2 <= 255 and
- b3 and b3 <= 255 and
- b4 and b4 <= 255 and
- prefix
- then
- table.insert(obj, { b1 * 256 + b2, b3 * 256 + b4 })
- table.insert(obj, prefix)
- return obj
- end
-end
-
---- Parse given IPv6 address in full, compressed, mixed or CIDR notation.
--- If an optional netmask is given as second argument and the IP address is
--- encoded in CIDR notation then the netmask parameter takes precedence.
--- If neither a CIDR encoded prefix nor a netmask parameter is given, then a
--- prefix length of 128 bit is assumed.
--- @param address IPv6 address in full/compressed/mixed or CIDR notation
--- @param netmask IPv6 netmask in full/compressed/mixed notation (optional)
--- @return luci.ip.cidr instance or nil if given address was invalid
--- @see IPv4
--- @see Hex
-function IPv6(address, netmask)
- address = address or "::/0"
-
- local obj = __bless({ FAMILY_INET6 })
-
- local data = {}
- local prefix = address:match("/(.+)")
- address = address:gsub("/.+","")
- address = address:gsub("^%[(.*)%]$", "%1")
-
- if netmask then
- prefix = obj:prefix(netmask)
- elseif prefix then
- prefix = tonumber(prefix)
- if not prefix or prefix < 0 or prefix > 128 then return nil end
- else
- prefix = 128
- end
-
- local borderl = address:sub(1, 1) == ":" and 2 or 1
- local borderh, zeroh, chunk, block, i
-
- if #address > 45 then return nil end
-
- repeat
- borderh = address:find(":", borderl, true)
- if not borderh then break end
-
- block = tonumber(address:sub(borderl, borderh - 1), 16)
- if block and block <= 0xFFFF then
- data[#data+1] = block
- else
- if zeroh or borderh - borderl > 1 then return nil end
- zeroh = #data + 1
- end
-
- borderl = borderh + 1
- until #data == 7
-
- chunk = address:sub(borderl)
- if #chunk > 0 and #chunk <= 4 then
- block = tonumber(chunk, 16)
- if not block or block > 0xFFFF then return nil end
-
- data[#data+1] = block
- elseif #chunk > 4 then
- if #data == 7 or #chunk > 15 then return nil end
- borderl = 1
- for i=1, 4 do
- borderh = chunk:find(".", borderl, true)
- if not borderh and i < 4 then return nil end
- borderh = borderh and borderh - 1
-
- block = tonumber(chunk:sub(borderl, borderh))
- if not block or block > 255 then return nil end
-
- if i == 1 or i == 3 then
- data[#data+1] = block * 256
- else
- data[#data] = data[#data] + block
- end
-
- borderl = borderh and borderh + 2
- end
- end
-
- if zeroh then
- if #data == 8 then return nil end
- while #data < 8 do
- table.insert(data, zeroh, 0)
- end
- end
-
- if #data == 8 and prefix then
- table.insert(obj, data)
- table.insert(obj, prefix)
- return obj
- end
-end
-
---- Transform given hex-encoded value to luci.ip.cidr instance of specified
--- address family.
--- @param hex String containing hex encoded value
--- @param prefix Prefix length of CIDR instance (optional, default is 32/128)
--- @param family Address family, either luci.ip.FAMILY_INET4 or FAMILY_INET6
--- @param swap Bool indicating whether to swap byteorder on low endian host
--- @return luci.ip.cidr instance or nil if given value was invalid
--- @see IPv4
--- @see IPv6
-function Hex( hex, prefix, family, swap )
- family = ( family ~= nil ) and family or FAMILY_INET4
- swap = ( swap == nil ) and true or swap
- prefix = prefix or __maxlen(family)
-
- local len = __maxlen(family)
- local tmp = ""
- local data = { }
- local i
-
- for i = 1, (len/4) - #hex do tmp = tmp .. '0' end
-
- if swap and LITTLE_ENDIAN then
- for i = #hex, 1, -2 do tmp = tmp .. hex:sub( i - 1, i ) end
- else
- tmp = tmp .. hex
- end
-
- hex = tmp
-
- for i = 1, ( len / 4 ), 4 do
- local n = tonumber( hex:sub( i, i+3 ), 16 )
- if n then
- data[#data+1] = n
- else
- return nil
- end
- end
-
- return __bless({ family, data, prefix })
-end
-
-
---- LuCI IP Library / CIDR instances
--- @class module
--- @cstyle instance
--- @name luci.ip.cidr
-cidr = util.class()
-
---- Test whether the instance is a IPv4 address.
--- @return Boolean indicating a IPv4 address type
--- @see cidr.is6
-function cidr.is4( self )
- return self[1] == FAMILY_INET4
-end
-
---- Test whether this instance is an IPv4 RFC1918 private address
--- @return Boolean indicating whether this instance is an RFC1918 address
-function cidr.is4rfc1918( self )
- if self[1] == FAMILY_INET4 then
- return ((self[2][1] >= 0x0A00) and (self[2][1] <= 0x0AFF)) or
- ((self[2][1] >= 0xAC10) and (self[2][1] <= 0xAC1F)) or
- (self[2][1] == 0xC0A8)
- end
- return false
-end
-
---- Test whether this instance is an IPv4 link-local address (Zeroconf)
--- @return Boolean indicating whether this instance is IPv4 link-local
-function cidr.is4linklocal( self )
- if self[1] == FAMILY_INET4 then
- return (self[2][1] == 0xA9FE)
- end
- return false
-end
-
---- Test whether the instance is a IPv6 address.
--- @return Boolean indicating a IPv6 address type
--- @see cidr.is4
-function cidr.is6( self )
- return self[1] == FAMILY_INET6
-end
-
---- Test whether this instance is an IPv6 link-local address
--- @return Boolean indicating whether this instance is IPv6 link-local
-function cidr.is6linklocal( self )
- if self[1] == FAMILY_INET6 then
- return (self[2][1] >= 0xFE80) and (self[2][1] <= 0xFEBF)
- end
- return false
-end
-
---- Return a corresponding string representation of the instance.
--- If the prefix length is lower then the maximum possible prefix length for the
--- corresponding address type then the address is returned in CIDR notation,
--- otherwise the prefix will be left out.
-function cidr.string( self )
- local str
- if self:is4() then
- str = string.format(
- "%d.%d.%d.%d",
- bit.rshift(self[2][1], 8), bit.band(self[2][1], 0xFF),
- bit.rshift(self[2][2], 8), bit.band(self[2][2], 0xFF)
- )
- if self[3] < 32 then
- str = str .. "/" .. self[3]
- end
- elseif self:is6() then
- str = string.format( "%X:%X:%X:%X:%X:%X:%X:%X", unpack(self[2]) )
- if self[3] < 128 then
- str = str .. "/" .. self[3]
- end
- end
- return str
-end
-
---- Test whether the value of the instance is lower then the given address.
--- This function will throw an exception if the given address has a different
--- family than this instance.
--- @param addr A luci.ip.cidr instance to compare against
--- @return Boolean indicating whether this instance is lower
--- @see cidr.higher
--- @see cidr.equal
-function cidr.lower( self, addr )
- assert( self[1] == addr[1], "Can't compare IPv4 and IPv6 addresses" )
- local i
- for i = 1, #self[2] do
- if self[2][i] ~= addr[2][i] then
- return self[2][i] < addr[2][i]
- end
- end
- return false
-end
-
---- Test whether the value of the instance is higher then the given address.
--- This function will throw an exception if the given address has a different
--- family than this instance.
--- @param addr A luci.ip.cidr instance to compare against
--- @return Boolean indicating whether this instance is higher
--- @see cidr.lower
--- @see cidr.equal
-function cidr.higher( self, addr )
- assert( self[1] == addr[1], "Can't compare IPv4 and IPv6 addresses" )
- local i
- for i = 1, #self[2] do
- if self[2][i] ~= addr[2][i] then
- return self[2][i] > addr[2][i]
- end
- end
- return false
-end
-
---- Test whether the value of the instance is equal to the given address.
--- This function will throw an exception if the given address is a different
--- family than this instance.
--- @param addr A luci.ip.cidr instance to compare against
--- @return Boolean indicating whether this instance is equal
--- @see cidr.lower
--- @see cidr.higher
-function cidr.equal( self, addr )
- assert( self[1] == addr[1], "Can't compare IPv4 and IPv6 addresses" )
- local i
- for i = 1, #self[2] do
- if self[2][i] ~= addr[2][i] then
- return false
- end
- end
- return true
-end
-
---- Return the prefix length of this CIDR instance.
--- @param mask Override instance prefix with given netmask (optional)
--- @return Prefix length in bit
-function cidr.prefix( self, mask )
- local prefix = self[3]
-
- if mask then
- prefix = 0
-
- local stop = false
- local obj = type(mask) ~= "table"
- and ( self:is4() and IPv4(mask) or IPv6(mask) ) or mask
-
- if not obj then return nil end
-
- local _, word
- for _, word in ipairs(obj[2]) do
- if word == 0xFFFF then
- prefix = prefix + 16
- else
- local bitmask = bit.lshift(1, 15)
- while bit.band(word, bitmask) == bitmask do
- prefix = prefix + 1
- bitmask = bit.lshift(1, 15 - (prefix % 16))
- end
-
- break
- end
- end
- end
-
- return prefix
-end
-
---- Return a corresponding CIDR representing the network address of this
--- instance.
--- @param bits Override prefix length of this instance (optional)
--- @return CIDR instance containing the network address
--- @see cidr.host
--- @see cidr.broadcast
--- @see cidr.mask
-function cidr.network( self, bits )
- local data = { }
- bits = bits or self[3]
-
- local i
- for i = 1, math.floor( bits / 16 ) do
- data[#data+1] = self[2][i]
- end
-
- if #data < #self[2] then
- data[#data+1] = bit.band( self[2][1+#data], __mask16(bits) )
-
- for i = #data + 1, #self[2] do
- data[#data+1] = 0
- end
- end
-
- return __bless({ self[1], data, __maxlen(self[1]) })
-end
-
---- Return a corresponding CIDR representing the host address of this
--- instance. This is intended to extract the host address from larger subnet.
--- @return CIDR instance containing the network address
--- @see cidr.network
--- @see cidr.broadcast
--- @see cidr.mask
-function cidr.host( self )
- return __bless({ self[1], self[2], __maxlen(self[1]) })
-end
-
---- Return a corresponding CIDR representing the netmask of this instance.
--- @param bits Override prefix length of this instance (optional)
--- @return CIDR instance containing the netmask
--- @see cidr.network
--- @see cidr.host
--- @see cidr.broadcast
-function cidr.mask( self, bits )
- local data = { }
- bits = bits or self[3]
-
- for i = 1, math.floor( bits / 16 ) do
- data[#data+1] = 0xFFFF
- end
-
- if #data < #self[2] then
- data[#data+1] = __mask16(bits)
-
- for i = #data + 1, #self[2] do
- data[#data+1] = 0
- end
- end
-
- return __bless({ self[1], data, __maxlen(self[1]) })
-end
-
---- Return CIDR containing the broadcast address of this instance.
--- @return CIDR instance containing the netmask, always nil for IPv6
--- @see cidr.network
--- @see cidr.host
--- @see cidr.mask
-function cidr.broadcast( self )
- -- IPv6 has no broadcast addresses (XXX: assert() instead?)
- if self[1] == FAMILY_INET4 then
- local data = { unpack(self[2]) }
- local offset = math.floor( self[3] / 16 ) + 1
-
- if offset <= #data then
- data[offset] = bit.bor( data[offset], __not16(self[3]) )
- for i = offset + 1, #data do data[i] = 0xFFFF end
-
- return __bless({ self[1], data, __maxlen(self[1]) })
- end
- end
-end
-
---- Test whether this instance fully contains the given CIDR instance.
--- @param addr CIDR instance to test against
--- @return Boolean indicating whether this instance contains the given CIDR
-function cidr.contains( self, addr )
- assert( self[1] == addr[1], "Can't compare IPv4 and IPv6 addresses" )
-
- if self:prefix() <= addr:prefix() then
- return self:network() == addr:network(self:prefix())
- end
-
- return false
-end
-
---- Add specified amount of hosts to this instance.
--- @param amount Number of hosts to add to this instance
--- @param inplace Boolen indicating whether to alter values inplace (optional)
--- @return CIDR representing the new address or nil on overflow error
--- @see cidr.sub
-function cidr.add( self, amount, inplace )
- local pos
- local data = { unpack(self[2]) }
- local shorts = __array16( amount, self[1] )
-
- for pos = #data, 1, -1 do
- local add = ( #shorts > 0 ) and table.remove( shorts, #shorts ) or 0
- if ( data[pos] + add ) > 0xFFFF then
- data[pos] = ( data[pos] + add ) % 0xFFFF
- if pos > 1 then
- data[pos-1] = data[pos-1] + ( add - data[pos] )
- else
- return nil
- end
- else
- data[pos] = data[pos] + add
- end
- end
-
- if inplace then
- self[2] = data
- return self
- else
- return __bless({ self[1], data, self[3] })
- end
-end
-
---- Substract specified amount of hosts from this instance.
--- @param amount Number of hosts to substract from this instance
--- @param inplace Boolen indicating whether to alter values inplace (optional)
--- @return CIDR representing the new address or nil on underflow error
--- @see cidr.add
-function cidr.sub( self, amount, inplace )
- local pos
- local data = { unpack(self[2]) }
- local shorts = __array16( amount, self[1] )
-
- for pos = #data, 1, -1 do
- local sub = ( #shorts > 0 ) and table.remove( shorts, #shorts ) or 0
- if ( data[pos] - sub ) < 0 then
- data[pos] = ( sub - data[pos] ) % 0xFFFF
- if pos > 1 then
- data[pos-1] = data[pos-1] - ( sub + data[pos] )
- else
- return nil
- end
- else
- data[pos] = data[pos] - sub
- end
- end
-
- if inplace then
- self[2] = data
- return self
- else
- return __bless({ self[1], data, self[3] })
- end
-end
-
---- Return CIDR containing the lowest available host address within this subnet.
--- @return CIDR containing the host address, nil if subnet is too small
--- @see cidr.maxhost
-function cidr.minhost( self )
- if self[3] <= __sublen(self[1]) then
- -- 1st is Network Address in IPv4 and Subnet-Router Anycast Adresse in IPv6
- return self:network():add(1, true)
- end
-end
-
---- Return CIDR containing the highest available host address within the subnet.
--- @return CIDR containing the host address, nil if subnet is too small
--- @see cidr.minhost
-function cidr.maxhost( self )
- if self[3] <= __sublen(self[1]) then
- local i
- local data = { unpack(self[2]) }
- local offset = math.floor( self[3] / 16 ) + 1
-
- data[offset] = bit.bor( data[offset], __not16(self[3]) )
- for i = offset + 1, #data do data[i] = 0xFFFF end
- data = __bless({ self[1], data, __maxlen(self[1]) })
-
- -- Last address in reserved for Broadcast Address in IPv4
- if data[1] == FAMILY_INET4 then data:sub(1, true) end
-
- return data
- end
-end
diff --git a/modules/luci-base/luasrc/ltn12.lua b/modules/luci-base/luasrc/ltn12.lua
index b59fb8c48a..3a7268ccae 100644
--- a/modules/luci-base/luasrc/ltn12.lua
+++ b/modules/luci-base/luasrc/ltn12.lua
@@ -39,7 +39,6 @@ local string = require("string")
local table = require("table")
local base = _G
---- Diego Nehab's LTN12 - Filters, sources, sinks and pumps.
-- See http://lua-users.org/wiki/FiltersSourcesAndSinks for design concepts
module("luci.ltn12")
@@ -56,16 +55,8 @@ _VERSION = "LTN12 1.0.1"
-- Filter stuff
-----------------------------------------------------------------------------
---- LTN12 Filter constructors
--- @class module
--- @name luci.ltn12.filter
---- Return a high level filter that cycles a low-level filter
-- by passing it each chunk and updating a context between calls.
--- @param low Low-level filter
--- @param ctx Context
--- @param extra Extra argument passed to the low-level filter
--- @return LTN12 filter
function filter.cycle(low, ctx, extra)
base.assert(low)
return function(chunk)
@@ -75,10 +66,7 @@ function filter.cycle(low, ctx, extra)
end
end
---- Chain a bunch of filters together.
-- (thanks to Wim Couwenberg)
--- @param ... filters to be chained
--- @return LTN12 filter
function filter.chain(...)
local n = table.getn(arg)
local top, index = 1, 1
@@ -112,34 +100,22 @@ end
-- Source stuff
-----------------------------------------------------------------------------
---- LTN12 Source constructors
--- @class module
--- @name luci.ltn12.source
-- create an empty source
local function empty()
return nil
end
---- Create an empty source.
--- @return LTN12 source
function source.empty()
return empty
end
---- Return a source that just outputs an error.
--- @param err Error object
--- @return LTN12 source
function source.error(err)
return function()
return nil, err
end
end
---- Create a file source.
--- @param handle File handle ready for reading
--- @param io_err IO error object
--- @return LTN12 source
function source.file(handle, io_err)
if handle then
return function()
@@ -151,9 +127,6 @@ function source.file(handle, io_err)
else return source.error(io_err or "unable to open file") end
end
---- Turn a fancy source into a simple source.
--- @param src fancy source
--- @return LTN12 source
function source.simplify(src)
base.assert(src)
return function()
@@ -164,9 +137,6 @@ function source.simplify(src)
end
end
---- Create a string source.
--- @param s Data
--- @return LTN12 source
function source.string(s)
if s then
local i = 1
@@ -179,9 +149,6 @@ function source.string(s)
else return source.empty() end
end
---- Creates rewindable source.
--- @param src LTN12 source to be made rewindable
--- @return LTN12 source
function source.rewind(src)
base.assert(src)
local t = {}
@@ -196,10 +163,6 @@ function source.rewind(src)
end
end
---- Chain a source and a filter together.
--- @param src LTN12 source
--- @param f LTN12 filter
--- @return LTN12 source
function source.chain(src, f)
base.assert(src and f)
local last_in, last_out = "", ""
@@ -247,11 +210,8 @@ function source.chain(src, f)
end
end
---- Create a source that produces contents of several sources.
-- Sources will be used one after the other, as if they were concatenated
-- (thanks to Wim Couwenberg)
--- @param ... LTN12 sources
--- @return LTN12 source
function source.cat(...)
local src = table.remove(arg, 1)
return function()
@@ -268,13 +228,7 @@ end
-- Sink stuff
-----------------------------------------------------------------------------
---- LTN12 sink constructors
--- @class module
--- @name luci.ltn12.sink
---- Create a sink that stores into a table.
--- @param t output table to store into
--- @return LTN12 sink
function sink.table(t)
t = t or {}
local f = function(chunk, err)
@@ -284,9 +238,6 @@ function sink.table(t)
return f, t
end
---- Turn a fancy sink into a simple sink.
--- @param snk fancy sink
--- @return LTN12 sink
function sink.simplify(snk)
base.assert(snk)
return function(chunk, err)
@@ -297,10 +248,6 @@ function sink.simplify(snk)
end
end
---- Create a file sink.
--- @param handle file handle to write to
--- @param io_err IO error
--- @return LTN12 sink
function sink.file(handle, io_err)
if handle then
return function(chunk, err)
@@ -317,25 +264,16 @@ local function null()
return 1
end
---- Create a sink that discards data.
--- @return LTN12 sink
function sink.null()
return null
end
---- Create a sink that just returns an error.
--- @param err Error object
--- @return LTN12 sink
function sink.error(err)
return function()
return nil, err
end
end
---- Chain a sink with a filter.
--- @param f LTN12 filter
--- @param snk LTN12 sink
--- @return LTN12 sink
function sink.chain(f, snk)
base.assert(f and snk)
return function(chunk, err)
@@ -356,15 +294,7 @@ end
-- Pump stuff
-----------------------------------------------------------------------------
---- LTN12 pump functions
--- @class module
--- @name luci.ltn12.pump
---- Pump one chunk from the source to the sink.
--- @param src LTN12 source
--- @param snk LTN12 sink
--- @return Chunk of data or nil if an error occured
--- @return Error object
function pump.step(src, snk)
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
@@ -372,12 +302,6 @@ function pump.step(src, snk)
else return nil, src_err or snk_err end
end
---- Pump all data from a source to a sink, using a step function.
--- @param src LTN12 source
--- @param snk LTN12 sink
--- @param step step function (optional)
--- @return 1 if the operation succeeded otherwise nil
--- @return Error object
function pump.all(src, snk, step)
base.assert(src and snk)
step = step or pump.step
diff --git a/modules/luci-base/luasrc/model/ipkg.lua b/modules/luci-base/luasrc/model/ipkg.lua
index 216caa5cca..587637272d 100644
--- a/modules/luci-base/luasrc/model/ipkg.lua
+++ b/modules/luci-base/luasrc/model/ipkg.lua
@@ -15,7 +15,6 @@ local table = table
local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase"
local icfg = "/etc/opkg.conf"
---- LuCI OPKG call abstraction library
module "luci.model.ipkg"
@@ -93,54 +92,31 @@ local function _lookup(act, pkg)
end
---- Return information about installed and available packages.
--- @param pkg Limit output to a (set of) packages
--- @return Table containing package information
function info(pkg)
return _lookup("info", pkg)
end
---- Return the package status of one or more packages.
--- @param pkg Limit output to a (set of) packages
--- @return Table containing package status information
function status(pkg)
return _lookup("status", pkg)
end
---- Install one or more packages.
--- @param ... List of packages to install
--- @return Boolean indicating the status of the action
--- @return OPKG return code, STDOUT and STDERR
function install(...)
return _action("install", ...)
end
---- Determine whether a given package is installed.
--- @param pkg Package
--- @return Boolean
function installed(pkg)
local p = status(pkg)[pkg]
return (p and p.Status and p.Status.installed)
end
---- Remove one or more packages.
--- @param ... List of packages to install
--- @return Boolean indicating the status of the action
--- @return OPKG return code, STDOUT and STDERR
function remove(...)
return _action("remove", ...)
end
---- Update package lists.
--- @return Boolean indicating the status of the action
--- @return OPKG return code, STDOUT and STDERR
function update()
return _action("update")
end
---- Upgrades all installed packages.
--- @return Boolean indicating the status of the action
--- @return OPKG return code, STDOUT and STDERR
function upgrade()
return _action("upgrade")
end
@@ -174,33 +150,19 @@ function _list(action, pat, cb)
end
end
---- List all packages known to opkg.
--- @param pat Only find packages matching this pattern, nil lists all packages
--- @param cb Callback function invoked for each package, receives name, version and description as arguments
--- @return nothing
function list_all(pat, cb)
_list("list", pat, cb)
end
---- List installed packages.
--- @param pat Only find packages matching this pattern, nil lists all packages
--- @param cb Callback function invoked for each package, receives name, version and description as arguments
--- @return nothing
function list_installed(pat, cb)
_list("list_installed", pat, cb)
end
---- Find packages that match the given pattern.
--- @param pat Find packages whose names or descriptions match this pattern, nil results in zero results
--- @param cb Callback function invoked for each patckage, receives name, version and description as arguments
--- @return nothing
function find(pat, cb)
_list("find", pat, cb)
end
---- Determines the overlay root used by opkg.
--- @return String containing the directory path of the overlay root.
function overlay_root()
local od = "/"
local fd = io.open(icfg, "r")
diff --git a/modules/luci-base/luasrc/model/ipkg.luadoc b/modules/luci-base/luasrc/model/ipkg.luadoc
new file mode 100644
index 0000000000..cf0985f94a
--- /dev/null
+++ b/modules/luci-base/luasrc/model/ipkg.luadoc
@@ -0,0 +1,109 @@
+---[[
+LuCI OPKG call abstraction library
+
+module "luci.model.ipkg"
+]]
+
+---[[
+Return information about installed and available packages.
+
+@class function
+@name info
+@param pkg Limit output to a (set of) packages
+@return Table containing package information
+]]
+
+---[[
+Return the package status of one or more packages.
+
+@class function
+@name status
+@param pkg Limit output to a (set of) packages
+@return Table containing package status information
+]]
+
+---[[
+Install one or more packages.
+
+@class function
+@name install
+@param ... List of packages to install
+@return Boolean indicating the status of the action
+@return OPKG return code, STDOUT and STDERR
+]]
+
+---[[
+Determine whether a given package is installed.
+
+@class function
+@name installed
+@param pkg Package
+@return Boolean
+]]
+
+---[[
+Remove one or more packages.
+
+@class function
+@name remove
+@param ... List of packages to install
+@return Boolean indicating the status of the action
+@return OPKG return code, STDOUT and STDERR
+]]
+
+---[[
+Update package lists.
+
+@class function
+@name update
+@return Boolean indicating the status of the action
+@return OPKG return code, STDOUT and STDERR
+]]
+
+---[[
+Upgrades all installed packages.
+
+@class function
+@name upgrade
+@return Boolean indicating the status of the action
+@return OPKG return code, STDOUT and STDERR
+]]
+
+---[[
+List all packages known to opkg.
+
+@class function
+@name list_all
+@param pat Only find packages matching this pattern, nil lists all packages
+@param cb Callback function invoked for each package, receives name, version and description as arguments
+@return nothing
+]]
+
+---[[
+List installed packages.
+
+@class function
+@name list_installed
+@param pat Only find packages matching this pattern, nil lists all packages
+@param cb Callback function invoked for each package, receives name, version and description as arguments
+@return nothing
+]]
+
+---[[
+Find packages that match the given pattern.
+
+@class function
+@name find
+@param pat Find packages whose names or descriptions match this pattern, nil results in zero results
+@param cb Callback function invoked for each patckage, receives name, version and description as arguments
+@return nothing
+]]
+
+---[[
+Determines the overlay root used by opkg.
+
+@class function
+@name overlay_root
+@return String containing the directory path of the overlay root.
+]]
+
diff --git a/modules/luci-base/luasrc/model/uci.lua b/modules/luci-base/luasrc/model/uci.lua
index 8ac82773f3..1659137742 100644
--- a/modules/luci-base/luasrc/model/uci.lua
+++ b/modules/luci-base/luasrc/model/uci.lua
@@ -12,26 +12,18 @@ local require, getmetatable = require, getmetatable
local error, pairs, ipairs = error, pairs, ipairs
local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack
---- LuCI UCI model library.
-- The typical workflow for UCI is: Get a cursor instance from the
-- cursor factory, modify data (via Cursor.add, Cursor.delete, etc.),
-- save the changes to the staging area via Cursor.save and finally
-- Cursor.commit the data to the actual config files.
-- LuCI then needs to Cursor.apply the changes so deamons etc. are
-- reloaded.
--- @cstyle instance
module "luci.model.uci"
---- Create a new UCI-Cursor.
--- @class function
--- @name cursor
--- @return UCI-Cursor
cursor = uci.cursor
APIVERSION = uci.APIVERSION
---- Create a new Cursor initialized to the state directory.
--- @return UCI cursor
function cursor_state()
return cursor(nil, "/var/state")
end
@@ -42,9 +34,6 @@ inst_state = cursor_state()
local Cursor = getmetatable(inst)
---- Applies UCI configuration changes
--- @param configlist List of UCI configurations
--- @param command Don't apply only return the command
function Cursor.apply(self, configlist, command)
configlist = self:_affected(configlist)
if command then
@@ -56,10 +45,6 @@ function Cursor.apply(self, configlist, command)
end
---- Delete all sections of a given type that match certain criteria.
--- @param config UCI config
--- @param type UCI section type
--- @param comparator Function that will be called for each section and
-- returns a boolean whether to delete the current section (optional)
function Cursor.delete_all(self, config, stype, comparator)
local del = {}
@@ -90,12 +75,6 @@ function Cursor.delete_all(self, config, stype, comparator)
end
end
---- Create a new section and initialize it with data.
--- @param config UCI config
--- @param type UCI section type
--- @param name UCI section name (optional)
--- @param values Table of key - value pairs to initialize the section with
--- @return Name of created section
function Cursor.section(self, config, type, name, values)
local stat = true
if name then
@@ -112,10 +91,6 @@ function Cursor.section(self, config, type, name, values)
return stat and name
end
---- Updated the data of a section using data from a table.
--- @param config UCI config
--- @param section UCI section name (optional)
--- @param values Table of key - value pairs to update the section with
function Cursor.tset(self, config, section, values)
local stat = true
for k, v in pairs(values) do
@@ -126,21 +101,11 @@ function Cursor.tset(self, config, section, values)
return stat
end
---- Get a boolean option and return it's value as true or false.
--- @param config UCI config
--- @param section UCI section name
--- @param option UCI option
--- @return Boolean
function Cursor.get_bool(self, ...)
local val = self:get(...)
return ( val == "1" or val == "true" or val == "yes" or val == "on" )
end
---- Get an option or list and return values as table.
--- @param config UCI config
--- @param section UCI section name
--- @param option UCI option
--- @return UCI value
function Cursor.get_list(self, config, section, option)
if config and section and option then
local val = self:get(config, section, option)
@@ -149,12 +114,6 @@ function Cursor.get_list(self, config, section, option)
return nil
end
---- Get the given option from the first section with the given type.
--- @param config UCI config
--- @param type UCI section type
--- @param option UCI option (optional)
--- @param default Default value (optional)
--- @return UCI value
function Cursor.get_first(self, conf, stype, opt, def)
local rv = def
@@ -178,12 +137,6 @@ function Cursor.get_first(self, conf, stype, opt, def)
return rv
end
---- Set given values as list.
--- @param config UCI config
--- @param section UCI section name
--- @param option UCI option
--- @param value UCI value
--- @return Boolean whether operation succeeded
function Cursor.set_list(self, config, section, option, value)
if config and section and option then
return self:set(
@@ -238,10 +191,8 @@ function Cursor._affected(self, configlist)
return reloadlist
end
---- Create a sub-state of this cursor. The sub-state is tied to the parent
-- curser, means it the parent unloads or loads configs, the sub state will
-- do so as well.
--- @return UCI state cursor tied to the parent cursor
function Cursor.substate(self)
Cursor._substates = Cursor._substates or { }
Cursor._substates[self] = Cursor._substates[self] or cursor_state()
@@ -265,118 +216,18 @@ function Cursor.unload(self, ...)
end
---- Add an anonymous section.
--- @class function
--- @name Cursor.add
--- @param config UCI config
--- @param type UCI section type
--- @return Name of created section
-
---- Get a table of saved but uncommitted changes.
--- @class function
--- @name Cursor.changes
--- @param config UCI config
--- @return Table of changes
--- @see Cursor.save
-
---- Commit saved changes.
--- @class function
--- @name Cursor.commit
--- @param config UCI config
--- @return Boolean whether operation succeeded
--- @see Cursor.revert
--- @see Cursor.save
-
---- Deletes a section or an option.
--- @class function
--- @name Cursor.delete
--- @param config UCI config
--- @param section UCI section name
--- @param option UCI option (optional)
--- @return Boolean whether operation succeeded
-
---- Call a function for every section of a certain type.
--- @class function
--- @name Cursor.foreach
--- @param config UCI config
--- @param type UCI section type
--- @param callback Function to be called
--- @return Boolean whether operation succeeded
-
---- Get a section type or an option
--- @class function
--- @name Cursor.get
--- @param config UCI config
--- @param section UCI section name
--- @param option UCI option (optional)
--- @return UCI value
-
---- Get all sections of a config or all values of a section.
--- @class function
--- @name Cursor.get_all
--- @param config UCI config
--- @param section UCI section name (optional)
--- @return Table of UCI sections or table of UCI values
-
---- Manually load a config.
--- @class function
--- @name Cursor.load
--- @param config UCI config
--- @return Boolean whether operation succeeded
--- @see Cursor.save
--- @see Cursor.unload
-
---- Revert saved but uncommitted changes.
--- @class function
--- @name Cursor.revert
--- @param config UCI config
--- @return Boolean whether operation succeeded
--- @see Cursor.commit
--- @see Cursor.save
-
---- Saves changes made to a config to make them committable.
--- @class function
--- @name Cursor.save
--- @param config UCI config
--- @return Boolean whether operation succeeded
--- @see Cursor.load
--- @see Cursor.unload
-
---- Set a value or create a named section.
--- @class function
--- @name Cursor.set
--- @param config UCI config
--- @param section UCI section name
--- @param option UCI option or UCI section type
--- @param value UCI value or nil if you want to create a section
--- @return Boolean whether operation succeeded
-
---- Get the configuration directory.
--- @class function
--- @name Cursor.get_confdir
--- @return Configuration directory
-
---- Get the directory for uncomitted changes.
--- @class function
--- @name Cursor.get_savedir
--- @return Save directory
-
---- Set the configuration directory.
--- @class function
--- @name Cursor.set_confdir
--- @param directory UCI configuration directory
--- @return Boolean whether operation succeeded
-
---- Set the directory for uncommited changes.
--- @class function
--- @name Cursor.set_savedir
--- @param directory UCI changes directory
--- @return Boolean whether operation succeeded
-
---- Discard changes made to a config.
--- @class function
--- @name Cursor.unload
--- @param config UCI config
--- @return Boolean whether operation succeeded
--- @see Cursor.load
--- @see Cursor.save
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/luci-base/luasrc/model/uci.luadoc b/modules/luci-base/luasrc/model/uci.luadoc
new file mode 100644
index 0000000000..1c208669d1
--- /dev/null
+++ b/modules/luci-base/luasrc/model/uci.luadoc
@@ -0,0 +1,291 @@
+---[[
+LuCI UCI model library.
+
+The typical workflow for UCI is: Get a cursor instance from the
+cursor factory, modify data (via Cursor.add, Cursor.delete, etc.),
+save the changes to the staging area via Cursor.save and finally
+Cursor.commit the data to the actual config files.
+LuCI then needs to Cursor.apply the changes so deamons etc. are
+reloaded.
+@cstyle instance
+module "luci.model.uci"
+]]
+
+---[[
+Create a new UCI-Cursor.
+
+@class function
+@name cursor
+@return UCI-Cursor
+]]
+
+---[[
+Create a new Cursor initialized to the state directory.
+
+@class function
+@name cursor_state
+@return UCI cursor
+]]
+
+---[[
+Applies UCI configuration changes
+
+@class function
+@name Cursor.apply
+@param configlist List of UCI configurations
+@param command Don't apply only return the command
+]]
+
+---[[
+Delete all sections of a given type that match certain criteria.
+
+@class function
+@name Cursor.delete_all
+@param config UCI config
+@param type UCI section type
+@param comparator Function that will be called for each section and
+returns a boolean whether to delete the current section (optional)
+]]
+
+---[[
+Create a new section and initialize it with data.
+
+@class function
+@name Cursor.section
+@param config UCI config
+@param type UCI section type
+@param name UCI section name (optional)
+@param values Table of key - value pairs to initialize the section with
+@return Name of created section
+]]
+
+---[[
+Updated the data of a section using data from a table.
+
+@class function
+@name Cursor.tset
+@param config UCI config
+@param section UCI section name (optional)
+@param values Table of key - value pairs to update the section with
+]]
+
+---[[
+Get a boolean option and return it's value as true or false.
+
+@class function
+@name Cursor.get_bool
+@param config UCI config
+@param section UCI section name
+@param option UCI option
+@return Boolean
+]]
+
+---[[
+Get an option or list and return values as table.
+
+@class function
+@name Cursor.get_list
+@param config UCI config
+@param section UCI section name
+@param option UCI option
+@return UCI value
+]]
+
+---[[
+Get the given option from the first section with the given type.
+
+@class function
+@name Cursor.get_first
+@param config UCI config
+@param type UCI section type
+@param option UCI option (optional)
+@param default Default value (optional)
+@return UCI value
+]]
+
+---[[
+Set given values as list.
+
+@class function
+@name Cursor.set_list
+@param config UCI config
+@param section UCI section name
+@param option UCI option
+@param value UCI value
+@return Boolean whether operation succeeded
+]]
+
+---[[
+Create a sub-state of this cursor. The sub-state is tied to the parent
+
+curser, means it the parent unloads or loads configs, the sub state will
+do so as well.
+@class function
+@name Cursor.substate
+@return UCI state cursor tied to the parent cursor
+]]
+
+---[[
+Add an anonymous section.
+
+@class function
+@name Cursor.add
+@param config UCI config
+@param type UCI section type
+@return Name of created section
+]]
+
+---[[
+Get a table of saved but uncommitted changes.
+
+@class function
+@name Cursor.changes
+@param config UCI config
+@return Table of changes
+@see Cursor.save
+]]
+
+---[[
+Commit saved changes.
+
+@class function
+@name Cursor.commit
+@param config UCI config
+@return Boolean whether operation succeeded
+@see Cursor.revert
+@see Cursor.save
+]]
+
+---[[
+Deletes a section or an option.
+
+@class function
+@name Cursor.delete
+@param config UCI config
+@param section UCI section name
+@param option UCI option (optional)
+@return Boolean whether operation succeeded
+]]
+
+---[[
+Call a function for every section of a certain type.
+
+@class function
+@name Cursor.foreach
+@param config UCI config
+@param type UCI section type
+@param callback Function to be called
+@return Boolean whether operation succeeded
+]]
+
+---[[
+Get a section type or an option
+
+@class function
+@name Cursor.get
+@param config UCI config
+@param section UCI section name
+@param option UCI option (optional)
+@return UCI value
+]]
+
+---[[
+Get all sections of a config or all values of a section.
+
+@class function
+@name Cursor.get_all
+@param config UCI config
+@param section UCI section name (optional)
+@return Table of UCI sections or table of UCI values
+]]
+
+---[[
+Manually load a config.
+
+@class function
+@name Cursor.load
+@param config UCI config
+@return Boolean whether operation succeeded
+@see Cursor.save
+@see Cursor.unload
+]]
+
+---[[
+Revert saved but uncommitted changes.
+
+@class function
+@name Cursor.revert
+@param config UCI config
+@return Boolean whether operation succeeded
+@see Cursor.commit
+@see Cursor.save
+]]
+
+---[[
+Saves changes made to a config to make them committable.
+
+@class function
+@name Cursor.save
+@param config UCI config
+@return Boolean whether operation succeeded
+@see Cursor.load
+@see Cursor.unload
+]]
+
+---[[
+Set a value or create a named section.
+
+@class function
+@name Cursor.set
+@param config UCI config
+@param section UCI section name
+@param option UCI option or UCI section type
+@param value UCI value or nil if you want to create a section
+@return Boolean whether operation succeeded
+]]
+
+---[[
+Get the configuration directory.
+
+@class function
+@name Cursor.get_confdir
+@return Configuration directory
+]]
+
+---[[
+Get the directory for uncomitted changes.
+
+@class function
+@name Cursor.get_savedir
+@return Save directory
+]]
+
+---[[
+Set the configuration directory.
+
+@class function
+@name Cursor.set_confdir
+@param directory UCI configuration directory
+@return Boolean whether operation succeeded
+]]
+
+---[[
+Set the directory for uncommited changes.
+
+@class function
+@name Cursor.set_savedir
+@param directory UCI changes directory
+@return Boolean whether operation succeeded
+]]
+
+---[[
+Discard changes made to a config.
+
+@class function
+@name Cursor.unload
+@param config UCI config
+@return Boolean whether operation succeeded
+@see Cursor.load
+@see Cursor.save
+]]
+
diff --git a/modules/luci-base/luasrc/sys.lua b/modules/luci-base/luasrc/sys.lua
index 1e594e1c88..3977da3eda 100644
--- a/modules/luci-base/luasrc/sys.lua
+++ b/modules/luci-base/luasrc/sys.lua
@@ -16,27 +16,14 @@ local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select
tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select
---- LuCI Linux and POSIX system utilities.
module "luci.sys"
---- Execute a given shell command and return the error code
--- @class function
--- @name call
--- @param ... Command to call
--- @return Error code of the command
function call(...)
return os.execute(...) / 256
end
---- Execute a given shell command and capture its standard output
--- @class function
--- @name exec
--- @param command Command to call
--- @return String containg the return the output of the command
exec = luci.util.exec
---- Retrieve information about currently mounted file systems.
--- @return Table containing mount information
function mounts()
local data = {}
local k = {"fs", "blocks", "used", "available", "percent", "mountpoint"}
@@ -82,20 +69,11 @@ function mounts()
return data
end
---- Retrieve environment variables. If no variable is given then a table
-- containing the whole environment is returned otherwise this function returns
-- the corresponding string value for the given name or nil if no such variable
-- exists.
--- @class function
--- @name getenv
--- @param var Name of the environment variable to retrieve (optional)
--- @return String containg the value of the specified variable
--- @return Table containing all variables if no variable name is given
getenv = nixio.getenv
---- Get or set the current hostname.
--- @param String containing a new hostname to set (optional)
--- @return String containing the system hostname
function hostname(newname)
if type(newname) == "string" and #newname > 0 then
fs.writefile( "/proc/sys/kernel/hostname", newname )
@@ -105,11 +83,6 @@ function hostname(newname)
end
end
---- Returns the contents of a documented referred by an URL.
--- @param url The URL to retrieve
--- @param stream Return a stream instead of a buffer
--- @param target Directly write to target file name
--- @return String containing the contents of given the URL
function httpget(url, stream, target)
if not target then
local source = stream and io.popen or luci.util.exec
@@ -120,46 +93,30 @@ function httpget(url, stream, target)
end
end
---- Initiate a system reboot.
--- @return Return value of os.execute()
function reboot()
return os.execute("reboot >/dev/null 2>&1")
end
---- Retrieves the output of the "logread" command.
--- @return String containing the current log buffer
function syslog()
return luci.util.exec("logread")
end
---- Retrieves the output of the "dmesg" command.
--- @return String containing the current log buffer
function dmesg()
return luci.util.exec("dmesg")
end
---- Generates a random id with specified length.
--- @param bytes Number of bytes for the unique id
--- @return String containing hex encoded id
function uniqueid(bytes)
local rand = fs.readfile("/dev/urandom", bytes)
return rand and nixio.bin.hexlify(rand)
end
---- Returns the current system uptime stats.
--- @return String containing total uptime in seconds
function uptime()
return nixio.sysinfo().uptime
end
---- LuCI system utilities / network related functions.
--- @class module
--- @name luci.sys.net
net = {}
---- Returns the current arp-table entries as two-dimensional table.
--- @return Table of table containing the current arp entries.
-- The following fields are defined for arp entry objects:
-- { "IP address", "HW address", "HW type", "Flags", "Mask", "Device" }
function net.arptable(callback)
@@ -269,8 +226,6 @@ local function _nethints(what, callback)
end
end
---- Returns a two-dimensional table of mac address hints.
--- @return Table of table containing known hosts from various sources.
-- Each entry contains the values in the following order:
-- [ "mac", "name" ]
function net.mac_hints(callback)
@@ -293,8 +248,6 @@ function net.mac_hints(callback)
end
end
---- Returns a two-dimensional table of IPv4 address hints.
--- @return Table of table containing known hosts from various sources.
-- Each entry contains the values in the following order:
-- [ "ip", "name" ]
function net.ipv4_hints(callback)
@@ -317,8 +270,6 @@ function net.ipv4_hints(callback)
end
end
---- Returns a two-dimensional table of IPv6 address hints.
--- @return Table of table containing known hosts from various sources.
-- Each entry contains the values in the following order:
-- [ "ip", "name" ]
function net.ipv6_hints(callback)
@@ -341,8 +292,6 @@ function net.ipv6_hints(callback)
end
end
---- Returns conntrack information
--- @return Table with the currently tracked IP connections
function net.conntrack(callback)
local connt = {}
if fs.access("/proc/net/nf_conntrack", "r") then
@@ -387,57 +336,6 @@ function net.conntrack(callback)
return connt
end
---- Determine the current IPv4 default route. If multiple default routes exist,
--- return the one with the lowest metric.
--- @return Table with the properties of the current default route.
--- The following fields are defined:
--- { "dest", "gateway", "metric", "refcount", "usecount", "irtt",
--- "flags", "device" }
-function net.defaultroute()
- local route
-
- net.routes(function(rt)
- if rt.dest:prefix() == 0 and (not route or route.metric > rt.metric) then
- route = rt
- end
- end)
-
- return route
-end
-
---- Determine the current IPv6 default route. If multiple default routes exist,
--- return the one with the lowest metric.
--- @return Table with the properties of the current default route.
--- The following fields are defined:
--- { "source", "dest", "nexthop", "metric", "refcount", "usecount",
--- "flags", "device" }
-function net.defaultroute6()
- local route
-
- net.routes6(function(rt)
- if rt.dest:prefix() == 0 and rt.device ~= "lo" and
- (not route or route.metric > rt.metric)
- then
- route = rt
- end
- end)
-
- if not route then
- local global_unicast = luci.ip.IPv6("2000::/3")
- net.routes6(function(rt)
- if rt.dest:equal(global_unicast) and
- (not route or route.metric > rt.metric)
- then
- route = rt
- end
- end)
- end
-
- return route
-end
-
---- Determine the names of available network interfaces.
--- @return Table containing all current interface names
function net.devices()
local devs = {}
for k, v in ipairs(nixio.getifaddrs()) do
@@ -449,8 +347,6 @@ function net.devices()
end
---- Return information about available network interfaces.
--- @return Table containing all current interface names and their information
function net.deviceinfo()
local devs = {}
for k, v in ipairs(nixio.getifaddrs()) do
@@ -479,21 +375,6 @@ function net.deviceinfo()
end
--- Determine the MAC address belonging to the given IP address.
--- @param ip IPv4 address
--- @return String containing the MAC address or nil if it cannot be found
-function net.ip4mac(ip)
- local mac = nil
- net.arptable(function(e)
- if e["IP address"] == ip then
- mac = e["HW address"]
- end
- end)
- return mac
-end
-
---- Returns the current kernel routing table entries.
--- @return Table of tables with properties of the corresponding routes.
-- The following fields are defined for route entry tables:
-- { "dest", "gateway", "metric", "refcount", "usecount", "irtt",
-- "flags", "device" }
@@ -539,8 +420,6 @@ function net.routes(callback)
return routes
end
---- Returns the current ipv6 kernel routing table entries.
--- @return Table of tables with properties of the corresponding routes.
-- The following fields are defined for route entry tables:
-- { "source", "dest", "nexthop", "metric", "refcount", "usecount",
-- "flags", "device" }
@@ -602,30 +481,18 @@ function net.routes6(callback)
end
end
---- Tests whether the given host responds to ping probes.
--- @param host String containing a hostname or IPv4 address
--- @return Number containing 0 on success and >= 1 on error
function net.pingtest(host)
return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1")
end
---- LuCI system utilities / process related functions.
--- @class module
--- @name luci.sys.process
process = {}
---- Get the current process id.
--- @class function
--- @name process.info
--- @return Number containing the current pid
function process.info(key)
local s = {uid = nixio.getuid(), gid = nixio.getgid()}
return not key and s or s[key]
end
---- Retrieve information about currently running processes.
--- @return Table containing process information
function process.list()
local data = {}
local k
@@ -658,51 +525,22 @@ function process.list()
return data
end
---- Set the gid of a process identified by given pid.
--- @param gid Number containing the Unix group id
--- @return Boolean indicating successful operation
--- @return String containing the error message if failed
--- @return Number containing the error code if failed
function process.setgroup(gid)
return nixio.setgid(gid)
end
---- Set the uid of a process identified by given pid.
--- @param uid Number containing the Unix user id
--- @return Boolean indicating successful operation
--- @return String containing the error message if failed
--- @return Number containing the error code if failed
function process.setuser(uid)
return nixio.setuid(uid)
end
---- Send a signal to a process identified by given pid.
--- @class function
--- @name process.signal
--- @param pid Number containing the process id
--- @param sig Signal to send (default: 15 [SIGTERM])
--- @return Boolean indicating successful operation
--- @return Number containing the error code if failed
process.signal = nixio.kill
---- LuCI system utilities / user related functions.
--- @class module
--- @name luci.sys.user
user = {}
---- Retrieve user informations for given uid.
--- @class function
--- @name getuser
--- @param uid Number containing the Unix user id
--- @return Table containing the following fields:
-- { "uid", "gid", "name", "passwd", "dir", "shell", "gecos" }
user.getuser = nixio.getpw
---- Retrieve the current user password hash.
--- @param username String containing the username to retrieve the password for
--- @return String containing the hash or nil if no password is set.
--- @return Password database entry
function user.getpasswd(username)
local pwe = nixio.getsp and nixio.getsp(username) or nixio.getpw(username)
local pwh = pwe and (pwe.pwdp or pwe.passwd)
@@ -713,10 +551,6 @@ function user.getpasswd(username)
end
end
---- Test whether given string matches the password of a given system user.
--- @param username String containing the Unix user name
--- @param pass String containing the password to compare
--- @return Boolean indicating wheather the passwords are equal
function user.checkpasswd(username, pass)
local pwh, pwe = user.getpasswd(username)
if pwe then
@@ -725,10 +559,6 @@ function user.checkpasswd(username, pass)
return false
end
---- Change the password of given user.
--- @param username String containing the Unix user name
--- @param password String containing the password to compare
--- @return Number containing 0 on success and >= 1 on error
function user.setpasswd(username, password)
if password then
password = password:gsub("'", [['"'"']])
@@ -745,14 +575,8 @@ function user.setpasswd(username, password)
end
---- LuCI system utilities / wifi related functions.
--- @class module
--- @name luci.sys.wifi
wifi = {}
---- Get wireless information for given interface.
--- @param ifname String containing the interface name
--- @return A wrapped iwinfo object instance
function wifi.getiwinfo(ifname)
local stat, iwinfo = pcall(require, "iwinfo")
@@ -798,14 +622,9 @@ function wifi.getiwinfo(ifname)
end
---- LuCI system utilities / init related functions.
--- @class module
--- @name luci.sys.init
init = {}
init.dir = "/etc/init.d/"
---- Get the names of all installed init scripts
--- @return Table containing the names of all inistalled init scripts
function init.names()
local names = { }
for name in fs.glob(init.dir.."*") do
@@ -814,9 +633,6 @@ function init.names()
return names
end
---- Get the index of he given init script
--- @param name Name of the init script
--- @return Numeric index value
function init.index(name)
if fs.access(init.dir..name) then
return call("env -i sh -c 'source %s%s enabled; exit ${START:-255}' >/dev/null"
@@ -830,37 +646,22 @@ local function init_action(action, name)
end
end
---- Test whether the given init script is enabled
--- @param name Name of the init script
--- @return Boolean indicating whether init is enabled
function init.enabled(name)
return (init_action("enabled", name) == 0)
end
---- Enable the given init script
--- @param name Name of the init script
--- @return Boolean indicating success
function init.enable(name)
return (init_action("enable", name) == 1)
end
---- Disable the given init script
--- @param name Name of the init script
--- @return Boolean indicating success
function init.disable(name)
return (init_action("disable", name) == 0)
end
---- Start the given init script
--- @param name Name of the init script
--- @return Boolean indicating success
function init.start(name)
return (init_action("start", name) == 0)
end
---- Stop the given init script
--- @param name Name of the init script
--- @return Boolean indicating success
function init.stop(name)
return (init_action("stop", name) == 0)
end
diff --git a/modules/luci-base/luasrc/sys.luadoc b/modules/luci-base/luasrc/sys.luadoc
new file mode 100644
index 0000000000..72a16a1ab0
--- /dev/null
+++ b/modules/luci-base/luasrc/sys.luadoc
@@ -0,0 +1,396 @@
+---[[
+LuCI Linux and POSIX system utilities.
+
+module "luci.sys"
+]]
+
+---[[
+Execute a given shell command and return the error code
+
+@class function
+@name call
+@param ... Command to call
+@return Error code of the command
+]]
+
+---[[
+Execute a given shell command and capture its standard output
+
+@class function
+@name exec
+@param command Command to call
+@return String containg the return the output of the command
+]]
+
+---[[
+Retrieve information about currently mounted file systems.
+
+@class function
+@name mounts
+@return Table containing mount information
+]]
+
+---[[
+Retrieve environment variables. If no variable is given then a table
+
+containing the whole environment is returned otherwise this function returns
+the corresponding string value for the given name or nil if no such variable
+exists.
+@class function
+@name getenv
+@param var Name of the environment variable to retrieve (optional)
+@return String containg the value of the specified variable
+@return Table containing all variables if no variable name is given
+]]
+
+---[[
+Get or set the current hostname.
+
+@class function
+@name hostname
+@param String containing a new hostname to set (optional)
+@return String containing the system hostname
+]]
+
+---[[
+Returns the contents of a documented referred by an URL.
+
+@class function
+@name httpget
+@param url The URL to retrieve
+@param stream Return a stream instead of a buffer
+@param target Directly write to target file name
+@return String containing the contents of given the URL
+]]
+
+---[[
+Initiate a system reboot.
+
+@class function
+@name reboot
+@return Return value of os.execute()
+]]
+
+---[[
+Retrieves the output of the "logread" command.
+
+@class function
+@name syslog
+@return String containing the current log buffer
+]]
+
+---[[
+Retrieves the output of the "dmesg" command.
+
+@class function
+@name dmesg
+@return String containing the current log buffer
+]]
+
+---[[
+Generates a random id with specified length.
+
+@class function
+@name uniqueid
+@param bytes Number of bytes for the unique id
+@return String containing hex encoded id
+]]
+
+---[[
+Returns the current system uptime stats.
+
+@class function
+@name uptime
+@return String containing total uptime in seconds
+]]
+
+---[[
+LuCI system utilities / network related functions.
+
+@class module
+@name luci.sys.net
+]]
+
+---[[
+Returns the current arp-table entries as two-dimensional table.
+
+@class function
+@name net.arptable
+@return Table of table containing the current arp entries.
+-- The following fields are defined for arp entry objects:
+-- { "IP address", "HW address", "HW type", "Flags", "Mask", "Device" }
+]]
+
+---[[
+Returns a two-dimensional table of mac address hints.
+
+@class function
+@name net.mac_hints
+@return Table of table containing known hosts from various sources.
+ Each entry contains the values in the following order:
+ [ "mac", "name" ]
+]]
+
+---[[
+Returns a two-dimensional table of IPv4 address hints.
+
+@class function
+@name net.ipv4_hints
+@return Table of table containing known hosts from various sources.
+ Each entry contains the values in the following order:
+ [ "ip", "name" ]
+]]
+
+---[[
+Returns a two-dimensional table of IPv6 address hints.
+
+@class function
+@name net.ipv6_hints
+@return Table of table containing known hosts from various sources.
+ Each entry contains the values in the following order:
+ [ "ip", "name" ]
+]]
+
+---[[
+Returns conntrack information
+
+@class function
+@name net.conntrack
+@return Table with the currently tracked IP connections
+]]
+
+---[[
+Determine the names of available network interfaces.
+
+@class function
+@name net.devices
+@return Table containing all current interface names
+]]
+
+---[[
+Return information about available network interfaces.
+
+@class function
+@name net.deviceinfo
+@return Table containing all current interface names and their information
+]]
+
+---[[
+Returns the current kernel routing table entries.
+
+@class function
+@name net.routes
+@return Table of tables with properties of the corresponding routes.
+-- The following fields are defined for route entry tables:
+-- { "dest", "gateway", "metric", "refcount", "usecount", "irtt",
+-- "flags", "device" }
+]]
+
+---[[
+Returns the current ipv6 kernel routing table entries.
+
+@class function
+@name net.routes6
+@return Table of tables with properties of the corresponding routes.
+-- The following fields are defined for route entry tables:
+-- { "source", "dest", "nexthop", "metric", "refcount", "usecount",
+-- "flags", "device" }
+]]
+
+---[[
+Tests whether the given host responds to ping probes.
+
+@class function
+@name net.pingtest
+@param host String containing a hostname or IPv4 address
+@return Number containing 0 on success and >= 1 on error
+]]
+
+---[[
+LuCI system utilities / process related functions.
+
+@class module
+@name luci.sys.process
+]]
+
+---[[
+Get the current process id.
+
+@class function
+@name process.info
+@return Number containing the current pid
+]]
+
+---[[
+Retrieve information about currently running processes.
+
+@class function
+@name process.list
+@return Table containing process information
+]]
+
+---[[
+Set the gid of a process identified by given pid.
+
+@class function
+@name process.setgroup
+@param gid Number containing the Unix group id
+@return Boolean indicating successful operation
+@return String containing the error message if failed
+@return Number containing the error code if failed
+]]
+
+---[[
+Set the uid of a process identified by given pid.
+
+@class function
+@name process.setuser
+@param uid Number containing the Unix user id
+@return Boolean indicating successful operation
+@return String containing the error message if failed
+@return Number containing the error code if failed
+]]
+
+---[[
+Send a signal to a process identified by given pid.
+
+@class function
+@name process.signal
+@param pid Number containing the process id
+@param sig Signal to send (default: 15 [SIGTERM])
+@return Boolean indicating successful operation
+@return Number containing the error code if failed
+]]
+
+---[[
+LuCI system utilities / user related functions.
+
+@class module
+@name luci.sys.user
+]]
+
+---[[
+Retrieve user informations for given uid.
+
+@class function
+@name getuser
+@param uid Number containing the Unix user id
+@return Table containing the following fields:
+-- { "uid", "gid", "name", "passwd", "dir", "shell", "gecos" }
+]]
+
+---[[
+Retrieve the current user password hash.
+
+@class function
+@name user.getpasswd
+@param username String containing the username to retrieve the password for
+@return String containing the hash or nil if no password is set.
+@return Password database entry
+]]
+
+---[[
+Test whether given string matches the password of a given system user.
+
+@class function
+@name user.checkpasswd
+@param username String containing the Unix user name
+@param pass String containing the password to compare
+@return Boolean indicating wheather the passwords are equal
+]]
+
+---[[
+Change the password of given user.
+
+@class function
+@name user.setpasswd
+@param username String containing the Unix user name
+@param password String containing the password to compare
+@return Number containing 0 on success and >= 1 on error
+]]
+
+---[[
+LuCI system utilities / wifi related functions.
+
+@class module
+@name luci.sys.wifi
+]]
+
+---[[
+Get wireless information for given interface.
+
+@class function
+@name wifi.getiwinfo
+@param ifname String containing the interface name
+@return A wrapped iwinfo object instance
+]]
+
+---[[
+LuCI system utilities / init related functions.
+
+@class module
+@name luci.sys.init
+]]
+
+---[[
+Get the names of all installed init scripts
+
+@class function
+@name init.names
+@return Table containing the names of all inistalled init scripts
+]]
+
+---[[
+Get the index of he given init script
+
+@class function
+@name init.index
+@param name Name of the init script
+@return Numeric index value
+]]
+
+---[[
+Test whether the given init script is enabled
+
+@class function
+@name init.enabled
+@param name Name of the init script
+@return Boolean indicating whether init is enabled
+]]
+
+---[[
+Enable the given init script
+
+@class function
+@name init.enable
+@param name Name of the init script
+@return Boolean indicating success
+]]
+
+---[[
+Disable the given init script
+
+@class function
+@name init.disable
+@param name Name of the init script
+@return Boolean indicating success
+]]
+
+---[[
+Start the given init script
+
+@class function
+@name init.start
+@param name Name of the init script
+@return Boolean indicating success
+]]
+
+---[[
+Stop the given init script
+
+@class function
+@name init.stop
+@param name Name of the init script
+@return Boolean indicating success
+]]
+
diff --git a/modules/luci-base/luasrc/sys/iptparser.lua b/modules/luci-base/luasrc/sys/iptparser.lua
index 6715937c69..2b81e0ee38 100644
--- a/modules/luci-base/luasrc/sys/iptparser.lua
+++ b/modules/luci-base/luasrc/sys/iptparser.lua
@@ -21,15 +21,8 @@ luci.ip = require "luci.ip"
local tonumber, ipairs, table = tonumber, ipairs, table
---- LuCI iptables parser and query library
--- @cstyle instance
module("luci.sys.iptparser")
---- Create a new iptables parser object.
--- @class function
--- @name IptParser
--- @param family Number specifying the address family. 4 for IPv4, 6 for IPv6
--- @return IptParser instance
IptParser = luci.util.class()
function IptParser.__init__( self, family )
@@ -50,7 +43,6 @@ function IptParser.__init__( self, family )
self:_parse_rules()
end
---- Find all firewall rules that match the given criteria. Expects a table with
-- search criteria as only argument. If args is nil or an empty table then all
-- rules will be returned.
--
@@ -108,8 +100,6 @@ end
-- This will match all rules with target "-j REJECT",
-- protocol "-p tcp" (or "-p all")
-- and the option "--reject-with tcp-reset".
--- @params args Table containing the search arguments (optional)
--- @return Table of matching rule tables
function IptParser.find( self, args )
local args = args or { }
@@ -205,9 +195,7 @@ function IptParser.find( self, args )
end
---- Rebuild the internal lookup table, for example when rules have changed
-- through external commands.
--- @return nothing
function IptParser.resync( self )
self._rules = { }
self._chain = nil
@@ -215,16 +203,11 @@ function IptParser.resync( self )
end
---- Find the names of all tables.
--- @return Table of table names.
function IptParser.tables( self )
return self._tables
end
---- Find the names of all chains within the given table name.
--- @param table String containing the table name
--- @return Table of chain names in the order they occur.
function IptParser.chains( self, table )
local lookup = { }
local chains = { }
@@ -238,19 +221,12 @@ function IptParser.chains( self, table )
end
---- Return the given firewall chain within the given table name.
--- @param table String containing the table name
--- @param chain String containing the chain name
--- @return Table containing the fields "policy", "packets", "bytes"
-- and "rules". The "rules" field is a table of rule tables.
function IptParser.chain( self, table, chain )
return self._chains[table:lower()] and self._chains[table:lower()][chain]
end
---- Test whether the given target points to a custom chain.
--- @param target String containing the target action
--- @return Boolean indicating whether target is a custom chain.
function IptParser.is_custom_target( self, target )
for _, r in ipairs(self._rules) do
if r.chain == target then
diff --git a/modules/luci-base/luasrc/sys/iptparser.luadoc b/modules/luci-base/luasrc/sys/iptparser.luadoc
new file mode 100644
index 0000000000..071e7d52e4
--- /dev/null
+++ b/modules/luci-base/luasrc/sys/iptparser.luadoc
@@ -0,0 +1,69 @@
+---[[
+LuCI iptables parser and query library
+
+@cstyle instance
+]]
+module "luci.sys.iptparser"
+
+---[[
+Create a new iptables parser object.
+
+@class function
+@name IptParser
+@param family Number specifying the address family. 4 for IPv4, 6 for IPv6
+@return IptParser instance
+]]
+
+---[[
+Find all firewall rules that match the given criteria. Expects a table with
+
+search criteria as only argument. If args is nil or an empty table then all
+rules will be returned.
+]]
+
+---[[
+Rebuild the internal lookup table, for example when rules have changed
+
+through external commands.
+@class function
+@name IptParser.resync
+@return nothing
+]]
+
+---[[
+Find the names of all tables.
+
+@class function
+@name IptParser.tables
+@return Table of table names.
+]]
+
+---[[
+Find the names of all chains within the given table name.
+
+@class function
+@name IptParser.chains
+@param table String containing the table name
+@return Table of chain names in the order they occur.
+]]
+
+---[[
+Return the given firewall chain within the given table name.
+
+@class function
+@name IptParser.chain
+@param table String containing the table name
+@param chain String containing the chain name
+@return Table containing the fields "policy", "packets", "bytes"
+-- and "rules". The "rules" field is a table of rule tables.
+]]
+
+---[[
+Test whether the given target points to a custom chain.
+
+@class function
+@name IptParser.is_custom_target
+@param target String containing the target action
+@return Boolean indicating whether target is a custom chain.
+]]
+
diff --git a/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua b/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua
index 6337496692..97a3608ea7 100644
--- a/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua
+++ b/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua
@@ -86,7 +86,7 @@ TZ = {
{ 'America/Boise', 'MST7MDT,M3.2.0,M11.1.0' },
{ 'America/Cambridge Bay', 'MST7MDT,M3.2.0,M11.1.0' },
{ 'America/Campo Grande', 'AMT4AMST,M10.3.0/0,M2.3.0/0' },
- { 'America/Cancun', 'CST6CDT,M4.1.0,M10.5.0' },
+ { 'America/Cancun', 'EST5' },
{ 'America/Caracas', 'VET4:30' },
{ 'America/Cayenne', 'GFT3' },
{ 'America/Cayman', 'EST5' },
@@ -178,7 +178,7 @@ TZ = {
{ 'America/Rio Branco', 'ACT5' },
{ 'America/Santa Isabel', 'PST8PDT,M4.1.0,M10.5.0' },
{ 'America/Santarem', 'BRT3' },
- { 'America/Santiago', 'CLT4CLST,M9.1.6/24,M4.4.6/24' },
+ { 'America/Santiago', 'CLT3' },
{ 'America/Santo Domingo', 'AST4' },
{ 'America/Sao Paulo', 'BRT3BRST,M10.3.0/0,M2.3.0/0' },
{ 'America/Scoresbysund', 'EGT1EGST,M3.5.0/0,M10.5.0/1' },
@@ -207,7 +207,7 @@ TZ = {
{ 'Antarctica/Macquarie', 'MIST-11' },
{ 'Antarctica/Mawson', 'MAWT-5' },
{ 'Antarctica/McMurdo', 'NZST-12NZDT,M9.5.0,M4.1.0/3' },
- { 'Antarctica/Palmer', 'CLT4CLST,M9.1.6/24,M4.4.6/24' },
+ { 'Antarctica/Palmer', 'CLT3' },
{ 'Antarctica/Rothera', 'ROTT3' },
{ 'Antarctica/Syowa', 'SYOT-3' },
{ 'Antarctica/Troll', 'UTC0CEST-2,M3.5.0/1,M10.5.0/3' },
@@ -384,7 +384,7 @@ TZ = {
{ 'Pacific/Bougainville', 'BST-11' },
{ 'Pacific/Chatham', 'CHAST-12:45CHADT,M9.5.0/2:45,M4.1.0/3:45' },
{ 'Pacific/Chuuk', 'CHUT-10' },
- { 'Pacific/Easter', 'EAST6EASST,M9.1.6/22,M4.4.6/22' },
+ { 'Pacific/Easter', 'EAST5' },
{ 'Pacific/Efate', 'VUT-11' },
{ 'Pacific/Enderbury', 'PHOT-13' },
{ 'Pacific/Fakaofo', 'TKT-13' },
diff --git a/modules/luci-base/luasrc/sys/zoneinfo/tzoffset.lua b/modules/luci-base/luasrc/sys/zoneinfo/tzoffset.lua
index facfd0c8bf..c8c908b6ea 100644
--- a/modules/luci-base/luasrc/sys/zoneinfo/tzoffset.lua
+++ b/modules/luci-base/luasrc/sys/zoneinfo/tzoffset.lua
@@ -45,8 +45,7 @@ OFFSET = {
uyst = -7200, -- UYST
fnt = -7200, -- FNT
srt = -10800, -- SRT
- clt = -14400, -- CLT
- clst = -10800, -- CLST
+ clt = -10800, -- CLT
egt = -3600, -- EGT
egst = 0, -- EGST
nst = -12600, -- NST
@@ -135,8 +134,7 @@ OFFSET = {
chast = 45900, -- CHAST
chadt = 49500, -- CHADT
chut = 36000, -- CHUT
- east = -21600, -- EAST
- easst = -18000, -- EASST
+ east = -18000, -- EAST
vut = 39600, -- VUT
phot = 46800, -- PHOT
tkt = 46800, -- TKT
diff --git a/modules/luci-base/luasrc/tools/webadmin.lua b/modules/luci-base/luasrc/tools/webadmin.lua
index 9adac29bfa..8273175de7 100644
--- a/modules/luci-base/luasrc/tools/webadmin.lua
+++ b/modules/luci-base/luasrc/tools/webadmin.lua
@@ -1,11 +1,12 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
--- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
+-- Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
module("luci.tools.webadmin", package.seeall)
-local uci = require("luci.model.uci")
-require("luci.sys")
-require("luci.ip")
+
+local util = require "luci.util"
+local uci = require "luci.model.uci"
+local ip = require "luci.ip"
function byte_format(byte)
local suff = {"B", "KB", "MB", "GB", "TB"}
@@ -47,49 +48,6 @@ function date_format(secs)
end
end
-function network_get_addresses(net)
- local state = uci.cursor_state()
- state:load("network")
- local addr = {}
- local ipv4 = state:get("network", net, "ipaddr")
- local mav4 = state:get("network", net, "netmask")
- local ipv6 = state:get("network", net, "ip6addr")
-
- if ipv4 and #ipv4 > 0 then
- if mav4 and #mav4 == 0 then mav4 = nil end
-
- ipv4 = luci.ip.IPv4(ipv4, mav4)
-
- if ipv4 then
- table.insert(addr, ipv4:string())
- end
- end
-
- if ipv6 then
- table.insert(addr, ipv6)
- end
-
- state:foreach("network", "alias",
- function (section)
- if section.interface == net then
- if section.ipaddr and section.netmask then
- local ipv4 = luci.ip.IPv4(section.ipaddr, section.netmask)
-
- if ipv4 then
- table.insert(addr, ipv4:string())
- end
- end
-
- if section.ip6addr then
- table.insert(addr, section.ip6addr)
- end
- end
- end
- )
-
- return addr
-end
-
function cbi_add_networks(field)
uci.cursor():foreach("network", "interface",
function (section)
@@ -102,29 +60,12 @@ function cbi_add_networks(field)
end
function cbi_add_knownips(field)
- for i, dataset in ipairs(luci.sys.net.arptable()) do
- field:value(dataset["IP address"])
- end
-end
-
-function network_get_zones(net)
- local state = uci.cursor_state()
- if not state:load("firewall") then
- return nil
- end
-
- local zones = {}
-
- state:foreach("firewall", "zone",
- function (section)
- local znet = section.network or section.name
- if luci.util.contains(luci.util.split(znet, " "), net) then
- table.insert(zones, section.name)
- end
+ local _, n
+ for _, n in ipairs(ip.neighbors({ family = 4 })) do
+ if n.dest then
+ field:value(n.dest:string())
end
- )
-
- return zones
+ end
end
function firewall_find_zone(name)
@@ -142,21 +83,23 @@ function firewall_find_zone(name)
end
function iface_get_network(iface)
- local state = uci.cursor_state()
- state:load("network")
- local net
-
- state:foreach("network", "interface",
- function (section)
- local ifname = state:get(
- "network", section[".name"], "ifname"
- )
-
- if iface == ifname then
- net = section[".name"]
+ local link = ip.link(tostring(iface))
+ if link.master then
+ iface = link.master
+ end
+
+ local cur = uci.cursor()
+ local dump = util.ubus("network.interface", "dump", { })
+ if dump then
+ local _, net
+ for _, net in ipairs(dump.interface) do
+ if net.l3_device == iface or net.device == iface then
+ -- cross check with uci to filter out @name style aliases
+ local uciname = cur:get("network", net.interface, "ifname")
+ if not uciname or uciname:sub(1, 1) ~= "@" then
+ return net.interface
+ end
end
end
- )
-
- return net
+ end
end
diff --git a/modules/luci-base/luasrc/util.lua b/modules/luci-base/luasrc/util.lua
index 42de3dd729..8b28b1752d 100644
--- a/modules/luci-base/luasrc/util.lua
+++ b/modules/luci-base/luasrc/util.lua
@@ -20,7 +20,6 @@ local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring
local require, pcall, xpcall = require, pcall, xpcall
local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit
---- LuCI utility functions.
module "luci.util"
--
@@ -54,7 +53,6 @@ local function _instantiate(class, ...)
return inst
end
---- Create a Class object (Python-style object model).
-- The class object can be instantiated by calling itself.
-- Any class functions or shared parameters can be attached to this object.
-- Attaching a table to the class object makes this table shared between
@@ -64,10 +62,6 @@ end
-- to the __init__ function of this class - if such a function exists.
-- The __init__ function must be used to set any object parameters that are not shared
-- with other objects of this class. Any return values will be ignored.
--- @param base The base class to inherit from (optional)
--- @return A class object
--- @see instanceof
--- @see clone
function class(base)
return setmetatable({}, {
__call = _instantiate,
@@ -75,12 +69,6 @@ function class(base)
})
end
---- Test whether the given object is an instance of the given class.
--- @param object Object instance
--- @param class Class object to test against
--- @return Boolean indicating whether the object is an instance
--- @see class
--- @see clone
function instanceof(object, class)
local meta = getmetatable(object)
while meta and meta.__index do
@@ -117,10 +105,8 @@ local tl_meta = {
end
}
---- Create a new or get an already existing thread local store associated with
-- the current active coroutine. A thread local store is private a table object
-- whose values can't be accessed from outside of the running coroutine.
--- @return Table value representing the corresponding thread local store
function threadlocal(tbl)
return setmetatable(tbl or {}, tl_meta)
end
@@ -130,17 +116,10 @@ end
-- Debugging routines
--
---- Write given object to stderr.
--- @param obj Value to write to stderr
--- @return Boolean indicating whether the write operation was successful
function perror(obj)
return io.stderr:write(tostring(obj) .. "\n")
end
---- Recursively dumps a table to stdout, useful for testing and debugging.
--- @param t Table value to dump
--- @param maxdepth Maximum depth
--- @return Always nil
function dumptable(t, maxdepth, i, seen)
i = i or 0
seen = seen or setmetatable({}, {__mode="k"})
@@ -163,31 +142,19 @@ end
-- String and data manipulation routines
--
---- Create valid XML PCDATA from given string.
--- @param value String value containing the data to escape
--- @return String value containing the escaped data
function pcdata(value)
return value and tparser.pcdata(tostring(value))
end
---- Strip HTML tags from given string.
--- @param value String containing the HTML text
--- @return String with HTML tags stripped of
function striptags(value)
return value and tparser.striptags(tostring(value))
end
---- Splits given string on a defined separator sequence and return a table
-- containing the resulting substrings. The optional max parameter specifies
-- the number of bytes to process, regardless of the actual length of the given
-- string. The optional last parameter, regex, specifies whether the separator
-- sequence is interpreted as regular expression.
--- @param str String value containing the data to split up
--- @param pat String with separator pattern (optional, defaults to "\n")
--- @param max Maximum times to split (optional)
--- @param regex Boolean indicating whether to interpret the separator
-- pattern as regular expression (optional, default is false)
--- @return Table containing the resulting substrings
function split(str, pat, max, regex)
pat = pat or "\n"
max = max or #str
@@ -221,29 +188,19 @@ function split(str, pat, max, regex)
return t
end
---- Remove leading and trailing whitespace from given string value.
--- @param str String value containing whitespace padded data
--- @return String value with leading and trailing space removed
function trim(str)
return (str:gsub("^%s*(.-)%s*$", "%1"))
end
---- Count the occurences of given substring in given string.
--- @param str String to search in
--- @param pattern String containing pattern to find
--- @return Number of found occurences
function cmatch(str, pat)
local count = 0
for _ in str:gmatch(pat) do count = count + 1 end
return count
end
---- Return a matching iterator for the given value. The iterator will return
-- one token per invocation, the tokens are separated by whitespace. If the
-- input value is a table, it is transformed into a string first. A nil value
-- will result in a valid interator which aborts with the first invocation.
--- @param val The value to scan (table, string or nil)
--- @return Iterator which returns one token per call
function imatch(v)
if type(v) == "table" then
local k = nil
@@ -268,7 +225,6 @@ function imatch(v)
return function() end
end
---- Parse certain units from the given string and return the canonical integer
-- value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
-- Recognized units are:
-- o "y" - one year (60*60*24*366)
@@ -283,8 +239,6 @@ end
-- o "kib" - one si kilobyte (1000)
-- o "mib" - one si megabyte (1000*1000)
-- o "gib" - one si gigabyte (1000*1000*1000)
--- @param ustr String containing a numerical value with trailing unit
--- @return Number containing the canonical value
function parse_units(ustr)
local val = 0
@@ -336,10 +290,6 @@ string.cmatch = cmatch
string.parse_units = parse_units
---- Appends numerically indexed tables or single objects to a given table.
--- @param src Target table
--- @param ... Objects to insert
--- @return Target table
function append(src, ...)
for i, a in ipairs({...}) do
if type(a) == "table" then
@@ -353,19 +303,10 @@ function append(src, ...)
return src
end
---- Combines two or more numerically indexed tables and single objects into one table.
--- @param tbl1 Table value to combine
--- @param tbl2 Table value to combine
--- @param ... More tables to combine
--- @return Table value containing all values of given tables
function combine(...)
return append({}, ...)
end
---- Checks whether the given table contains the given value.
--- @param table Table value
--- @param value Value to search within the given table
--- @return Boolean indicating whether the given value occurs within table
function contains(table, value)
for k, v in pairs(table) do
if value == v then
@@ -375,20 +316,13 @@ function contains(table, value)
return false
end
---- Update values in given table with the values from the second given table.
-- Both table are - in fact - merged together.
--- @param t Table which should be updated
--- @param updates Table containing the values to update
--- @return Always nil
function update(t, updates)
for k, v in pairs(updates) do
t[k] = v
end
end
---- Retrieve all keys of given associative table.
--- @param t Table to extract keys from
--- @return Sorted table containing the keys
function keys(t)
local keys = { }
if t then
@@ -399,10 +333,6 @@ function keys(t)
return keys
end
---- Clones the given object and return it's copy.
--- @param object Table value to clone
--- @param deep Boolean indicating whether to do recursive cloning
--- @return Cloned table value
function clone(object, deep)
local copy = {}
@@ -417,8 +347,6 @@ function clone(object, deep)
end
---- Create a dynamic table which automatically creates subtables.
--- @return Dynamic Table
function dtable()
return setmetatable({}, { __index =
function(tbl, key)
@@ -457,12 +385,7 @@ function _serialize_table(t, seen)
return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data
end
---- Recursively serialize given data to lua code, suitable for restoring
-- with loadstring().
--- @param val Value containing the data to serialize
--- @return String value containing the serialized code
--- @see restore_data
--- @see get_bytecode
function serialize_data(val, seen)
seen = seen or setmetatable({}, {__mode="k"})
@@ -483,11 +406,6 @@ function serialize_data(val, seen)
end
end
---- Restore data previously serialized with serialize_data().
--- @param str String containing the data to restore
--- @return Value containing the restored data structure
--- @see serialize_data
--- @see get_bytecode
function restore_data(str)
return loadstring("return " .. str)()
end
@@ -497,10 +415,7 @@ end
-- Byte code manipulation routines
--
---- Return the current runtime bytecode of the given data. The byte code
-- will be stripped before it is returned.
--- @param val Value to return as bytecode
--- @return String value containing the bytecode of the given data
function get_bytecode(val)
local code
@@ -513,11 +428,8 @@ function get_bytecode(val)
return code -- and strip_bytecode(code)
end
---- Strips unnescessary lua bytecode from given string. Information like line
-- numbers and debugging numbers will be discarded. Original version by
-- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
--- @param code String value containing the original lua byte code
--- @return String value containing the stripped lua byte code
function strip_bytecode(code)
local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12)
local subint
@@ -607,27 +519,17 @@ function _sortiter( t, f )
end
end
---- Return a key, value iterator which returns the values sorted according to
-- the provided callback function.
--- @param t The table to iterate
--- @param f A callback function to decide the order of elements
--- @return Function value containing the corresponding iterator
function spairs(t,f)
return _sortiter( t, f )
end
---- Return a key, value iterator for the given table.
-- The table pairs are sorted by key.
--- @param t The table to iterate
--- @return Function value containing the corresponding iterator
function kspairs(t)
return _sortiter( t )
end
---- Return a key, value iterator for the given table.
-- The table pairs are sorted by value.
--- @param t The table to iterate
--- @return Function value containing the corresponding iterator
function vspairs(t)
return _sortiter( t, function (a,b) return t[a] < t[b] end )
end
@@ -637,15 +539,10 @@ end
-- System utility functions
--
---- Test whether the current system is operating in big endian mode.
--- @return Boolean value indicating whether system is big endian
function bigendian()
return string.byte(string.dump(function() end), 7) == 0
end
---- Execute given commandline and gather stdout.
--- @param command String containing command to execute
--- @return String containing the command's stdout
function exec(command)
local pp = io.popen(command)
local data = pp:read("*a")
@@ -654,9 +551,6 @@ function exec(command)
return data
end
---- Return a line-buffered iterator over the output of given command.
--- @param command String containing the command to execute
--- @return Iterator
function execi(command)
local pp = io.popen(command)
@@ -687,11 +581,6 @@ function execl(command)
return data
end
---- Issue an ubus call.
--- @param object String containing the ubus object to call
--- @param method String containing the ubus method to call
--- @param values Table containing the values to pass
--- @return Table containin the ubus result
function ubus(object, method, data)
if not _ubus_connection then
_ubus_connection = _ubus.connect()
@@ -710,8 +599,60 @@ function ubus(object, method, data)
end
end
---- Returns the absolute path to LuCI base directory.
--- @return String containing the directory path
+function serialize_json(x, cb)
+ local rv, push = nil, cb
+ if not push then
+ rv = { }
+ push = function(tok) rv[#rv+1] = tok end
+ end
+
+ if x == nil then
+ push("null")
+ elseif type(x) == "table" then
+ -- test if table is array like
+ local k, v
+ local n1, n2 = 0, 0
+ for k in pairs(x) do n1 = n1 + 1 end
+ for k in ipairs(x) do n2 = n2 + 1 end
+
+ if n1 == n2 and n1 > 0 then
+ push("[")
+ for k = 1, n2 do
+ if k > 1 then
+ push(",")
+ end
+ serialize_json(x[k], push)
+ end
+ push("]")
+ else
+ push("{")
+ for k, v in pairs(x) do
+ push("%q:" % tostring(k))
+ serialize_json(v, push)
+ if next(x, k) then
+ push(",")
+ end
+ end
+ push("}")
+ end
+ elseif type(x) == "number" or type(x) == "boolean" then
+ if (x ~= x) then
+ -- NaN is the only value that doesn't equal to itself.
+ push("Number.NaN")
+ else
+ push(tostring(x))
+ end
+ else
+ push('"%s"' % tostring(x):gsub('["%z\1-\31]',
+ function(c) return '\\u%04x' % c:byte(1) end))
+ end
+
+ if not cb then
+ return table.concat(rv, "")
+ end
+end
+
+
function libpath()
return require "nixio.fs".dirname(ldebug.__file__)
end
@@ -751,11 +692,6 @@ local function copcall_id(trace, ...)
return ...
end
---- This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function
--- @param f Lua function to be called protected
--- @param err Custom error handler
--- @param ... Parameters passed to the function
--- @return A boolean whether the function call succeeded and the return
-- values of either the function or the error handler
function coxpcall(f, err, ...)
local res, co = oldpcall(coroutine.create, f)
@@ -770,10 +706,6 @@ function coxpcall(f, err, ...)
return performResume(err, co, ...)
end
---- This is a coroutine-safe drop-in replacement for Lua's "pcall"-function
--- @param f Lua function to be called protected
--- @param ... Parameters passed to the function
--- @return A boolean whether the function call succeeded and the returns
-- values of the function or the error object
function copcall(f, ...)
return coxpcall(f, copcall_id, ...)
diff --git a/modules/luci-base/luasrc/util.luadoc b/modules/luci-base/luasrc/util.luadoc
new file mode 100644
index 0000000000..1c09b7a9ab
--- /dev/null
+++ b/modules/luci-base/luasrc/util.luadoc
@@ -0,0 +1,378 @@
+---[[
+LuCI utility functions.
+
+module "luci.util"
+]]
+
+---[[
+Create a Class object (Python-style object model).
+
+The class object can be instantiated by calling itself.
+Any class functions or shared parameters can be attached to this object.
+Attaching a table to the class object makes this table shared between
+all instances of this class. For object parameters use the __init__ function.
+Classes can inherit member functions and values from a base class.
+Class can be instantiated by calling them. All parameters will be passed
+to the __init__ function of this class - if such a function exists.
+The __init__ function must be used to set any object parameters that are not shared
+with other objects of this class. Any return values will be ignored.
+@class function
+@name class
+@param base The base class to inherit from (optional)
+@return A class object
+@see instanceof
+@see clone
+]]
+
+---[[
+Test whether the given object is an instance of the given class.
+
+@class function
+@name instanceof
+@param object Object instance
+@param class Class object to test against
+@return Boolean indicating whether the object is an instance
+@see class
+@see clone
+]]
+
+---[[
+Create a new or get an already existing thread local store associated with
+
+the current active coroutine. A thread local store is private a table object
+whose values can't be accessed from outside of the running coroutine.
+@class function
+@name threadlocal
+@return Table value representing the corresponding thread local store
+]]
+
+---[[
+Write given object to stderr.
+
+@class function
+@name perror
+@param obj Value to write to stderr
+@return Boolean indicating whether the write operation was successful
+]]
+
+---[[
+Recursively dumps a table to stdout, useful for testing and debugging.
+
+@class function
+@name dumptable
+@param t Table value to dump
+@param maxdepth Maximum depth
+@return Always nil
+]]
+
+---[[
+Create valid XML PCDATA from given string.
+
+@class function
+@name pcdata
+@param value String value containing the data to escape
+@return String value containing the escaped data
+]]
+
+---[[
+Strip HTML tags from given string.
+
+@class function
+@name striptags
+@param value String containing the HTML text
+@return String with HTML tags stripped of
+]]
+
+---[[
+Splits given string on a defined separator sequence and return a table
+
+containing the resulting substrings. The optional max parameter specifies
+the number of bytes to process, regardless of the actual length of the given
+string. The optional last parameter, regex, specifies whether the separator
+sequence is interpreted as regular expression.
+@class function
+@name split
+@param str String value containing the data to split up
+@param pat String with separator pattern (optional, defaults to "\n")
+@param max Maximum times to split (optional)
+@param regex Boolean indicating whether to interpret the separator
+-- pattern as regular expression (optional, default is false)
+@return Table containing the resulting substrings
+]]
+
+---[[
+Remove leading and trailing whitespace from given string value.
+
+@class function
+@name trim
+@param str String value containing whitespace padded data
+@return String value with leading and trailing space removed
+]]
+
+---[[
+Count the occurences of given substring in given string.
+
+@class function
+@name cmatch
+@param str String to search in
+@param pattern String containing pattern to find
+@return Number of found occurences
+]]
+
+---[[
+Return a matching iterator for the given value. The iterator will return
+
+one token per invocation, the tokens are separated by whitespace. If the
+input value is a table, it is transformed into a string first. A nil value
+will result in a valid interator which aborts with the first invocation.
+@class function
+@name imatch
+@param val The value to scan (table, string or nil)
+@return Iterator which returns one token per call
+]]
+
+---[[
+Parse certain units from the given string and return the canonical integer
+
+value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
+Recognized units are:
+-- o "y" - one year (60*60*24*366)
+ o "m" - one month (60*60*24*31)
+ o "w" - one week (60*60*24*7)
+ o "d" - one day (60*60*24)
+ o "h" - one hour (60*60)
+ o "min" - one minute (60)
+ o "kb" - one kilobyte (1024)
+ o "mb" - one megabyte (1024*1024)
+ o "gb" - one gigabyte (1024*1024*1024)
+ o "kib" - one si kilobyte (1000)
+ o "mib" - one si megabyte (1000*1000)
+ o "gib" - one si gigabyte (1000*1000*1000)
+@class function
+@name parse_units
+@param ustr String containing a numerical value with trailing unit
+@return Number containing the canonical value
+]]
+
+---[[
+Appends numerically indexed tables or single objects to a given table.
+
+@class function
+@name append
+@param src Target table
+@param ... Objects to insert
+@return Target table
+]]
+
+---[[
+Combines two or more numerically indexed tables and single objects into one table.
+
+@class function
+@name combine
+@param tbl1 Table value to combine
+@param tbl2 Table value to combine
+@param ... More tables to combine
+@return Table value containing all values of given tables
+]]
+
+---[[
+Checks whether the given table contains the given value.
+
+@class function
+@name contains
+@param table Table value
+@param value Value to search within the given table
+@return Boolean indicating whether the given value occurs within table
+]]
+
+---[[
+Update values in given table with the values from the second given table.
+
+Both table are - in fact - merged together.
+@class function
+@name update
+@param t Table which should be updated
+@param updates Table containing the values to update
+@return Always nil
+]]
+
+---[[
+Retrieve all keys of given associative table.
+
+@class function
+@name keys
+@param t Table to extract keys from
+@return Sorted table containing the keys
+]]
+
+---[[
+Clones the given object and return it's copy.
+
+@class function
+@name clone
+@param object Table value to clone
+@param deep Boolean indicating whether to do recursive cloning
+@return Cloned table value
+]]
+
+---[[
+Create a dynamic table which automatically creates subtables.
+
+@class function
+@name dtable
+@return Dynamic Table
+]]
+
+---[[
+Recursively serialize given data to lua code, suitable for restoring
+
+with loadstring().
+@class function
+@name serialize_data
+@param val Value containing the data to serialize
+@return String value containing the serialized code
+@see restore_data
+@see get_bytecode
+]]
+
+---[[
+Restore data previously serialized with serialize_data().
+
+@class function
+@name restore_data
+@param str String containing the data to restore
+@return Value containing the restored data structure
+@see serialize_data
+@see get_bytecode
+]]
+
+---[[
+Return the current runtime bytecode of the given data. The byte code
+
+will be stripped before it is returned.
+@class function
+@name get_bytecode
+@param val Value to return as bytecode
+@return String value containing the bytecode of the given data
+]]
+
+---[[
+Strips unnescessary lua bytecode from given string. Information like line
+
+numbers and debugging numbers will be discarded. Original version by
+Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
+@class function
+@name strip_bytecode
+@param code String value containing the original lua byte code
+@return String value containing the stripped lua byte code
+]]
+
+---[[
+Return a key, value iterator which returns the values sorted according to
+
+the provided callback function.
+@class function
+@name spairs
+@param t The table to iterate
+@param f A callback function to decide the order of elements
+@return Function value containing the corresponding iterator
+]]
+
+---[[
+Return a key, value iterator for the given table.
+
+The table pairs are sorted by key.
+@class function
+@name kspairs
+@param t The table to iterate
+@return Function value containing the corresponding iterator
+]]
+
+---[[
+Return a key, value iterator for the given table.
+
+The table pairs are sorted by value.
+@class function
+@name vspairs
+@param t The table to iterate
+@return Function value containing the corresponding iterator
+]]
+
+---[[
+Test whether the current system is operating in big endian mode.
+
+@class function
+@name bigendian
+@return Boolean value indicating whether system is big endian
+]]
+
+---[[
+Execute given commandline and gather stdout.
+
+@class function
+@name exec
+@param command String containing command to execute
+@return String containing the command's stdout
+]]
+
+---[[
+Return a line-buffered iterator over the output of given command.
+
+@class function
+@name execi
+@param command String containing the command to execute
+@return Iterator
+]]
+
+---[[
+Issue an ubus call.
+
+@class function
+@name ubus
+@param object String containing the ubus object to call
+@param method String containing the ubus method to call
+@param values Table containing the values to pass
+@return Table containin the ubus result
+]]
+
+---[[
+Convert data structure to JSON
+
+@class function
+@name serialize_json
+@param data The data to serialize
+@param writer A function to write a chunk of JSON data (optional)
+@return String containing the JSON if called without write callback
+]]
+
+---[[
+Returns the absolute path to LuCI base directory.
+
+@class function
+@name libpath
+@return String containing the directory path
+]]
+
+---[[
+This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function
+
+@class function
+@name coxpcall
+@param f Lua function to be called protected
+@param err Custom error handler
+@param ... Parameters passed to the function
+@return A boolean whether the function call succeeded and the return
+-- values of either the function or the error handler
+]]
+
+---[[
+This is a coroutine-safe drop-in replacement for Lua's "pcall"-function
+
+@class function
+@name copcall
+@param f Lua function to be called protected
+@param ... Parameters passed to the function
+@return A boolean whether the function call succeeded and the returns
+-- values of the function or the error object
+]]
+
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua
index 055142b53e..52e347d07b 100644
--- a/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua
+++ b/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua
@@ -178,13 +178,7 @@ function action_flashops()
local image_tmp = "/tmp/firmware.img"
local function image_supported()
- -- XXX: yay...
- return ( 0 == os.execute(
- ". /lib/functions.sh; " ..
- "include /lib/upgrade; " ..
- "platform_check_image %q >/dev/null"
- % image_tmp
- ) )
+ return (os.execute("sysupgrade -T %q >/dev/null" % image_tmp) == 0)
end
local function image_checksum()
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua
index 88e81bb18c..997a9274d2 100644
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua
+++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua
@@ -1,7 +1,7 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
-local sys = require "luci.sys"
+local ipc = require "luci.ip"
m = Map("dhcp", translate("DHCP and DNS"),
translate("Dnsmasq is a combined <abbr title=\"Dynamic Host Configuration Protocol" ..
@@ -232,12 +232,11 @@ ip.datatype = "or(ip4addr,'ignore')"
hostid = s:option(Value, "hostid", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Suffix (hex)"))
-sys.net.arptable(function(entry)
- ip:value(entry["IP address"])
- mac:value(
- entry["HW address"],
- entry["HW address"] .. " (" .. entry["IP address"] .. ")"
- )
+ipc.neighbors({ family = 4 }, function(n)
+ if n.mac and n.dest then
+ ip:value(n.dest:string())
+ mac:value(n.mac, "%s (%s)" %{ n.mac, n.dest:string() })
+ end
end)
function ip.validate(self, value, section)
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua
index da7c1181f7..fafacf35c5 100644
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua
+++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua
@@ -1,9 +1,9 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
--- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
+-- Copyright 2010-2015 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
-require("luci.sys")
-require("luci.util")
+local ipc = require "luci.ip"
+
m = Map("dhcp", translate("Hostnames"))
s = m:section(TypedSection, "domain", translate("Host entries"))
@@ -19,12 +19,10 @@ ip = s:option(Value, "ip", translate("IP address"))
ip.datatype = "ipaddr"
ip.rmempty = true
-local arptable = luci.sys.net.arptable() or {}
-for i, dataset in ipairs(arptable) do
- ip:value(
- dataset["IP address"],
- "%s (%s)" %{ dataset["IP address"], dataset["HW address"] }
- )
-end
+ipc.neighbors({ }, function(n)
+ if n.mac and n.dest and not n.dest:is6linklocal() then
+ ip:value(n.dest:string(), "%s (%s)" %{ n.dest:string(), n.mac })
+ end
+end)
return m
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/routes.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/routes.lua
index 01580f1016..ac02b156e9 100644
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/routes.lua
+++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/routes.lua
@@ -1,14 +1,14 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
-require("luci.tools.webadmin")
+local wa = require "luci.tools.webadmin"
+local fs = require "nixio.fs"
+
m = Map("network",
translate("Routes"),
translate("Routes specify over which interface and gateway a certain host or network " ..
"can be reached."))
-local routes6 = luci.sys.net.routes6()
-
s = m:section(TypedSection, "route", translate("Static IPv4 Routes"))
s.addremove = true
s.anonymous = true
@@ -16,7 +16,7 @@ s.anonymous = true
s.template = "cbi/tblsection"
iface = s:option(ListValue, "interface", translate("Interface"))
-luci.tools.webadmin.cbi_add_networks(iface)
+wa.cbi_add_networks(iface)
t = s:option(Value, "target", translate("Target"), translate("Host-<abbr title=\"Internet Protocol Address\">IP</abbr> or Network"))
t.datatype = "ip4addr"
@@ -41,7 +41,7 @@ mtu.placeholder = 1500
mtu.datatype = "range(64,9000)"
mtu.rmempty = true
-if routes6 then
+if fs.access("/proc/net/ipv6_route") then
s = m:section(TypedSection, "route6", translate("Static IPv6 Routes"))
s.addremove = true
s.anonymous = true
@@ -49,7 +49,7 @@ if routes6 then
s.template = "cbi/tblsection"
iface = s:option(ListValue, "interface", translate("Interface"))
- luci.tools.webadmin.cbi_add_networks(iface)
+ wa.cbi_add_networks(iface)
t = s:option(Value, "target", translate("Target"), translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Address or Network (CIDR)"))
t.datatype = "ip6addr"
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview.htm b/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview.htm
index ea60a7f078..b7c44f9073 100644
--- a/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview.htm
+++ b/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview.htm
@@ -1,12 +1,12 @@
<%#
Copyright 2008-2009 Steven Barth <steven@midlink.org>
- Copyright 2008-2013 Jo-Philipp Wich <jow@openwrt.org>
+ Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%-
- local sys = require "luci.sys"
+ local ip = require "luci.ip"
local fs = require "nixio.fs"
local utl = require "luci.util"
local uci = require "luci.model.uci".cursor()
@@ -90,7 +90,9 @@
local devices = ntm:get_wifidevs()
local arpcache = { }
- sys.net.arptable(function(e) arpcache[e["HW address"]:upper()] = e["IP address"] end)
+ ip.neighbors({ family = 4 }, function(n)
+ if n.mac and n.dest then arpcache[n.mac:upper()] = n.dest:string() end
+ end)
local netlist = { }
local netdevs = { }
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm
index 2d9a4a3dc8..82dd3a7dfe 100644
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm
+++ b/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm
@@ -1,15 +1,33 @@
<%#
Copyright 2008-2009 Steven Barth <steven@midlink.org>
- Copyright 2008-2009 Jo-Philipp Wich <jow@openwrt.org>
+ Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%-
- require "luci.sys"
require "luci.tools.webadmin"
require "nixio.fs"
+ local ip = require "luci.ip"
local style = true
+ local _, v
+
+ local rtn = {
+ [255] = "local",
+ [254] = "main",
+ [253] = "default",
+ [0] = "unspec"
+ }
+
+ if nixio.fs.access("/etc/iproute2/rt_tables") then
+ local ln
+ for ln in io.lines("/etc/iproute2/rt_tables") do
+ local i, n = ln:match("^(%d+)%s+(%S+)")
+ if i and n then
+ rtn[tonumber(i)] = n
+ end
+ end
+ end
-%>
<%+header%>
@@ -18,7 +36,7 @@
<h2><a id="content" name="content"><%:Routes%></a></h2>
<div class="cbi-map-descr"><%:The following rules are currently active on this system.%></div>
- <fieldset class="cbi-section" id="cbi-table-table">
+ <fieldset class="cbi-section">
<legend>ARP</legend>
<div class="cbi-section-node">
<table class="cbi-section-table">
@@ -28,19 +46,26 @@
<th class="cbi-section-table-cell"><%:Interface%></th>
</tr>
- <% luci.sys.net.arptable(function(e) %>
+ <%
+ for _, v in ipairs(ip.neighbors({ family = 4 })) do
+ if v.mac then
+ %>
<tr class="cbi-section-table-row cbi-rowstyle-<%=(style and 1 or 2)%>">
- <td class="cbi-value-field"><%=e["IP address"]%></td>
- <td class="cbi-value-field"><%=e["HW address"]%></td>
- <td class="cbi-value-field"><%=e["Device"]%></td>
+ <td class="cbi-value-field"><%=v.dest%></td>
+ <td class="cbi-value-field"><%=v.mac%></td>
+ <td class="cbi-value-field"><%=v.dev%></td>
</tr>
- <% style = not style; end) %>
+ <%
+ style = not style
+ end
+ end
+ %>
</table>
</div>
</fieldset>
<br />
- <fieldset class="cbi-section" id="cbi-table-table">
+ <fieldset class="cbi-section">
<legend><%_Active <abbr title="Internet Protocol Version 4">IPv4</abbr>-Routes%></legend>
<div class="cbi-section-node">
@@ -50,25 +75,27 @@
<th class="cbi-section-table-cell"><%:Target%></th>
<th class="cbi-section-table-cell"><%_<abbr title="Internet Protocol Version 4">IPv4</abbr>-Gateway%></th>
<th class="cbi-section-table-cell"><%:Metric%></th>
+ <th class="cbi-section-table-cell"><%:Table%></th>
</tr>
- <% luci.sys.net.routes(function(rt) %>
+ <% for _, v in ipairs(ip.routes({ family = 4, type = 1 })) do %>
<tr class="cbi-section-table-row cbi-rowstyle-<%=(style and 1 or 2)%>">
- <td class="cbi-value-field"><%=luci.tools.webadmin.iface_get_network(rt.device) or rt.device%></td>
- <td class="cbi-value-field"><%=rt.dest:string()%></td>
- <td class="cbi-value-field"><%=rt.gateway:string()%></td>
- <td class="cbi-value-field"><%=rt.metric%></td>
+ <td class="cbi-value-field"><%=luci.tools.webadmin.iface_get_network(v.dev) or v.dev%></td>
+ <td class="cbi-value-field"><%=v.dest%></td>
+ <td class="cbi-value-field"><%=v.gw%></td>
+ <td class="cbi-value-field"><%=v.metric or 0%></td>
+ <td class="cbi-value-field"><%=rtn[v.table] or v.table%></td>
</tr>
- <% style = not style; end) %>
+ <% style = not style end %>
</table>
</div>
</fieldset>
<br />
- <% if nixio.fs.access("/proc/net/ipv6_route") then
- style = true
- fe80 = luci.ip.IPv6("fe80::/10")
+ <%
+ if nixio.fs.access("/proc/net/ipv6_route") then
+ style = true
%>
- <fieldset class="cbi-section" id="cbi-table-table">
+ <fieldset class="cbi-section">
<legend><%_Active <abbr title="Internet Protocol Version 6">IPv6</abbr>-Routes%></legend>
<div class="cbi-section-node">
@@ -76,17 +103,55 @@
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell"><%:Network%></th>
<th class="cbi-section-table-cell"><%:Target%></th>
- <th class="cbi-section-table-cell"><%_<abbr title="Internet Protocol Version 6">IPv6</abbr>-Gateway%></th>
+ <th class="cbi-section-table-cell"><%:Source%></th>
<th class="cbi-section-table-cell"><%:Metric%></th>
+ <th class="cbi-section-table-cell"><%:Table%></th>
+ </tr>
+ <%
+ for _, v in ipairs(ip.routes({ family = 6, type = 1 })) do
+ if v.dest and not v.dest:is6linklocal() then
+ %>
+ <tr class="cbi-section-table-row cbi-rowstyle-<%=(style and 1 or 2)%>">
+ <td class="cbi-value-field"><%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%></td>
+ <td class="cbi-value-field"><%=v.dest%></td>
+ <td class="cbi-value-field"><%=v.from%></td>
+ <td class="cbi-value-field"><%=v.metric or 0%></td>
+ <td class="cbi-value-field"><%=rtn[v.table] or v.table%></td>
+ </tr>
+ <%
+ style = not style
+ end
+ end
+ %>
+ </table>
+ </div>
+ </fieldset>
+ <br />
+
+ <fieldset class="cbi-section">
+ <legend><%:IPv6 Neighbours%></legend>
+
+ <div class="cbi-section-node">
+ <table class="cbi-section-table">
+ <tr class="cbi-section-table-titles">
+ <th class="cbi-section-table-cell"><%:IPv6-Address%></th>
+ <th class="cbi-section-table-cell"><%:MAC-Address%></th>
+ <th class="cbi-section-table-cell"><%:Interface%></th>
</tr>
- <% luci.sys.net.routes6(function(rt) if fe80:contains(rt.dest) then return end %>
+ <%
+ for _, v in ipairs(ip.neighbors({ family = 6 })) do
+ if v.dest and not v.dest:is6linklocal() and v.mac then
+ %>
<tr class="cbi-section-table-row cbi-rowstyle-<%=(style and 1 or 2)%>">
- <td class="cbi-value-field"><%=luci.tools.webadmin.iface_get_network(rt.device) or '(' .. rt.device .. ')'%></td>
- <td class="cbi-value-field"><%=rt.dest:string()%></td>
- <td class="cbi-value-field"><%=rt.source:string()%></td>
- <td class="cbi-value-field"><%=rt.metric_raw:upper()%></td>
+ <td class="cbi-value-field"><%=v.dest%></td>
+ <td class="cbi-value-field"><%=v.mac%></td>
+ <td class="cbi-value-field"><%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%></td>
</tr>
- <% style = not style; end) %>
+ <%
+ style = not style
+ end
+ end
+ %>
</table>
</div>
</fieldset>
diff --git a/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua b/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua
index 5d3d8ad22a..9a1c1fea45 100644
--- a/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua
+++ b/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua
@@ -3,7 +3,7 @@
-- Licensed to the public under the Apache License 2.0.
local uci = require "luci.model.uci".cursor()
-local sys = require "luci.sys"
+local ipc = require "luci.ip"
local wa = require "luci.tools.webadmin"
local fs = require "nixio.fs"
@@ -86,12 +86,12 @@ s2.template = "cbi/tblsection"
name = s2:option(Value, "name", translate("Hostname"))
mac = s2:option(Value, "mac", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
ip = s2:option(Value, "ip", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
-sys.net.arptable(function(entry)
- ip:value(entry["IP address"])
- mac:value(
- entry["HW address"],
- entry["HW address"] .. " (" .. entry["IP address"] .. ")"
- )
+
+ipc.neighbors({ family = 4 }, function(n)
+ if n.mac and n.dest then
+ ip:value(n.dest:string())
+ mac:value(n.mac, "%s (%s)" %{ n.mac, n.dest:string() })
+ end
end)
return m
diff --git a/modules/luci-mod-freifunk/luasrc/view/freifunk/public_status.htm b/modules/luci-mod-freifunk/luasrc/view/freifunk/public_status.htm
index 715ac756fd..72bd136c5e 100644
--- a/modules/luci-mod-freifunk/luasrc/view/freifunk/public_status.htm
+++ b/modules/luci-mod-freifunk/luasrc/view/freifunk/public_status.htm
@@ -2,6 +2,7 @@
local utl = require "luci.util"
local sys = require "luci.sys"
local twa = require "luci.tools.webadmin"
+local ip = require "luci.ip"
-- System
@@ -48,27 +49,6 @@ for _, dev in ipairs(devices) do
end
local has_iwinfo = pcall(require, "iwinfo")
--- Routes
-local defroutev4 = sys.net.defaultroute()
-local defroutev6 = sys.net.defaultroute6()
-
-if defroutev4 then
- defroutev4.dest = defroutev4.dest:string()
- defroutev4.gateway = defroutev4.gateway:string()
-else
- -- probably policy routing activated, try olsr-default table
- local dr4 = sys.exec("ip r s t olsr-default")
- if dr4 then
- defroutev4 = { }
- defroutev4.dest, defroutev4.gateway, defroutev4.device, defroutev4.metric = dr4:match("^(%w+) via (%d+.%d+.%d+.%d+) dev ([%w-]+) +metric (%d+)")
- end
-end
-
-if defroutev6 then
- defroutev6.dest = defroutev6.dest:string()
- defroutev6.nexthop = defroutev6.nexthop:string()
-end
-
if luci.http.formvalue("status") == "1" then
local rv = { }
for dev in pairs(netdevs) do
@@ -86,22 +66,29 @@ if luci.http.formvalue("status") == "1" then
rv[#rv+1] = j
end
- if defroutev6 then
- def6 = {
- gateway = defroutev6.nexthop,
- dest = defroutev6.dest,
- dev = defroutev6.device,
- metr = defroutev6.metric
+
+ -- Find default routes
+
+ local _, r, def4, def6
+
+ for _, r in ipairs(ip.routes({ type = 1, dest_exact = "0.0.0.0/0" })) do
+ def4 = {
+ gateway = r.gw:string(),
+ dest = r.dest:string(),
+ dev = r.dev,
+ metr = r.metric or 0
}
+ break
end
- if defroutev4 then
- def4 = {
- gateway = defroutev4.gateway,
- dest = defroutev4.dest,
- dev = defroutev4.device,
- metr = defroutev4.metric
+ for _, r in ipairs(ip.routes({ type = 1, dest_exact = "::/0" })) do
+ def6 = {
+ gateway = r.gw:string(),
+ dest = r.dest:string(),
+ dev = r.dev,
+ metr = r.metric or 0
}
+ break
end
rv[#rv+1] = {
diff --git a/protocols/luci-proto-openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua b/protocols/luci-proto-openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua
index e0e63d8631..7b213127f8 100644
--- a/protocols/luci-proto-openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua
+++ b/protocols/luci-proto-openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua
@@ -19,6 +19,9 @@ port = section:taboption("general", Value, "port", translate("VPN Server port"))
port.placeholder = "443"
port.datatype = "port"
+ifname = section:taboption("general", Value, "interface", translate("Output Interface"))
+ifname.template = "cbi/network_netlist"
+
section:taboption("general", Value, "serverhash", translate("VPN Server's certificate SHA1 hash"))
section:taboption("general", Value, "authgroup", translate("AuthGroup"))