summaryrefslogtreecommitdiffhomepage
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/luci-base/Makefile3
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/cbi.js7
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/xhr.js34
-rw-r--r--modules/luci-base/luasrc/cbi/datatypes.lua4
-rw-r--r--modules/luci-base/luasrc/dispatcher.lua65
-rw-r--r--modules/luci-base/luasrc/dispatcher.luadoc11
-rw-r--r--modules/luci-base/luasrc/http.lua368
-rw-r--r--modules/luci-base/luasrc/http.luadoc187
-rw-r--r--modules/luci-base/luasrc/http/protocol.lua649
-rw-r--r--modules/luci-base/luasrc/http/protocol.luadoc142
-rw-r--r--modules/luci-base/luasrc/http/protocol/conditionals.lua110
-rw-r--r--modules/luci-base/luasrc/http/protocol/conditionals.luadoc85
-rw-r--r--modules/luci-base/luasrc/http/protocol/date.lua87
-rw-r--r--modules/luci-base/luasrc/http/protocol/date.luadoc46
-rw-r--r--modules/luci-base/luasrc/http/protocol/mime.lua78
-rw-r--r--modules/luci-base/luasrc/http/protocol/mime.luadoc34
-rw-r--r--modules/luci-base/luasrc/model/ipkg.lua23
-rw-r--r--modules/luci-base/luasrc/model/network.lua2
-rw-r--r--modules/luci-base/luasrc/model/uci.lua501
-rw-r--r--modules/luci-base/luasrc/model/uci.luadoc299
-rw-r--r--modules/luci-base/luasrc/sys.lua23
-rw-r--r--modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua6
-rw-r--r--modules/luci-base/luasrc/tools/status.lua4
-rw-r--r--modules/luci-base/luasrc/util.lua56
-rw-r--r--modules/luci-base/luasrc/util.luadoc389
-rw-r--r--modules/luci-base/luasrc/view/cbi/filebrowser.htm61
-rw-r--r--modules/luci-base/luasrc/view/cbi/simpleform.htm3
-rw-r--r--modules/luci-base/luasrc/view/cbi/tblsection.htm4
-rw-r--r--modules/luci-base/luasrc/view/error404.htm2
-rw-r--r--modules/luci-base/luasrc/view/sysauth.htm2
-rw-r--r--modules/luci-base/po/ca/base.po13
-rw-r--r--modules/luci-base/po/cs/base.po13
-rw-r--r--modules/luci-base/po/de/base.po15
-rw-r--r--modules/luci-base/po/el/base.po13
-rw-r--r--modules/luci-base/po/en/base.po13
-rw-r--r--modules/luci-base/po/es/base.po15
-rw-r--r--modules/luci-base/po/fr/base.po15
-rw-r--r--modules/luci-base/po/he/base.po13
-rw-r--r--modules/luci-base/po/hu/base.po15
-rw-r--r--modules/luci-base/po/it/base.po13
-rw-r--r--modules/luci-base/po/ja/base.po73
-rw-r--r--modules/luci-base/po/ko/base.po13
-rw-r--r--modules/luci-base/po/ms/base.po13
-rw-r--r--modules/luci-base/po/no/base.po15
-rw-r--r--modules/luci-base/po/pl/base.po15
-rw-r--r--modules/luci-base/po/pt-br/base.po15
-rw-r--r--modules/luci-base/po/pt/base.po13
-rw-r--r--modules/luci-base/po/ro/base.po13
-rw-r--r--modules/luci-base/po/ru/base.po15
-rw-r--r--modules/luci-base/po/sk/base.po13
-rw-r--r--modules/luci-base/po/sv/base.po13
-rw-r--r--modules/luci-base/po/templates/base.pot13
-rw-r--r--modules/luci-base/po/tr/base.po13
-rw-r--r--modules/luci-base/po/uk/base.po15
-rw-r--r--modules/luci-base/po/vi/base.po13
-rw-r--r--modules/luci-base/po/zh-cn/base.po16
-rw-r--r--modules/luci-base/po/zh-tw/base.po15
-rw-r--r--modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json11
-rw-r--r--modules/luci-mod-admin-full/luasrc/controller/admin/network.lua23
-rw-r--r--modules/luci-mod-admin-full/luasrc/controller/admin/status.lua10
-rw-r--r--modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua4
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua12
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua3
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua2
-rw-r--r--modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm2
-rw-r--r--modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm4
-rw-r--r--modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm12
-rw-r--r--modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm3
-rw-r--r--modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua2
-rw-r--r--modules/luci-mod-rpc/luasrc/controller/rpc.lua95
70 files changed, 1902 insertions, 2000 deletions
diff --git a/modules/luci-base/Makefile b/modules/luci-base/Makefile
index d3039ef41b..7f7d7e772f 100644
--- a/modules/luci-base/Makefile
+++ b/modules/luci-base/Makefile
@@ -12,8 +12,7 @@ LUCI_TYPE:=mod
LUCI_BASENAME:=base
LUCI_TITLE:=LuCI core libraries
-LUCI_DEPENDS:=+lua +libuci-lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc
-LUCI_EXTRA_DEPENDS:=libuci-lua (>= 2018-01-01)
+LUCI_DEPENDS:=+lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc +liblucihttp-lua
PKG_SOURCE:=LuaSrcDiet-0.12.1.tar.bz2
PKG_SOURCE_URL:=https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/luasrcdiet
diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js
index d40ec34bc6..6c35372cdd 100644
--- a/modules/luci-base/htdocs/luci-static/resources/cbi.js
+++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js
@@ -218,12 +218,13 @@ var cbi_validators = {
((ipv4only == 1) && cbi_validators.ip4addr.apply(this));
},
- 'hostname': function()
+ 'hostname': function(strict)
{
if (this.length <= 253)
- return (this.match(/^[a-zA-Z0-9]+$/) != null ||
+ return (this.match(/^[a-zA-Z0-9_]+$/) != null ||
(this.match(/^[a-zA-Z0-9_][a-zA-Z0-9_\-.]*[a-zA-Z0-9]$/) &&
- this.match(/[^0-9.]/)));
+ this.match(/[^0-9.]/))) &&
+ (!strict || !this.match(/^_/));
return false;
},
diff --git a/modules/luci-base/htdocs/luci-static/resources/xhr.js b/modules/luci-base/htdocs/luci-static/resources/xhr.js
index 3385f8f230..91dcf3fefe 100644
--- a/modules/luci-base/htdocs/luci-static/resources/xhr.js
+++ b/modules/luci-base/htdocs/luci-static/resources/xhr.js
@@ -39,7 +39,7 @@ XHR = function()
this._xmlHttp.abort();
}
- this.get = function(url,data,callback)
+ this.get = function(url,data,callback,timeout)
{
this.reinit();
@@ -54,6 +54,9 @@ XHR = function()
else
url += '?' + code;
+ if (!isNaN(timeout))
+ xhr.timeout = timeout;
+
xhr.open('GET', url, true);
xhr.onreadystatechange = function()
@@ -76,7 +79,7 @@ XHR = function()
xhr.send(null);
}
- this.post = function(url,data,callback)
+ this.post = function(url,data,callback,timeout)
{
this.reinit();
@@ -89,6 +92,9 @@ XHR = function()
callback(xhr);
}
+ if (!isNaN(timeout))
+ xhr.timeout = timeout;
+
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send(code);
@@ -168,7 +174,7 @@ XHR.get = function(url, data, callback)
(new XHR()).get(url, data, callback);
}
-XHR.poll = function(interval, url, data, callback)
+XHR.poll = function(interval, url, data, callback, post)
{
if (isNaN(interval) || interval < 1)
interval = 5;
@@ -181,22 +187,38 @@ XHR.poll = function(interval, url, data, callback)
for (var i = 0, e = XHR._q[0]; i < XHR._q.length; e = XHR._q[++i])
{
if (!(XHR._t % e.interval) && !e.xhr.busy())
- e.xhr.get(e.url, e.data, e.callback);
+ e.xhr[post ? 'post' : 'get'](e.url, e.data, e.callback, e.interval * 1000 - 5);
}
XHR._t++;
};
}
- XHR._q.push({
+ var e = {
interval: interval,
callback: callback,
url: url,
data: data,
xhr: new XHR()
- });
+ };
+ XHR._q.push(e);
XHR.run();
+
+ return e;
+}
+
+XHR.stop = function(e)
+{
+ for (var i = 0; XHR._q && XHR._q[i]; i++) {
+ if (XHR._q[i] === e) {
+ e.xhr.cancel();
+ XHR._q.splice(i, 1);
+ return true;
+ }
+ }
+
+ return false;
}
XHR.halt = function()
diff --git a/modules/luci-base/luasrc/cbi/datatypes.lua b/modules/luci-base/luasrc/cbi/datatypes.lua
index 55cdf8a74b..99113e0b7a 100644
--- a/modules/luci-base/luasrc/cbi/datatypes.lua
+++ b/modules/luci-base/luasrc/cbi/datatypes.lua
@@ -199,13 +199,13 @@ function macaddr(val)
return ip.checkmac(val) and true or false
end
-function hostname(val)
+function hostname(val, strict)
if val and (#val < 254) and (
val:match("^[a-zA-Z_]+$") or
(val:match("^[a-zA-Z0-9_][a-zA-Z0-9_%-%.]*[a-zA-Z0-9]$") and
val:match("[^0-9%.]"))
) then
- return true
+ return (not strict or not val:match("^_"))
end
return false
end
diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua
index 16b32548e6..1984fc4ad2 100644
--- a/modules/luci-base/luasrc/dispatcher.lua
+++ b/modules/luci-base/luasrc/dispatcher.lua
@@ -75,11 +75,16 @@ function error404(message)
http.status(404, "Not Found")
message = message or "Not Found"
- require("luci.template")
- if not util.copcall(luci.template.render, "error404") then
+ local function render()
+ local template = require "luci.template"
+ template.render("error404")
+ end
+
+ if not util.copcall(render) then
http.prepare_content("text/plain")
http.write(message)
end
+
return false
end
@@ -113,7 +118,8 @@ function httpdispatch(request, prefix)
end
end
- for node in pathinfo:gmatch("[^/]+") do
+ local node
+ for node in pathinfo:gmatch("[^/%z]+") do
r[#r+1] = node
end
@@ -136,8 +142,7 @@ local function require_post_security(target)
if (type(required_val) == "string" and
request_val ~= required_val) or
- (required_val == true and
- (request_val == nil or request_val == ""))
+ (required_val == true and request_val == nil)
then
return false
end
@@ -346,15 +351,23 @@ function dispatch(request)
ifattr = function(...) return _ifattr(...) end;
attr = function(...) return _ifattr(true, ...) end;
url = build_url;
- }, {__index=function(table, key)
+ }, {__index=function(tbl, key)
if key == "controller" then
return build_url()
elseif key == "REQUEST_URI" then
return build_url(unpack(ctx.requestpath))
+ elseif key == "FULL_REQUEST_URI" then
+ local url = { http.getenv("SCRIPT_NAME"), http.getenv("PATH_INFO") }
+ local query = http.getenv("QUERY_STRING")
+ if query and #query > 0 then
+ url[#url+1] = "?"
+ url[#url+1] = query
+ end
+ return table.concat(url, "")
elseif key == "token" then
return ctx.authtoken
else
- return rawget(table, key) or _G[key]
+ return rawget(tbl, key) or _G[key]
end
end})
end
@@ -429,6 +442,13 @@ function dispatch(request)
ctx.authuser = sdat.username
end
+ if track.cors and http.getenv("REQUEST_METHOD") == "OPTIONS" then
+ luci.http.status(200, "OK")
+ luci.http.header("Access-Control-Allow-Origin", http.getenv("HTTP_ORIGIN") or "*")
+ luci.http.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
+ return
+ end
+
if c and require_post_security(c.target) then
if not test_post_security(c) then
return
@@ -650,6 +670,23 @@ function node(...)
return c
end
+function lookup(...)
+ local i, path = nil, {}
+ for i = 1, select('#', ...) do
+ local name, arg = nil, tostring(select(i, ...))
+ for name in arg:gmatch("[^/]+") do
+ path[#path+1] = name
+ end
+ end
+
+ for i = #path, 1, -1 do
+ local node = context.treecache[table.concat(path, ".", 1, i)]
+ if node and (i == #path or node.leaf) then
+ return node, build_url(unpack(path))
+ end
+ end
+end
+
function _create_node(path)
if #path == 0 then
return context.tree
@@ -791,7 +828,16 @@ local function _cbi(self, ...)
local state = nil
+ local i, res
for i, res in ipairs(maps) do
+ if util.instanceof(res, cbi.SimpleForm) then
+ io.stderr:write("Model %s returns SimpleForm but is dispatched via cbi(),\n"
+ % self.model)
+
+ io.stderr:write("please change %s to use the form() action instead.\n"
+ % table.concat(context.request, "/"))
+ end
+
res.flow = config
local cstate = res:parse()
if cstate and (not state or cstate < state) then
@@ -884,7 +930,7 @@ end
function cbi(model, config)
return {
type = "cbi",
- post = { ["cbi.submit"] = "1" },
+ post = { ["cbi.submit"] = true },
config = config,
model = model,
target = _cbi
@@ -912,6 +958,7 @@ local function _form(self, ...)
local maps = luci.cbi.load(self.model, ...)
local state = nil
+ local i, res
for i, res in ipairs(maps) do
local cstate = res:parse()
if cstate and (not state or cstate < state) then
@@ -930,7 +977,7 @@ end
function form(model)
return {
type = "cbi",
- post = { ["cbi.submit"] = "1" },
+ post = { ["cbi.submit"] = true },
model = model,
target = _form
}
diff --git a/modules/luci-base/luasrc/dispatcher.luadoc b/modules/luci-base/luasrc/dispatcher.luadoc
index 743463c74f..ddf534b3e1 100644
--- a/modules/luci-base/luasrc/dispatcher.luadoc
+++ b/modules/luci-base/luasrc/dispatcher.luadoc
@@ -116,8 +116,8 @@ Create a new dispatching node and define common parameters.
---[[
Fetch or create a dispatching node without setting the target module or
-
enabling the node.
+
@class function
@name get
@param ... Virtual path
@@ -134,6 +134,15 @@ Fetch or create a new dispatching node.
]]
---[[
+Lookup node in dispatching tree.
+
+@class function
+@name lookup
+@param ... Virtual path
+@return Node object, canonical url or nil if the path was not found.
+]]
+
+---[[
Alias the first (lowest order) page automatically
diff --git a/modules/luci-base/luasrc/http.lua b/modules/luci-base/luasrc/http.lua
index 9cc9857867..16fb04c549 100644
--- a/modules/luci-base/luasrc/http.lua
+++ b/modules/luci-base/luasrc/http.lua
@@ -1,18 +1,21 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
+-- Copyright 2010-2018 Jo-Philipp Wich <jo@mein.io>
-- Licensed to the public under the Apache License 2.0.
-local ltn12 = require "luci.ltn12"
-local protocol = require "luci.http.protocol"
local util = require "luci.util"
-local string = require "string"
local coroutine = require "coroutine"
local table = require "table"
+local lhttp = require "lucihttp"
+local nixio = require "nixio"
+local ltn12 = require "luci.ltn12"
-local ipairs, pairs, next, type, tostring, error =
- ipairs, pairs, next, type, tostring, error
+local table, ipairs, pairs, type, tostring, tonumber, error =
+ table, ipairs, pairs, type, tostring, tonumber, error
module "luci.http"
+HTTP_MAX_CONTENT = 1024*8 -- 8 kB maximum content size
+
context = util.threadlocal()
Request = util.class()
@@ -28,7 +31,7 @@ function Request.__init__(self, env, sourcein, sinkerr)
self.message = {
env = env,
headers = {},
- params = protocol.urldecode_params(env.QUERY_STRING or ""),
+ params = urldecode_params(env.QUERY_STRING or ""),
}
self.parsed_input = false
@@ -73,10 +76,7 @@ function Request.content(self)
end
function Request.getcookie(self, name)
- local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
- local p = ";" .. name .. "=(.-);"
- local i, j, value = c:find(p)
- return value and urldecode(value)
+ return lhttp.header_attribute("cookie; " .. (self:getenv("HTTP_COOKIE") or ""), name)
end
function Request.getenv(self, name)
@@ -90,40 +90,34 @@ end
function Request.setfilehandler(self, callback)
self.filehandler = callback
- -- If input has already been parsed then any files are either in temporary files
- -- or are in self.message.params[key]
- if self.parsed_input then
- for param, value in pairs(self.message.params) do
- repeat
- -- We're only interested in files
- if (not value["file"]) then break end
- -- If we were able to write to temporary file
- if (value["fd"]) then
- fd = value["fd"]
- local eof = false
- repeat
- filedata = fd:read(1024)
- if (filedata:len() < 1024) then
- eof = true
- end
- callback({ name=value["name"], file=value["file"] }, filedata, eof)
- until (eof)
- fd:close()
- value["fd"] = nil
- -- We had to read into memory
- else
- -- There should only be one numbered value in table - the data
- for k, v in ipairs(value) do
- callback({ name=value["name"], file=value["file"] }, v, true)
+ if not self.parsed_input then
+ return
+ end
+
+ -- If input has already been parsed then uploads are stored as unlinked
+ -- temporary files pointed to by open file handles in the parameter
+ -- value table. Loop all params, and invoke the file callback for any
+ -- param with an open file handle.
+ local name, value
+ for name, value in pairs(self.message.params) do
+ if type(value) == "table" then
+ while value.fd do
+ local data = value.fd:read(1024)
+ local eof = (not data or data == "")
+
+ callback(value, data, eof)
+
+ if eof then
+ value.fd:close()
+ value.fd = nil
end
end
- until true
end
end
end
function Request._parse_input(self)
- protocol.parse_message_body(
+ parse_message_body(
self.input,
self.message,
self.filehandler
@@ -254,23 +248,307 @@ function redirect(url)
end
function build_querystring(q)
- local s = { "?" }
+ local s, n, k, v = {}, 1, nil, nil
for k, v in pairs(q) do
- if #s > 1 then s[#s+1] = "&" end
-
- s[#s+1] = urldecode(k)
- s[#s+1] = "="
- s[#s+1] = urldecode(v)
+ s[n+0] = (n == 1) and "?" or "&"
+ s[n+1] = util.urlencode(k)
+ s[n+2] = "="
+ s[n+3] = util.urlencode(v)
+ n = n + 4
end
return table.concat(s, "")
end
-urldecode = protocol.urldecode
+urldecode = util.urldecode
-urlencode = protocol.urlencode
+urlencode = util.urlencode
function write_json(x)
util.serialize_json(x, write)
end
+
+-- 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.
+function urldecode_params(url, tbl)
+ local parser, name
+ local params = tbl or { }
+
+ parser = lhttp.urlencoded_parser(function (what, buffer, length)
+ if what == parser.TUPLE then
+ name, value = nil, nil
+ elseif what == parser.NAME then
+ name = lhttp.urldecode(buffer)
+ elseif what == parser.VALUE and name then
+ params[name] = lhttp.urldecode(buffer) or ""
+ end
+
+ return true
+ end)
+
+ if parser then
+ parser:parse((url or ""):match("[^?]*$"))
+ parser:parse(nil)
+ end
+
+ return params
+end
+
+-- separated by "&". Tables are encoded as parameters with multiple values by
+-- repeating the parameter name with each value.
+function urlencode_params(tbl)
+ local k, v
+ local n, enc = 1, {}
+ for k, v in pairs(tbl) do
+ if type(v) == "table" then
+ local i, v2
+ for i, v2 in ipairs(v) do
+ if enc[1] then
+ enc[n] = "&"
+ n = n + 1
+ end
+
+ enc[n+0] = lhttp.urlencode(k)
+ enc[n+1] = "="
+ enc[n+2] = lhttp.urlencode(v2)
+ n = n + 3
+ end
+ else
+ if enc[1] then
+ enc[n] = "&"
+ n = n + 1
+ end
+
+ enc[n+0] = lhttp.urlencode(k)
+ enc[n+1] = "="
+ enc[n+2] = lhttp.urlencode(v)
+ n = n + 3
+ end
+ end
+
+ return table.concat(enc, "")
+end
+
+-- Content-Type. Stores all extracted data associated with its parameter name
+-- in the params table within 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)
+function mimedecode_message_body(src, msg, file_cb)
+ local parser, header, field
+ local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil)
+
+ parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length)
+ if what == parser.PART_INIT then
+ field = { }
+
+ elseif what == parser.HEADER_NAME then
+ header = buffer:lower()
+
+ elseif what == parser.HEADER_VALUE and header then
+ if header:lower() == "content-disposition" and
+ lhttp.header_attribute(buffer, nil) == "form-data"
+ then
+ field.name = lhttp.header_attribute(buffer, "name")
+ field.file = lhttp.header_attribute(buffer, "filename")
+ field[1] = field.file
+ end
+
+ if field.headers then
+ field.headers[header] = buffer
+ else
+ field.headers = { [header] = buffer }
+ end
+
+ elseif what == parser.PART_BEGIN then
+ return not field.file
+
+ elseif what == parser.PART_DATA and field.name and length > 0 then
+ if field.file then
+ if file_cb then
+ file_cb(field, buffer, false)
+ msg.params[field.name] = msg.params[field.name] or field
+ else
+ if not field.fd then
+ field.fd = nixio.mkstemp(field.name)
+ end
+
+ if field.fd then
+ field.fd:write(buffer)
+ msg.params[field.name] = msg.params[field.name] or field
+ end
+ end
+ else
+ field.value = buffer
+ end
+
+ elseif what == parser.PART_END and field.name then
+ if field.file and msg.params[field.name] then
+ if file_cb then
+ file_cb(field, "", true)
+ elseif field.fd then
+ field.fd:seek(0, "set")
+ end
+ else
+ local val = msg.params[field.name]
+
+ if type(val) == "table" then
+ val[#val+1] = field.value or ""
+ elseif val ~= nil then
+ msg.params[field.name] = { val, field.value or "" }
+ else
+ msg.params[field.name] = field.value or ""
+ end
+ end
+
+ field = nil
+
+ elseif what == parser.ERROR then
+ err = buffer
+ end
+
+ return true
+ end)
+
+ return ltn12.pump.all(src, function (chunk)
+ len = len + (chunk and #chunk or 0)
+
+ if maxlen and len > maxlen + 2 then
+ return nil, "Message body size exceeds Content-Length"
+ end
+
+ if not parser or not parser:parse(chunk) then
+ return nil, err
+ end
+
+ return true
+ end)
+end
+
+-- Content-Type. Stores all extracted data associated with its parameter name
+-- in the params table within the given message object. Multiple parameter
+-- values are stored as tables, ordinary ones as strings.
+function urldecode_message_body(src, msg)
+ local err, name, value, parser
+ local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil)
+
+ parser = lhttp.urlencoded_parser(function (what, buffer, length)
+ if what == parser.TUPLE then
+ name, value = nil, nil
+ elseif what == parser.NAME then
+ name = lhttp.urldecode(buffer, lhttp.DECODE_PLUS)
+ elseif what == parser.VALUE and name then
+ local val = msg.params[name]
+
+ if type(val) == "table" then
+ val[#val+1] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or ""
+ elseif val ~= nil then
+ msg.params[name] = { val, lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" }
+ else
+ msg.params[name] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or ""
+ end
+ elseif what == parser.ERROR then
+ err = buffer
+ end
+
+ return true
+ end)
+
+ return ltn12.pump.all(src, function (chunk)
+ len = len + (chunk and #chunk or 0)
+
+ if maxlen and len > maxlen + 2 then
+ return nil, "Message body size exceeds Content-Length"
+ elseif len > HTTP_MAX_CONTENT then
+ return nil, "Message body size exceeds maximum allowed length"
+ end
+
+ if not parser or not parser:parse(chunk) then
+ return nil, err
+ end
+
+ return true
+ end)
+end
+
+-- 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.
+function parse_message_body(src, msg, filecb)
+ if msg.env.CONTENT_LENGTH or msg.env.REQUEST_METHOD == "POST" then
+ local ctype = lhttp.header_attribute(msg.env.CONTENT_TYPE, nil)
+
+ -- Is it multipart/mime ?
+ if ctype == "multipart/form-data" then
+ return mimedecode_message_body(src, msg, filecb)
+
+ -- Is it application/x-www-form-urlencoded ?
+ elseif ctype == "application/x-www-form-urlencoded" then
+ return urldecode_message_body(src, msg)
+
+ end
+
+ -- Unhandled encoding
+ -- If a file callback is given then feed it chunk by chunk, else
+ -- store whole buffer in message.content
+ local sink
+
+ -- If we have a file callback then feed it
+ if type(filecb) == "function" then
+ local meta = {
+ name = "raw",
+ encoding = msg.env.CONTENT_TYPE
+ }
+ sink = function( chunk )
+ if chunk then
+ return filecb(meta, chunk, false)
+ else
+ return filecb(meta, nil, true)
+ end
+ end
+ -- ... else append to .content
+ else
+ msg.content = ""
+ msg.content_length = 0
+
+ sink = function( chunk )
+ if chunk then
+ if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then
+ msg.content = msg.content .. chunk
+ msg.content_length = msg.content_length + #chunk
+ return true
+ else
+ return nil, "POST data exceeds maximum allowed length"
+ end
+ end
+ return true
+ end
+ end
+
+ -- Pump data...
+ while true do
+ local ok, err = ltn12.pump.step( src, sink )
+
+ if not ok and err then
+ return nil, err
+ elseif not ok then -- eof
+ return true
+ end
+ end
+
+ return true
+ end
+
+ return false
+end
diff --git a/modules/luci-base/luasrc/http.luadoc b/modules/luci-base/luasrc/http.luadoc
index 8a325db21a..f8121230b6 100644
--- a/modules/luci-base/luasrc/http.luadoc
+++ b/modules/luci-base/luasrc/http.luadoc
@@ -6,25 +6,24 @@ module "luci.http"
---[[
Close the HTTP-Connection.
-
-@class function
-@name close
+@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
+@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
+@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
@@ -33,8 +32,8 @@ Get a certain HTTP input value or a table of all input values.
---[[
Get a table of all HTTP input values with a certain prefix.
-@class function
-@name formvaluetable
+@class function
+@name formvaluetable
@param prefix Prefix
@return Table of all HTTP input values with given prefix
]]
@@ -42,18 +41,18 @@ Get a table of all HTTP input values with a certain prefix.
---[[
Get the value of a certain HTTP-Cookie.
-@class function
-@name getcookie
+@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
+
+@class function
+@name getenv
@param name Environment variable
@return HTTP environment value or environment table
]]
@@ -61,41 +60,41 @@ or the environment table itself.
---[[
Set a handler function for incoming user file uploads.
-@class function
-@name setfilehandler
+@class function
+@name setfilehandler
@param callback Handler function
]]
---[[
Send a HTTP-Header.
-@class function
-@name header
-@param key Header key
-@param value Header value
+@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
+@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
+@class function
+@name source
+@return HTTP LTN12 source
]]
---[[
Set the HTTP status code and status message.
-@class function
-@name status
+@class function
+@name status
@param code Status code
@param message Status message
]]
@@ -105,8 +104,9 @@ 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
+
+@class function
+@name write
@param content Content chunk
@param src_err Error object from source (optional)
@see close
@@ -115,51 +115,146 @@ If the content chunk is nil this function will automatically invoke close.
---[[
Splice data from a filedescriptor to the client.
-@class function
-@name splice
-@param fp File descriptor
-@param size Bytes to splice (optional)
+@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
+@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
+@class function
+@name build_querystring
+@param table Query string source table
@return Encoded HTTP query string
]]
---[[
Return the URL-decoded equivalent of a string.
+@class function
+@name urldecode
@param str URL-encoded string
@param no_plus Don't decode + to " "
@return URL-decoded string
-@see urlencode
+@see urlencode
]]
---[[
Return the URL-encoded equivalent of a string.
+@class function
+@name urlencode
@param str Source string
@return URL-encoded string
-@see urldecode
+@see urldecode
]]
---[[
Send the given data as JSON encoded string.
-@class function
-@name write_json
+@class function
+@name write_json
@param data Data to send
]]
+---[[
+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 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
+]]
+
+---[[
+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 within 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 within 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 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
+]]
diff --git a/modules/luci-base/luasrc/http/protocol.lua b/modules/luci-base/luasrc/http/protocol.lua
deleted file mode 100644
index 0a8b2fbab9..0000000000
--- a/modules/luci-base/luasrc/http/protocol.lua
+++ /dev/null
@@ -1,649 +0,0 @@
--- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
--- 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)
-
-local ltn12 = require("luci.ltn12")
-
-HTTP_MAX_CONTENT = 1024*8 -- 8 kB maximum content size
-
--- the "+" sign to " " - and return the decoded string.
-function urldecode( str, no_plus )
-
- local function __chrdec( hex )
- return string.char( tonumber( hex, 16 ) )
- end
-
- if type(str) == "string" then
- if not no_plus then
- str = str:gsub( "+", " " )
- end
-
- str = str:gsub( "%%([a-fA-F0-9][a-fA-F0-9])", __chrdec )
- end
-
- return str
-end
-
--- 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.
-function urldecode_params( url, tbl )
-
- local params = tbl or { }
-
- if url:find("?") then
- url = url:gsub( "^.+%?([^?]+)", "%1" )
- end
-
- for pair in url:gmatch( "[^&;]+" ) do
-
- -- find key and value
- local key = urldecode( pair:match("^([^=]+)") )
- local val = urldecode( pair:match("^[^=]+=(.+)$") )
-
- -- store
- if type(key) == "string" and key:len() > 0 then
- if type(val) ~= "string" then val = "" end
-
- if not params[key] then
- params[key] = val
- elseif type(params[key]) ~= "table" then
- params[key] = { params[key], val }
- else
- table.insert( params[key], val )
- end
- end
- end
-
- return params
-end
-
-function urlencode( str )
-
- local function __chrenc( chr )
- return string.format(
- "%%%02x", string.byte( chr )
- )
- end
-
- if type(str) == "string" then
- str = str:gsub(
- "([^a-zA-Z0-9$_%-%.%~])",
- __chrenc
- )
- end
-
- return str
-end
-
--- separated by "&". Tables are encoded as parameters with multiple values by
--- repeating the parameter name with each value.
-function urlencode_params( tbl )
- local enc = ""
-
- for k, v in pairs(tbl) do
- if type(v) == "table" then
- for i, v2 in ipairs(v) do
- enc = enc .. ( #enc > 0 and "&" or "" ) ..
- urlencode(k) .. "=" .. urlencode(v2)
- end
- else
- enc = enc .. ( #enc > 0 and "&" or "" ) ..
- urlencode(k) .. "=" .. urlencode(v)
- end
- end
-
- return enc
-end
-
--- (Internal function)
--- Initialize given parameter and coerce string into table when the parameter
--- already exists.
-local function __initval( tbl, key )
- if tbl[key] == nil then
- tbl[key] = ""
- elseif type(tbl[key]) == "string" then
- tbl[key] = { tbl[key], "" }
- else
- table.insert( tbl[key], "" )
- end
-end
-
--- (Internal function)
--- Initialize given file parameter.
-local function __initfileval( tbl, key, filename, fd )
- if tbl[key] == nil then
- tbl[key] = { file=filename, fd=fd, name=key, "" }
- else
- table.insert( tbl[key], "" )
- end
-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.
-local function __appendval( tbl, key, chunk )
- if type(tbl[key]) == "table" then
- tbl[key][#tbl[key]] = tbl[key][#tbl[key]] .. chunk
- else
- tbl[key] = tbl[key] .. chunk
- end
-end
-
--- (Internal function)
--- 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.
-local function __finishval( tbl, key, handler )
- if handler then
- if type(tbl[key]) == "table" then
- tbl[key][#tbl[key]] = handler( tbl[key][#tbl[key]] )
- else
- tbl[key] = handler( tbl[key] )
- end
- end
-end
-
-
--- Table of our process states
-local process_states = { }
-
--- Extract "magic", the first line of a http message.
--- Extracts the message type ("get", "post" or "response"), the requested uri
--- or the status code if the line descripes a http response.
-process_states['magic'] = function( msg, chunk, err )
-
- if chunk ~= nil then
- -- ignore empty lines before request
- if #chunk == 0 then
- return true, nil
- end
-
- -- Is it a request?
- local method, uri, http_ver = chunk:match("^([A-Z]+) ([^ ]+) HTTP/([01]%.[019])$")
-
- -- Yup, it is
- if method then
-
- msg.type = "request"
- msg.request_method = method:lower()
- msg.request_uri = uri
- msg.http_version = tonumber( http_ver )
- msg.headers = { }
-
- -- We're done, next state is header parsing
- return true, function( chunk )
- return process_states['headers']( msg, chunk )
- end
-
- -- Is it a response?
- else
-
- local http_ver, code, message = chunk:match("^HTTP/([01]%.[019]) ([0-9]+) ([^\r\n]+)$")
-
- -- Is a response
- if code then
-
- msg.type = "response"
- msg.status_code = code
- msg.status_message = message
- msg.http_version = tonumber( http_ver )
- msg.headers = { }
-
- -- We're done, next state is header parsing
- return true, function( chunk )
- return process_states['headers']( msg, chunk )
- end
- end
- end
- end
-
- -- Can't handle it
- return nil, "Invalid HTTP message magic"
-end
-
-
--- Extract headers from given string.
-process_states['headers'] = function( msg, chunk )
-
- if chunk ~= nil then
-
- -- Look for a valid header format
- local hdr, val = chunk:match( "^([A-Za-z][A-Za-z0-9%-_]+): +(.+)$" )
-
- if type(hdr) == "string" and hdr:len() > 0 and
- type(val) == "string" and val:len() > 0
- then
- msg.headers[hdr] = val
-
- -- Valid header line, proceed
- return true, nil
-
- elseif #chunk == 0 then
- -- Empty line, we won't accept data anymore
- return false, nil
- else
- -- Junk data
- return nil, "Invalid HTTP header received"
- end
- else
- return nil, "Unexpected EOF"
- end
-end
-
-
--- data line by line with the trailing \r\n stripped of.
-function header_source( sock )
- return ltn12.source.simplify( function()
-
- local chunk, err, part = sock:receive("*l")
-
- -- Line too long
- if chunk == nil then
- if err ~= "timeout" then
- return nil, part
- and "Line exceeds maximum allowed length"
- or "Unexpected EOF"
- else
- return nil, err
- end
-
- -- Line ok
- elseif chunk ~= nil then
-
- -- Strip trailing CR
- chunk = chunk:gsub("\r$","")
-
- return chunk, nil
- end
- end )
-end
-
--- Content-Type. Stores all extracted data associated with its parameter name
--- in the params table within 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)
-function mimedecode_message_body( src, msg, filecb )
-
- if msg and msg.env.CONTENT_TYPE then
- msg.mime_boundary = msg.env.CONTENT_TYPE:match("^multipart/form%-data; boundary=(.+)$")
- end
-
- if not msg.mime_boundary then
- return nil, "Invalid Content-Type found"
- end
-
-
- local tlen = 0
- local inhdr = false
- local field = nil
- local store = nil
- local lchunk = nil
-
- local function parse_headers( chunk, field )
-
- local stat
- repeat
- chunk, stat = chunk:gsub(
- "^([A-Z][A-Za-z0-9%-_]+): +([^\r\n]+)\r\n",
- function(k,v)
- field.headers[k] = v
- return ""
- end
- )
- until stat == 0
-
- chunk, stat = chunk:gsub("^\r\n","")
-
- -- End of headers
- if stat > 0 then
- if field.headers["Content-Disposition"] then
- if field.headers["Content-Disposition"]:match("^form%-data; ") then
- field.name = field.headers["Content-Disposition"]:match('name="(.-)"')
- field.file = field.headers["Content-Disposition"]:match('filename="(.+)"$')
- end
- end
-
- if not field.headers["Content-Type"] then
- field.headers["Content-Type"] = "text/plain"
- end
-
- if field.name and field.file and filecb then
- __initval( msg.params, field.name )
- __appendval( msg.params, field.name, field.file )
-
- store = filecb
- elseif field.name and field.file then
- local nxf = require "nixio"
- local fd = nxf.mkstemp(field.name)
- __initfileval ( msg.params, field.name, field.file, fd )
- if fd then
- store = function(hdr, buf, eof)
- fd:write(buf)
- if (eof) then
- fd:seek(0, "set")
- end
- end
- else
- store = function( hdr, buf, eof )
- __appendval( msg.params, field.name, buf )
- end
- end
- elseif field.name then
- __initval( msg.params, field.name )
-
- store = function( hdr, buf, eof )
- __appendval( msg.params, field.name, buf )
- end
- else
- store = nil
- end
-
- return chunk, true
- end
-
- return chunk, false
- end
-
- local function snk( chunk )
-
- tlen = tlen + ( chunk and #chunk or 0 )
-
- if msg.env.CONTENT_LENGTH and tlen > tonumber(msg.env.CONTENT_LENGTH) + 2 then
- return nil, "Message body size exceeds Content-Length"
- end
-
- if chunk and not lchunk then
- lchunk = "\r\n" .. chunk
-
- elseif lchunk then
- local data = lchunk .. ( chunk or "" )
- local spos, epos, found
-
- repeat
- spos, epos = data:find( "\r\n--" .. msg.mime_boundary .. "\r\n", 1, true )
-
- if not spos then
- spos, epos = data:find( "\r\n--" .. msg.mime_boundary .. "--\r\n", 1, true )
- end
-
-
- if spos then
- local predata = data:sub( 1, spos - 1 )
-
- if inhdr then
- predata, eof = parse_headers( predata, field )
-
- if not eof then
- return nil, "Invalid MIME section header"
- elseif not field.name then
- return nil, "Invalid Content-Disposition header"
- end
- end
-
- if store then
- store( field, predata, true )
- end
-
-
- field = { headers = { } }
- found = found or true
-
- data, eof = parse_headers( data:sub( epos + 1, #data ), field )
- inhdr = not eof
- end
- until not spos
-
- if found then
- -- We found at least some boundary. Save
- -- the unparsed remaining data for the
- -- next chunk.
- lchunk, data = data, nil
- else
- -- There was a complete chunk without a boundary. Parse it as headers or
- -- append it as data, depending on our current state.
- if inhdr then
- lchunk, eof = parse_headers( data, field )
- inhdr = not eof
- else
- -- We're inside data, so append the data. Note that we only append
- -- lchunk, not all of data, since there is a chance that chunk
- -- contains half a boundary. Assuming that each chunk is at least the
- -- boundary in size, this should prevent problems
- store( field, lchunk, false )
- lchunk, chunk = chunk, nil
- end
- end
- end
-
- return true
- end
-
- return ltn12.pump.all( src, snk )
-end
-
--- Content-Type. Stores all extracted data associated with its parameter name
--- in the params table within the given message object. Multiple parameter
--- values are stored as tables, ordinary ones as strings.
-function urldecode_message_body( src, msg )
-
- local tlen = 0
- local lchunk = nil
-
- local function snk( chunk )
-
- tlen = tlen + ( chunk and #chunk or 0 )
-
- if msg.env.CONTENT_LENGTH and tlen > tonumber(msg.env.CONTENT_LENGTH) + 2 then
- return nil, "Message body size exceeds Content-Length"
- elseif tlen > HTTP_MAX_CONTENT then
- return nil, "Message body size exceeds maximum allowed length"
- end
-
- if not lchunk and chunk then
- lchunk = chunk
-
- elseif lchunk then
- local data = lchunk .. ( chunk or "&" )
- local spos, epos
-
- repeat
- spos, epos = data:find("^.-[;&]")
-
- if spos then
- local pair = data:sub( spos, epos - 1 )
- local key = pair:match("^(.-)=")
- local val = pair:match("=([^%s]*)%s*$")
-
- if key and #key > 0 then
- __initval( msg.params, key )
- __appendval( msg.params, key, val )
- __finishval( msg.params, key, urldecode )
- end
-
- data = data:sub( epos + 1, #data )
- end
- until not spos
-
- lchunk = data
- end
-
- return true
- end
-
- return ltn12.pump.all( src, snk )
-end
-
--- version, message headers and resulting CGI environment variables from the
--- given ltn12 source.
-function parse_message_header( src )
-
- local ok = true
- local msg = { }
-
- local sink = ltn12.sink.simplify(
- function( chunk )
- return process_states['magic']( msg, chunk )
- end
- )
-
- -- Pump input data...
- while ok do
-
- -- get data
- ok, err = ltn12.pump.step( src, sink )
-
- -- error
- if not ok and err then
- return nil, err
-
- -- eof
- elseif not ok then
-
- -- Process get parameters
- if ( msg.request_method == "get" or msg.request_method == "post" ) and
- msg.request_uri:match("?")
- then
- msg.params = urldecode_params( msg.request_uri )
- else
- msg.params = { }
- end
-
- -- Populate common environment variables
- msg.env = {
- CONTENT_LENGTH = msg.headers['Content-Length'];
- CONTENT_TYPE = msg.headers['Content-Type'] or msg.headers['Content-type'];
- REQUEST_METHOD = msg.request_method:upper();
- REQUEST_URI = msg.request_uri;
- SCRIPT_NAME = msg.request_uri:gsub("?.+$","");
- SCRIPT_FILENAME = ""; -- XXX implement me
- SERVER_PROTOCOL = "HTTP/" .. string.format("%.1f", msg.http_version);
- QUERY_STRING = msg.request_uri:match("?")
- and msg.request_uri:gsub("^.+?","") or ""
- }
-
- -- Populate HTTP_* environment variables
- for i, hdr in ipairs( {
- 'Accept',
- 'Accept-Charset',
- 'Accept-Encoding',
- 'Accept-Language',
- 'Connection',
- 'Cookie',
- 'Host',
- 'Referer',
- 'User-Agent',
- } ) do
- local var = 'HTTP_' .. hdr:upper():gsub("%-","_")
- local val = msg.headers[hdr]
-
- msg.env[var] = val
- end
- end
- end
-
- return msg
-end
-
--- 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.
-function parse_message_body( src, msg, filecb )
- -- Is it multipart/mime ?
- if msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and
- msg.env.CONTENT_TYPE:match("^multipart/form%-data")
- then
-
- return mimedecode_message_body( src, msg, filecb )
-
- -- Is it application/x-www-form-urlencoded ?
- elseif msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and
- msg.env.CONTENT_TYPE:match("^application/x%-www%-form%-urlencoded")
- then
- return urldecode_message_body( src, msg, filecb )
-
-
- -- Unhandled encoding
- -- If a file callback is given then feed it chunk by chunk, else
- -- store whole buffer in message.content
- else
-
- local sink
-
- -- If we have a file callback then feed it
- if type(filecb) == "function" then
- local meta = {
- name = "raw",
- encoding = msg.env.CONTENT_TYPE
- }
- sink = function( chunk )
- if chunk then
- return filecb(meta, chunk, false)
- else
- return filecb(meta, nil, true)
- end
- end
- -- ... else append to .content
- else
- msg.content = ""
- msg.content_length = 0
-
- sink = function( chunk )
- if chunk then
- if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then
- msg.content = msg.content .. chunk
- msg.content_length = msg.content_length + #chunk
- return true
- else
- return nil, "POST data exceeds maximum allowed length"
- end
- end
- return true
- end
- end
-
- -- Pump data...
- while true do
- local ok, err = ltn12.pump.step( src, sink )
-
- if not ok and err then
- return nil, err
- elseif not ok then -- eof
- return true
- end
- end
-
- return true
- end
-end
-
-statusmsg = {
- [200] = "OK",
- [206] = "Partial Content",
- [301] = "Moved Permanently",
- [302] = "Found",
- [304] = "Not Modified",
- [400] = "Bad Request",
- [403] = "Forbidden",
- [404] = "Not Found",
- [405] = "Method Not Allowed",
- [408] = "Request Time-out",
- [411] = "Length Required",
- [412] = "Precondition Failed",
- [416] = "Requested range not satisfiable",
- [500] = "Internal Server Error",
- [503] = "Server Unavailable",
-}
diff --git a/modules/luci-base/luasrc/http/protocol.luadoc b/modules/luci-base/luasrc/http/protocol.luadoc
deleted file mode 100644
index 19a0a3419b..0000000000
--- a/modules/luci-base/luasrc/http/protocol.luadoc
+++ /dev/null
@@ -1,142 +0,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"
-
----[[
-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 within 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 within 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
deleted file mode 100644
index d31a4e38a4..0000000000
--- a/modules/luci-base/luasrc/http/protocol/conditionals.lua
+++ /dev/null
@@ -1,110 +0,0 @@
--- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
--- 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)
-
-local date = require("luci.http.protocol.date")
-
-
-function mk_etag( stat )
- if stat ~= nil then
- return string.format( '"%x-%x-%x"', stat.ino, stat.size, stat.mtime )
- end
-end
-
--- Test whether the given message object contains an "If-Match" header and
--- compare it against the given stat object.
-function if_match( req, stat )
- local h = req.headers
- local etag = mk_etag( stat )
-
- -- Check for matching resource
- if type(h['If-Match']) == "string" then
- for ent in h['If-Match']:gmatch("([^, ]+)") do
- if ( ent == '*' or ent == etag ) and stat ~= nil then
- return true
- end
- end
-
- return false, 412
- end
-
- return true
-end
-
--- Test whether the given message object contains an "If-Modified-Since" header
--- and compare it against the given stat object.
-function if_modified_since( req, stat )
- local h = req.headers
-
- -- Compare mtimes
- if type(h['If-Modified-Since']) == "string" then
- local since = date.to_unix( h['If-Modified-Since'] )
-
- if stat == nil or since < stat.mtime then
- return true
- end
-
- return false, 304, {
- ["ETag"] = mk_etag( stat );
- ["Date"] = date.to_http( os.time() );
- ["Last-Modified"] = date.to_http( stat.mtime )
- }
- end
-
- return true
-end
-
--- Test whether the given message object contains an "If-None-Match" header and
--- compare it against the given stat object.
-function if_none_match( req, stat )
- local h = req.headers
- local etag = mk_etag( stat )
- local method = req.env and req.env.REQUEST_METHOD or "GET"
-
- -- Check for matching resource
- if type(h['If-None-Match']) == "string" then
- for ent in h['If-None-Match']:gmatch("([^, ]+)") do
- if ( ent == '*' or ent == etag ) and stat ~= nil then
- if method == "GET" or method == "HEAD" then
- return false, 304, {
- ["ETag"] = etag;
- ["Date"] = date.to_http( os.time() );
- ["Last-Modified"] = date.to_http( stat.mtime )
- }
- else
- return false, 412
- end
- end
- end
- end
-
- return true
-end
-
--- 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.
-function if_range( req, stat )
- -- Sorry, no subranges (yet)
- return false, 412
-end
-
--- Test whether the given message object contains an "If-Unmodified-Since"
--- header and compare it against the given stat object.
-function if_unmodified_since( req, stat )
- local h = req.headers
-
- -- Compare mtimes
- if type(h['If-Unmodified-Since']) == "string" then
- local since = date.to_unix( h['If-Unmodified-Since'] )
-
- if stat ~= nil and since <= stat.mtime then
- return false, 412
- end
- end
-
- return true
-end
diff --git a/modules/luci-base/luasrc/http/protocol/conditionals.luadoc b/modules/luci-base/luasrc/http/protocol/conditionals.luadoc
deleted file mode 100644
index 9cfe02dd50..0000000000
--- a/modules/luci-base/luasrc/http/protocol/conditionals.luadoc
+++ /dev/null
@@ -1,85 +0,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"
-
----[[
-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
deleted file mode 100644
index e440219a9c..0000000000
--- a/modules/luci-base/luasrc/http/protocol/date.lua
+++ /dev/null
@@ -1,87 +0,0 @@
--- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
--- This class contains functions to parse, compare and format http dates.
-module("luci.http.protocol.date", package.seeall)
-
-require("luci.sys.zoneinfo")
-
-
-MONTHS = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
- "Sep", "Oct", "Nov", "Dec"
-}
-
-function tz_offset(tz)
-
- if type(tz) == "string" then
-
- -- check for a numeric identifier
- local s, v = tz:match("([%+%-])([0-9]+)")
- if s == '+' then s = 1 else s = -1 end
- if v then v = tonumber(v) end
-
- if s and v then
- return s * 60 * ( math.floor( v / 100 ) * 60 + ( v % 100 ) )
-
- -- lookup symbolic tz
- elseif luci.sys.zoneinfo.OFFSET[tz:lower()] then
- return luci.sys.zoneinfo.OFFSET[tz:lower()]
- end
-
- end
-
- -- bad luck
- return 0
-end
-
-function to_unix(date)
-
- local wd, day, mon, yr, hr, min, sec, tz = date:match(
- "([A-Z][a-z][a-z]), ([0-9]+) " ..
- "([A-Z][a-z][a-z]) ([0-9]+) " ..
- "([0-9]+):([0-9]+):([0-9]+) " ..
- "([A-Z0-9%+%-]+)"
- )
-
- if day and mon and yr and hr and min and sec then
- -- find month
- local month = 1
- for i = 1, 12 do
- if MONTHS[i] == mon then
- month = i
- break
- end
- end
-
- -- convert to epoch time
- return tz_offset(tz) + os.time( {
- year = yr,
- month = month,
- day = day,
- hour = hr,
- min = min,
- sec = sec
- } )
- end
-
- return 0
-end
-
-function to_http(time)
- return os.date( "%a, %d %b %Y %H:%M:%S GMT", time )
-end
-
-function compare(d1, d2)
-
- if d1:match("[^0-9]") then d1 = to_unix(d1) end
- if d2:match("[^0-9]") then d2 = to_unix(d2) end
-
- if d1 == d2 then
- return 0
- elseif d1 < d2 then
- return -1
- else
- return 1
- end
-end
diff --git a/modules/luci-base/luasrc/http/protocol/date.luadoc b/modules/luci-base/luasrc/http/protocol/date.luadoc
deleted file mode 100644
index d6f1c8d658..0000000000
--- a/modules/luci-base/luasrc/http/protocol/date.luadoc
+++ /dev/null
@@ -1,46 +0,0 @@
----[[
-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
deleted file mode 100644
index 2b99d8e74e..0000000000
--- a/modules/luci-base/luasrc/http/protocol/mime.lua
+++ /dev/null
@@ -1,78 +0,0 @@
--- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
--- 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_TYPES = {
- ["txt"] = "text/plain";
- ["js"] = "text/javascript";
- ["css"] = "text/css";
- ["htm"] = "text/html";
- ["html"] = "text/html";
- ["patch"] = "text/x-patch";
- ["c"] = "text/x-csrc";
- ["h"] = "text/x-chdr";
- ["o"] = "text/x-object";
- ["ko"] = "text/x-object";
-
- ["bmp"] = "image/bmp";
- ["gif"] = "image/gif";
- ["png"] = "image/png";
- ["jpg"] = "image/jpeg";
- ["jpeg"] = "image/jpeg";
- ["svg"] = "image/svg+xml";
-
- ["zip"] = "application/zip";
- ["pdf"] = "application/pdf";
- ["xml"] = "application/xml";
- ["xsl"] = "application/xml";
- ["doc"] = "application/msword";
- ["ppt"] = "application/vnd.ms-powerpoint";
- ["xls"] = "application/vnd.ms-excel";
- ["odt"] = "application/vnd.oasis.opendocument.text";
- ["odp"] = "application/vnd.oasis.opendocument.presentation";
- ["pl"] = "application/x-perl";
- ["sh"] = "application/x-shellscript";
- ["php"] = "application/x-php";
- ["deb"] = "application/x-deb";
- ["iso"] = "application/x-cd-image";
- ["tgz"] = "application/x-compressed-tar";
-
- ["mp3"] = "audio/mpeg";
- ["ogg"] = "audio/x-vorbis+ogg";
- ["wav"] = "audio/x-wav";
-
- ["mpg"] = "video/mpeg";
- ["mpeg"] = "video/mpeg";
- ["avi"] = "video/x-msvideo";
-}
-
--- "application/octet-stream" if the extension is unknown.
-function to_mime(filename)
- if type(filename) == "string" then
- local ext = filename:match("[^%.]+$")
-
- if ext and MIME_TYPES[ext:lower()] then
- return MIME_TYPES[ext:lower()]
- end
- end
-
- return "application/octet-stream"
-end
-
--- given mime-type is unknown.
-function to_ext(mimetype)
- if type(mimetype) == "string" then
- for ext, type in luci.util.kspairs( MIME_TYPES ) do
- if type == mimetype then
- return ext
- end
- end
- end
-
- return nil
-end
diff --git a/modules/luci-base/luasrc/http/protocol/mime.luadoc b/modules/luci-base/luasrc/http/protocol/mime.luadoc
deleted file mode 100644
index 195b5fcc89..0000000000
--- a/modules/luci-base/luasrc/http/protocol/mime.luadoc
+++ /dev/null
@@ -1,34 +0,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"
-
----[[
-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/model/ipkg.lua b/modules/luci-base/luasrc/model/ipkg.lua
index e653b03465..e27ea52895 100644
--- a/modules/luci-base/luasrc/model/ipkg.lua
+++ b/modules/luci-base/luasrc/model/ipkg.lua
@@ -20,12 +20,14 @@ module "luci.model.ipkg"
-- Internal action function
local function _action(cmd, ...)
- local pkg = ""
+ local cmdline = { ipkg, cmd }
+
+ local k, v
for k, v in pairs({...}) do
- pkg = pkg .. " '" .. v:gsub("'", "") .. "'"
+ cmdline[#cmdline+1] = util.shellquote(v)
end
- local c = "%s %s %s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" %{ ipkg, cmd, pkg }
+ local c = "%s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" % table.concat(cmdline, " ")
local r = os.execute(c)
local e = fs.readfile("/tmp/opkg.stderr")
local o = fs.readfile("/tmp/opkg.stdout")
@@ -74,17 +76,17 @@ local function _parselist(rawdata)
end
-- Internal lookup function
-local function _lookup(act, pkg)
- local cmd = ipkg .. " " .. act
+local function _lookup(cmd, pkg)
+ local cmdline = { ipkg, cmd }
if pkg then
- cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'"
+ cmdline[#cmdline+1] = util.shellquote(pkg)
end
-- OPKG sometimes kills the whole machine because it sucks
-- Therefore we have to use a sucky approach too and use
-- tmpfiles instead of directly reading the output
local tmpfile = os.tmpname()
- os.execute(cmd .. (" >%s 2>/dev/null" % tmpfile))
+ os.execute("%s >%s 2>/dev/null" %{ table.concat(cmdline, " "), tmpfile })
local data = _parselist(io.lines(tmpfile))
os.remove(tmpfile)
@@ -123,9 +125,12 @@ end
-- List helper
local function _list(action, pat, cb)
- local fd = io.popen(ipkg .. " " .. action ..
- (pat and (" '%s'" % pat:gsub("'", "")) or ""))
+ local cmdline = { ipkg, action }
+ if pat then
+ cmdline[#cmdline+1] = util.shellquote(pat)
+ end
+ local fd = io.popen(table.concat(cmdline, " "))
if fd then
local name, version, sz, desc
while true do
diff --git a/modules/luci-base/luasrc/model/network.lua b/modules/luci-base/luasrc/model/network.lua
index 056fc67b14..dfe818bcc7 100644
--- a/modules/luci-base/luasrc/model/network.lua
+++ b/modules/luci-base/luasrc/model/network.lua
@@ -629,7 +629,7 @@ function get_interface(self, i)
if _interfaces[i] or _wifi_iface(i) then
return interface(i)
else
- local netid = _wifi_netid_by_netname(i)
+ local netid = _wifi_netid_by_sid(i)
return netid and interface(netid)
end
end
diff --git a/modules/luci-base/luasrc/model/uci.lua b/modules/luci-base/luasrc/model/uci.lua
index 577c6cde08..fc2a605b34 100644
--- a/modules/luci-base/luasrc/model/uci.lua
+++ b/modules/luci-base/luasrc/model/uci.lua
@@ -2,13 +2,12 @@
-- Licensed to the public under the Apache License 2.0.
local os = require "os"
-local uci = require "uci"
local util = require "luci.util"
local table = require "table"
local setmetatable, rawget, rawset = setmetatable, rawget, rawset
-local require, getmetatable = require, getmetatable
+local require, getmetatable, assert = require, getmetatable, assert
local error, pairs, ipairs = error, pairs, ipairs
local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack
@@ -20,151 +19,436 @@ local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack
-- reloaded.
module "luci.model.uci"
-cursor = uci.cursor
+local ERRSTR = {
+ "Invalid command",
+ "Invalid argument",
+ "Method not found",
+ "Entry not found",
+ "No data",
+ "Permission denied",
+ "Timeout",
+ "Not supported",
+ "Unknown error",
+ "Connection failed"
+}
+
+local session_id = nil
+
+local function call(cmd, args)
+ if type(args) == "table" and session_id then
+ args.ubus_rpc_session = session_id
+ end
+ return util.ubus("uci", cmd, args)
+end
-APIVERSION = uci.APIVERSION
+
+function cursor()
+ return _M
+end
function cursor_state()
- return cursor(nil, "/var/state")
+ return _M
end
+function substate(self)
+ return self
+end
-inst = cursor()
-inst_state = cursor_state()
-local Cursor = getmetatable(inst)
+function get_confdir(self)
+ return "/etc/config"
+end
-function Cursor.apply(self, configlist, command)
- configlist = self:_affected(configlist)
- if command then
- return { "/sbin/luci-reload", unpack(configlist) }
- else
- return os.execute("/sbin/luci-reload %s >/dev/null 2>&1"
- % table.concat(configlist, " "))
- end
+function get_savedir(self)
+ return "/tmp/.uci"
end
+function get_session_id(self)
+ return session_id
+end
--- returns a boolean whether to delete the current section (optional)
-function Cursor.delete_all(self, config, stype, comparator)
- local del = {}
+function set_confdir(self, directory)
+ return false
+end
- if type(comparator) == "table" then
- local tbl = comparator
- comparator = function(section)
- for k, v in pairs(tbl) do
- if section[k] ~= v then
- return false
+function set_savedir(self, directory)
+ return false
+end
+
+function set_session_id(self, id)
+ session_id = id
+ return true
+end
+
+
+function load(self, config)
+ return true
+end
+
+function save(self, config)
+ return true
+end
+
+function unload(self, config)
+ return true
+end
+
+
+function changes(self, config)
+ local rv = call("changes", { config = config })
+ local res = {}
+
+ if type(rv) == "table" and type(rv.changes) == "table" then
+ local package, changes
+ for package, changes in pairs(rv.changes) do
+ res[package] = {}
+
+ local _, change
+ for _, change in ipairs(changes) do
+ local operation, section, option, value = unpack(change)
+ if option and value and operation ~= "add" then
+ res[package][section] = res[package][section] or { }
+
+ if operation == "list-add" then
+ local v = res[package][section][option]
+ if type(v) == "table" then
+ v[#v+1] = value or ""
+ elseif v ~= nil then
+ res[package][section][option] = { v, value }
+ else
+ res[package][section][option] = { value }
+ end
+ else
+ res[package][section][option] = value or ""
+ end
+ else
+ res[package][section] = res[package][section] or {}
+ res[package][section][".type"] = option or ""
end
end
- return true
end
end
- local function helper (section)
+ return res
+end
+
+
+function revert(self, config)
+ local _, err = call("revert", { config = config })
+ return (err == nil), ERRSTR[err]
+end
+
+function commit(self, config)
+ local _, err = call("commit", { config = config })
+ return (err == nil), ERRSTR[err]
+end
+
+--[[
+function apply(self, configs, command)
+ local _, config
+
+ assert(not command, "Apply command not supported anymore")
- if not comparator or comparator(section) then
- del[#del+1] = section[".name"]
+ if type(configs) == "table" then
+ for _, config in ipairs(configs) do
+ call("service", "event", {
+ type = "config.change",
+ data = { package = config }
+ })
end
end
+end
+]]
+
+
+function foreach(self, config, stype, callback)
+ if type(callback) == "function" then
+ local rv, err = call("get", {
+ config = config,
+ type = stype
+ })
+
+ if type(rv) == "table" and type(rv.values) == "table" then
+ local sections = { }
+ local res = false
+ local index = 1
+
+ local _, section
+ for _, section in pairs(rv.values) do
+ section[".index"] = section[".index"] or index
+ sections[index] = section
+ index = index + 1
+ end
- self:foreach(config, stype, helper)
+ table.sort(sections, function(a, b)
+ return a[".index"] < b[".index"]
+ end)
- for i, j in ipairs(del) do
- self:delete(config, j)
+ for _, section in ipairs(sections) do
+ local continue = callback(section)
+ res = true
+ if continue == false then
+ break
+ end
+ end
+ return res
+ else
+ return false, ERRSTR[err] or "No data"
+ end
+ else
+ return false, "Invalid argument"
end
end
-function Cursor.section(self, config, type, name, values)
- local stat = true
- if name then
- stat = self:set(config, name, type)
+local function _get(self, operation, config, section, option)
+ if section == nil then
+ return nil
+ elseif type(option) == "string" and option:byte(1) ~= 46 then
+ local rv, err = call(operation, {
+ config = config,
+ section = section,
+ option = option
+ })
+
+ if type(rv) == "table" then
+ return rv.value or nil
+ elseif err then
+ return false, ERRSTR[err]
+ else
+ return nil
+ end
+ elseif option == nil then
+ local values = self:get_all(config, section)
+ if values then
+ return values[".type"], values[".name"]
+ else
+ return nil
+ end
else
- name = self:add(config, type)
- stat = name and true
+ return false, "Invalid argument"
end
+end
- if stat and values then
- stat = self:tset(config, name, values)
- end
+function get(self, ...)
+ return _get(self, "get", ...)
+end
- return stat and name
+function get_state(self, ...)
+ return _get(self, "state", ...)
end
-function Cursor.tset(self, config, section, values)
- local stat = true
- for k, v in pairs(values) do
- if k:sub(1, 1) ~= "." then
- stat = stat and self:set(config, section, k, v)
- end
+function get_all(self, config, section)
+ local rv, err = call("get", {
+ config = config,
+ section = section
+ })
+
+ if type(rv) == "table" and type(rv.values) == "table" then
+ return rv.values
+ elseif err then
+ return false, ERRSTR[err]
+ else
+ return nil
end
- return stat
end
-function Cursor.get_bool(self, ...)
+function get_bool(self, ...)
local val = self:get(...)
- return ( val == "1" or val == "true" or val == "yes" or val == "on" )
+ return (val == "1" or val == "true" or val == "yes" or val == "on")
+end
+
+function get_first(self, config, stype, option, default)
+ local rv = default
+
+ self:foreach(config, stype, function(s)
+ local val = not option and s[".name"] or s[option]
+
+ if type(default) == "number" then
+ val = tonumber(val)
+ elseif type(default) == "boolean" then
+ val = (val == "1" or val == "true" or
+ val == "yes" or val == "on")
+ end
+
+ if val ~= nil then
+ rv = val
+ return false
+ end
+ end)
+
+ return rv
end
-function Cursor.get_list(self, config, section, option)
+function get_list(self, config, section, option)
if config and section and option then
local val = self:get(config, section, option)
- return ( type(val) == "table" and val or { val } )
+ return (type(val) == "table" and val or { val })
end
- return {}
+ return { }
end
-function Cursor.get_first(self, conf, stype, opt, def)
- local rv = def
- self:foreach(conf, stype,
- function(s)
- local val = not opt and s['.name'] or s[opt]
+function section(self, config, stype, name, values)
+ local rv, err = call("add", {
+ config = config,
+ type = stype,
+ name = name,
+ values = values
+ })
+
+ if type(rv) == "table" then
+ return rv.section
+ elseif err then
+ return false, ERRSTR[err]
+ else
+ return nil
+ end
+end
- if type(def) == "number" then
- val = tonumber(val)
- elseif type(def) == "boolean" then
- val = (val == "1" or val == "true" or
- val == "yes" or val == "on")
+
+function add(self, config, stype)
+ return self:section(config, stype)
+end
+
+function set(self, config, section, option, value)
+ if value == nil then
+ local sname, err = self:section(config, option, section)
+ return (not not sname), err
+ else
+ local _, err = call("set", {
+ config = config,
+ section = section,
+ values = { [option] = value }
+ })
+ return (err == nil), ERRSTR[err]
+ end
+end
+
+function set_list(self, config, section, option, value)
+ if section == nil or option == nil then
+ return false
+ elseif value == nil or (type(value) == "table" and #value == 0) then
+ return self:delete(config, section, option)
+ elseif type(value) == "table" then
+ return self:set(config, section, option, value)
+ else
+ return self:set(config, section, option, { value })
+ end
+end
+
+function tset(self, config, section, values)
+ local _, err = call("set", {
+ config = config,
+ section = section,
+ values = values
+ })
+ return (err == nil), ERRSTR[err]
+end
+
+function reorder(self, config, section, index)
+ local sections
+
+ if type(section) == "string" and type(index) == "number" then
+ local pos = 0
+
+ sections = { }
+
+ self:foreach(config, nil, function(s)
+ if pos == index then
+ pos = pos + 1
end
- if val ~= nil then
- rv = val
- return false
+ if s[".name"] ~= section then
+ pos = pos + 1
+ sections[pos] = s[".name"]
+ else
+ sections[index + 1] = section
end
end)
+ elseif type(section) == "table" then
+ sections = section
+ else
+ return false, "Invalid argument"
+ end
- return rv
+ local _, err = call("order", {
+ config = config,
+ sections = sections
+ })
+
+ return (err == nil), ERRSTR[err]
end
-function Cursor.set_list(self, config, section, option, value)
- if config and section and option then
- if not value or #value == 0 then
- return self:delete(config, section, option)
+
+function delete(self, config, section, option)
+ local _, err = call("delete", {
+ config = config,
+ section = section,
+ option = option
+ })
+ return (err == nil), ERRSTR[err]
+end
+
+function delete_all(self, config, stype, comparator)
+ local _, err
+ if type(comparator) == "table" then
+ _, err = call("delete", {
+ config = config,
+ type = stype,
+ match = comparator
+ })
+ elseif type(comparator) == "function" then
+ local rv = call("get", {
+ config = config,
+ type = stype
+ })
+
+ if type(rv) == "table" and type(rv.values) == "table" then
+ local sname, section
+ for sname, section in pairs(rv.values) do
+ if comparator(section) then
+ _, err = call("delete", {
+ config = config,
+ section = sname
+ })
+ end
+ end
end
- return self:set(
- config, section, option,
- ( type(value) == "table" and value or { value } )
- )
+ elseif comparator == nil then
+ _, err = call("delete", {
+ config = config,
+ type = stype
+ })
+ else
+ return false, "Invalid argument"
end
- return false
+
+ return (err == nil), ERRSTR[err]
end
--- Return a list of initscripts affected by configuration changes.
-function Cursor._affected(self, configlist)
- configlist = type(configlist) == "table" and configlist or {configlist}
- local c = cursor()
- c:load("ucitrack")
+function apply(self, configlist, command)
+ configlist = self:_affected(configlist)
+ if command then
+ return { "/sbin/luci-reload", unpack(configlist) }
+ else
+ return os.execute("/sbin/luci-reload %s >/dev/null 2>&1"
+ % util.shellquote(table.concat(configlist, " ")))
+ end
+end
+
+-- Return a list of initscripts affected by configuration changes.
+function _affected(self, configlist)
+ configlist = type(configlist) == "table" and configlist or { configlist }
-- Resolve dependencies
- local reloadlist = {}
+ local reloadlist = { }
local function _resolve_deps(name)
- local reload = {name}
- local deps = {}
+ local reload = { name }
+ local deps = { }
- c:foreach("ucitrack", name,
+ self:foreach("ucitrack", name,
function(section)
if section.affects then
for i, aff in ipairs(section.affects) do
@@ -173,7 +457,9 @@ function Cursor._affected(self, configlist)
end
end)
+ local i, dep
for i, dep in ipairs(deps) do
+ local j, add
for j, add in ipairs(_resolve_deps(dep)) do
reload[#reload+1] = add
end
@@ -183,7 +469,9 @@ function Cursor._affected(self, configlist)
end
-- Collect initscripts
+ local j, config
for j, config in ipairs(configlist) do
+ local i, e
for i, e in ipairs(_resolve_deps(config)) do
if not util.contains(reloadlist, e) then
reloadlist[#reloadlist+1] = e
@@ -193,44 +481,3 @@ function Cursor._affected(self, configlist)
return reloadlist
end
-
--- curser, means it the parent unloads or loads configs, the sub state will
--- do so as well.
-function Cursor.substate(self)
- Cursor._substates = Cursor._substates or { }
- Cursor._substates[self] = Cursor._substates[self] or cursor_state()
- return Cursor._substates[self]
-end
-
-local _load = Cursor.load
-function Cursor.load(self, ...)
- if Cursor._substates and Cursor._substates[self] then
- _load(Cursor._substates[self], ...)
- end
- return _load(self, ...)
-end
-
-local _unload = Cursor.unload
-function Cursor.unload(self, ...)
- if Cursor._substates and Cursor._substates[self] then
- _unload(Cursor._substates[self], ...)
- end
- return _unload(self, ...)
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/modules/luci-base/luasrc/model/uci.luadoc b/modules/luci-base/luasrc/model/uci.luadoc
index 49093c7930..ef89d09b9e 100644
--- a/modules/luci-base/luasrc/model/uci.luadoc
+++ b/modules/luci-base/luasrc/model/uci.luadoc
@@ -14,224 +14,226 @@ module "luci.model.uci"
---[[
Create a new UCI-Cursor.
-@class function
-@name cursor
-@return 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
+@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
+@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
+@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)
+@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
+@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
+@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
+@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 table. If the option was not found, you will simply get
--- an empty table.
+@class function
+@name Cursor.get_list
+@param config UCI config
+@param section UCI section name
+@param option UCI option
+@return table. If the option was not found, you will simply get an empty
+ table.
]]
---[[
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
+@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. Setting a list option to an empty list
has the same effect as deleting the option.
-@class function
-@name Cursor.set_list
-@param config UCI config
-@param section UCI section name
-@param option UCI option
-@param value value or table. Raw values will become a single item table.
-@return Boolean whether operation succeeded
+@class function
+@name Cursor.set_list
+@param config UCI config
+@param section UCI section name
+@param option UCI option
+@param value Value or table. Non-table values will be set as single
+ item UCI list.
+@return Boolean whether operation succeeded
]]
---[[
-Create a sub-state of this cursor. The sub-state is tied to the parent
+Create a sub-state of this cursor.
-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
+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
+@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
+@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
+@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
+@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
+@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
+@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
+@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
+@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
+@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
+@class function
+@name Cursor.save
+@param config UCI config
+@return Boolean whether operation succeeded
+@see Cursor.load
+@see Cursor.unload
]]
---[[
@@ -243,57 +245,74 @@ then a named section of the given type is created.
When invoked with four arguments `config`, `sectionname`, `optionname` and
`optionvalue` then the value of the specified option is set to the given value.
-@class function
-@name Cursor.set
-@param config UCI config
-@param section UCI section name
-@param option UCI option or UCI section type
+@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 nothing if you want to create a section
-@return Boolean whether operation succeeded
+@return Boolean whether operation succeeded
]]
---[[
Get the configuration directory.
-@class function
-@name Cursor.get_confdir
-@return 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
+@class function
+@name Cursor.get_savedir
+@return Save directory
+]]
+
+---[[
+Get the effective session ID.
+
+@class function
+@name Cursor.get_session_id
+@return String containing the session ID
]]
---[[
Set the configuration directory.
-@class function
-@name Cursor.set_confdir
+@class function
+@name Cursor.set_confdir
@param directory UCI configuration directory
-@return Boolean whether operation succeeded
+@return Boolean whether operation succeeded
]]
---[[
Set the directory for uncommited changes.
-@class function
-@name Cursor.set_savedir
+@class function
+@name Cursor.set_savedir
@param directory UCI changes directory
-@return Boolean whether operation succeeded
+@return Boolean whether operation succeeded
+]]
+
+---[[
+Set the effective session ID.
+
+@class function
+@name Cursor.set_session_id
+@param id String containing the session ID to set
+@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
+@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 12b20e4c38..823e20770c 100644
--- a/modules/luci-base/luasrc/sys.lua
+++ b/modules/luci-base/luasrc/sys.lua
@@ -87,10 +87,10 @@ end
function httpget(url, stream, target)
if not target then
local source = stream and io.popen or luci.util.exec
- return source("wget -qO- '"..url:gsub("'", "").."'")
+ return source("wget -qO- %s" % luci.util.shellquote(url))
else
- return os.execute("wget -qO '%s' '%s'" %
- {target:gsub("'", ""), url:gsub("'", "")})
+ return os.execute("wget -qO %s %s" %
+ {luci.util.shellquote(target), luci.util.shellquote(url)})
end
end
@@ -443,18 +443,11 @@ function user.checkpasswd(username, pass)
end
function user.setpasswd(username, password)
- if password then
- password = password:gsub("'", [['"'"']])
- end
-
- if username then
- username = username:gsub("'", [['"'"']])
- end
-
- return os.execute(
- "(echo '" .. password .. "'; sleep 1; echo '" .. password .. "') | " ..
- "passwd '" .. username .. "' >/dev/null 2>&1"
- )
+ return os.execute("(echo %s; sleep 1; echo %s) | passwd %s >/dev/null 2>&1" %{
+ luci.util.shellquote(password),
+ luci.util.shellquote(password),
+ luci.util.shellquote(username)
+ })
end
diff --git a/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua b/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua
index 6668dad839..47cb901a5b 100644
--- a/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua
+++ b/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua
@@ -202,7 +202,7 @@ TZ = {
{ 'America/Winnipeg', 'CST6CDT,M3.2.0,M11.1.0' },
{ 'America/Yakutat', 'AKST9AKDT,M3.2.0,M11.1.0' },
{ 'America/Yellowknife', 'MST7MDT,M3.2.0,M11.1.0' },
- { 'Antarctica/Casey', '<+11>-11' },
+ { 'Antarctica/Casey', '<+08>-8' },
{ 'Antarctica/Davis', '<+07>-7' },
{ 'Antarctica/DumontDUrville', '<+10>-10' },
{ 'Antarctica/Macquarie', '<+11>-11' },
@@ -239,8 +239,8 @@ TZ = {
{ 'Asia/Dubai', '<+04>-4' },
{ 'Asia/Dushanbe', '<+05>-5' },
{ 'Asia/Famagusta', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
- { 'Asia/Gaza', 'EET-2EEST,M3.5.6/1,M10.5.6/1' },
- { 'Asia/Hebron', 'EET-2EEST,M3.5.6/1,M10.5.6/1' },
+ { 'Asia/Gaza', 'EET-2EEST,M3.4.6/1,M10.5.6/1' },
+ { 'Asia/Hebron', 'EET-2EEST,M3.4.6/1,M10.5.6/1' },
{ 'Asia/Ho Chi Minh', '<+07>-7' },
{ 'Asia/Hong Kong', 'HKT-8' },
{ 'Asia/Hovd', '<+07>-7' },
diff --git a/modules/luci-base/luasrc/tools/status.lua b/modules/luci-base/luasrc/tools/status.lua
index 5012111815..06a9ad4154 100644
--- a/modules/luci-base/luasrc/tools/status.lua
+++ b/modules/luci-base/luasrc/tools/status.lua
@@ -187,7 +187,9 @@ function switch_status(devs)
local switches = { }
for dev in devs:gmatch("[^%s,]+") do
local ports = { }
- local swc = io.popen("swconfig dev %q show" % dev, "r")
+ local swc = io.popen("swconfig dev %s show"
+ % luci.util.shellquote(dev), "r")
+
if swc then
local l
repeat
diff --git a/modules/luci-base/luasrc/util.lua b/modules/luci-base/luasrc/util.lua
index 0e7334be87..ce42af2fb0 100644
--- a/modules/luci-base/luasrc/util.lua
+++ b/modules/luci-base/luasrc/util.lua
@@ -10,6 +10,7 @@ local string = require "string"
local coroutine = require "coroutine"
local tparser = require "luci.template.parser"
local json = require "luci.jsonc"
+local lhttp = require "lucihttp"
local _ubus = require "ubus"
local _ubus_connection = nil
@@ -160,10 +161,33 @@ function pcdata(value)
return value and tparser.pcdata(tostring(value))
end
+function urlencode(value)
+ if value ~= nil then
+ local str = tostring(value)
+ return lhttp.urlencode(str, lhttp.ENCODE_IF_NEEDED + lhttp.ENCODE_FULL)
+ or str
+ end
+ return nil
+end
+
+function urldecode(value, decode_plus)
+ if value ~= nil then
+ local flag = decode_plus and lhttp.DECODE_PLUS or 0
+ local str = tostring(value)
+ return lhttp.urldecode(str, lhttp.DECODE_IF_NEEDED + flag)
+ or str
+ end
+ return nil
+end
+
function striptags(value)
return value and tparser.striptags(tostring(value))
end
+function shellquote(value)
+ return string.format("'%s'", string.gsub(value or "", "'", "'\\''"))
+end
+
-- for bash, ash and similar shells single-quoted strings are taken
-- literally except for single quotes (which terminate the string)
-- (and the exception noted below for dash (-) at the start of a
@@ -383,16 +407,6 @@ function clone(object, deep)
end
-function dtable()
- return setmetatable({}, { __index =
- function(tbl, key)
- return rawget(tbl, key)
- or rawget(rawset(tbl, key, dtable()), key)
- end
- })
-end
-
-
-- Serialize the contents of a table value.
function _serialize_table(t, seen)
assert(not seen[t], "Recursion detected.")
@@ -617,6 +631,20 @@ function execl(command)
return data
end
+
+local ubus_codes = {
+ "INVALID_COMMAND",
+ "INVALID_ARGUMENT",
+ "METHOD_NOT_FOUND",
+ "NOT_FOUND",
+ "NO_DATA",
+ "PERMISSION_DENIED",
+ "TIMEOUT",
+ "NOT_SUPPORTED",
+ "UNKNOWN_ERROR",
+ "CONNECTION_FAILED"
+}
+
function ubus(object, method, data)
if not _ubus_connection then
_ubus_connection = _ubus.connect()
@@ -627,7 +655,8 @@ function ubus(object, method, data)
if type(data) ~= "table" then
data = { }
end
- return _ubus_connection:call(object, method, data)
+ local rv, err = _ubus_connection:call(object, method, data)
+ return rv, err, ubus_codes[err]
elseif object then
return _ubus_connection:signatures(object)
else
@@ -652,10 +681,11 @@ end
function checklib(fullpathexe, wantedlib)
local fs = require "nixio.fs"
local haveldd = fs.access('/usr/bin/ldd')
- if not haveldd then
+ local haveexe = fs.access(fullpathexe)
+ if not haveldd or not haveexe then
return false
end
- local libs = exec("/usr/bin/ldd " .. fullpathexe)
+ local libs = exec(string.format("/usr/bin/ldd %s", shellquote(fullpathexe)))
if not libs then
return false
end
diff --git a/modules/luci-base/luasrc/util.luadoc b/modules/luci-base/luasrc/util.luadoc
index 949aeb21c0..c4f28d039a 100644
--- a/modules/luci-base/luasrc/util.luadoc
+++ b/modules/luci-base/luasrc/util.luadoc
@@ -15,126 +15,164 @@ 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
+
+@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
+@class function
+@name instanceof
+@param object Object instance
@param class Class object to test against
-@return Boolean indicating whether the object is an instance
+@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.
-the current active coroutine. A thread local store is private a table object
+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
+
+@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
+@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
+@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
+@class function
+@name pcdata
+@param value String value containing the data to escape
+@return String value containing the escaped data
+]]
+
+---[[
+Decode an URL-encoded string - optionally decoding the "+" sign to space.
+
+@class function
+@name urldecode
+@param str Input string in x-www-urlencoded format
+@param decode_plus Decode "+" signs to spaces if true (optional)
+@return The decoded string
+@see urlencode
+]]
+
+---[[
+URL-encode given string.
+
+@class function
+@name urlencode
+@param str String to encode
+@return String containing the encoded data
+@see urldecode
]]
---[[
Strip HTML tags from given string.
-@class function
-@name striptags
-@param value String containing the HTML text
-@return String with HTML tags stripped of
+@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
+Safely quote value for use in shell commands.
+
+@class function
+@name shellquote
+@param value String containing the value to quote
+@return Single-quote enclosed string with embedded quotes escaped
+]]
-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
+---[[
+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
+nterpreted 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
+@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
+@class function
+@name trim
+@param str String value containing whitespace padded data
+@return String value with leading and trailing space removed
]]
---[[
Count the occurrences 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 occurrences
+@class function
+@name cmatch
+@param str String to search in
+@param pattern String containing pattern to find
+@return Number of found occurrences
]]
---[[
-Return a matching iterator for the given value. The iterator will return
+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.
-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
+@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.
-value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
+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)
@@ -147,232 +185,229 @@ Recognized units are:
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
+
+@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
+@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
+@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 number indicating the first index at which the given value occurs
--- within table or false.
+@class function
+@name contains
+@param table Table value
+@param value Value to search within the given table
+@return Number indicating the first index at which the given value occurs
+-- within table or false.
]]
---[[
Update values in given table with the values from the second given table.
Both table are - in fact - merged together.
-@class function
-@name update
+
+@class function
+@name update
@param t Table which should be updated
-@param updates Table containing the values to update
-@return Always nil
+@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
+@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
+@class function
+@name clone
+@param object Table value to clone
+@param deep Boolean indicating whether to do recursive cloning
+@return Cloned table value
]]
---[[
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
+
+@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
+@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
+
+@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
+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)
-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
+@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
+
+@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
+
+@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
+
+@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
+@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
+@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
+@class function
+@name execi
+@param command String containing the command to execute
+@return Iterator
]]
---[[
Issue an ubus call.
-@class function
-@name ubus
+@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
+@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
+@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
+@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
+@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
+@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-base/luasrc/view/cbi/filebrowser.htm b/modules/luci-base/luasrc/view/cbi/filebrowser.htm
index a79beebba7..806b1b5f40 100644
--- a/modules/luci-base/luasrc/view/cbi/filebrowser.htm
+++ b/modules/luci-base/luasrc/view/cbi/filebrowser.htm
@@ -22,9 +22,9 @@
<script type="text/javascript">
function callback(path) {
if( window.opener ) {
- var input = window.opener.document.getElementById('<%=luci.http.formvalue('field')%>');
+ var input = window.opener.document.getElementById(decodeURIComponent('<%=luci.http.urlencode(luci.http.formvalue('field'))%>'));
if( input ) {
- input.value = path;
+ input.value = decodeURIComponent(path);
window.close();
}
}
@@ -48,33 +48,44 @@
end
end
- local filepath = table.concat( path, '/' )
- local filestat = nixio.fs.stat( filepath )
- local baseurl = luci.dispatcher.build_url('admin', 'filebrowser')
+ local filestat = nixio.fs.stat(table.concat(path, '/'))
+ local baseurl = { 'admin', 'filebrowser' }
if filestat and filestat.type == "reg" then
- table.remove( path, #path )
- filepath = table.concat( path, '/' ) .. '/'
- elseif not ( filestat and filestat.type == "dir" ) then
- path = { '' }
- filepath = '/'
+ path[#path] = ''
+ elseif not (filestat and filestat.type == "dir") then
+ path = { '', '' }
else
- filepath = filepath .. '/'
+ path[#path+1] = ''
end
- local entries = nixio.util.consume((nixio.fs.dir(filepath)))
+ filepath = table.concat(path, '/')
+
+ local entries = {}
+ local _, e
+ for _, e in luci.util.vspairs(nixio.util.consume((nixio.fs.dir(filepath)))) do
+ local p = filepath .. e
+ local s = nixio.fs.stat(p)
+ if s then
+ entries[#entries+1] = {
+ name = e,
+ path = p,
+ type = s.type
+ }
+ end
+ end
-%>
- <div id="path">
+ <div id="path">
Location:
<% for i, dir in ipairs(path) do %>
<% if i == 1 then %>
- <a href="<%=baseurl%>?field=<%=field%>">(root)</a>
+ <a href="<%=url(unpack(baseurl))%>?field=<%=luci.http.urlencode(field)%>">(root)</a>
<% elseif next(path, i) then %>
- <% baseurl = baseurl .. '/' .. dir %>
- / <a href="<%=baseurl%>?field=<%=field%>"><%=dir%></a>
+ <% baseurl[#baseurl+1] = luci.http.urlencode(dir) %>
+ / <a href="<%=url(unpack(baseurl))%>?field=<%=luci.http.urlencode(field)%>"><%=pcdata(dir)%></a>
<% else %>
- <% baseurl = baseurl .. '/' .. dir %>
- / <%=dir%>
+ <% baseurl[#baseurl+1] = luci.http.urlencode(dir) %>
+ / <%=pcdata(dir)%>
<% end %>
<% end %>
</div>
@@ -83,23 +94,17 @@
<div id="listing">
<ul>
- <% for _, e in luci.util.vspairs(entries) do
- local stat = nixio.fs.stat(filepath..e)
- if stat and stat.type == 'dir' then
- -%>
+ <% for _, e in ipairs(entries) do if e.type == 'dir' then -%>
<li class="dir">
<img src="<%=resource%>/cbi/folder.gif" alt="<%:Directory%>" />
- <a href="<%=baseurl%>/<%=e%>?field=<%=field%>"><%=e%>/</a>
+ <a href="<%=url(unpack(baseurl))%>/<%=luci.http.urlencode(e.name)%>?field=<%=luci.http.urlencode(field)%>"><%=pcdata(e.name)%>/</a>
</li>
<% end end -%>
- <% for _, e in luci.util.vspairs(entries) do
- local stat = nixio.fs.stat(filepath..e)
- if stat and stat.type ~= 'dir' then
- -%>
+ <% for _, e in ipairs(entries) do if e.type ~= 'dir' then -%>
<li class="file">
<img src="<%=resource%>/cbi/file.gif" alt="<%:File%>" />
- <a href="#" onclick="callback('<%=filepath..e%>')"><%=e%></a>
+ <a href="#" onclick="callback('<%=luci.http.urlencode(e.path)%>')"><%=pcdata(e.name)%></a>
</li>
<% end end -%>
</ul>
diff --git a/modules/luci-base/luasrc/view/cbi/simpleform.htm b/modules/luci-base/luasrc/view/cbi/simpleform.htm
index 78f5c5a544..3b758d70ee 100644
--- a/modules/luci-base/luasrc/view/cbi/simpleform.htm
+++ b/modules/luci-base/luasrc/view/cbi/simpleform.htm
@@ -52,7 +52,8 @@
<%- if not self.cancel then -%><%-:Cancel-%><%-else-%><%=self.cancel%><%end-%>
" />
<% end %>
- <script type="text/javascript">cbi_d_update();</script>
</div>
</form>
<% end %>
+
+<script type="text/javascript">cbi_init();</script>
diff --git a/modules/luci-base/luasrc/view/cbi/tblsection.htm b/modules/luci-base/luasrc/view/cbi/tblsection.htm
index 26d13f9372..3cb87563f1 100644
--- a/modules/luci-base/luasrc/view/cbi/tblsection.htm
+++ b/modules/luci-base/luasrc/view/cbi/tblsection.htm
@@ -35,7 +35,7 @@ end
<%- else -%>
<th>&#160;</th>
<%- end -%>
- <%- end -%>
+ <%- count = count +1; end -%>
<%- for i, k in pairs(self.children) do if not k.optional then -%>
<th class="cbi-section-table-cell"<%=width(k)%>>
<%- if k.titleref then -%><a title="<%=self.titledesc or translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=k.titleref%>"><%- end -%>
@@ -44,7 +44,7 @@ end
</th>
<%- count = count + 1; end; end; if self.sortable then -%>
<th class="cbi-section-table-cell"><%:Sort%></th>
- <%- end; if self.extedit or self.addremove then -%>
+ <%- count = count + 1; end; if self.extedit or self.addremove then -%>
<th class="cbi-section-table-cell">&#160;</th>
<%- count = count + 1; end -%>
</tr>
diff --git a/modules/luci-base/luasrc/view/error404.htm b/modules/luci-base/luasrc/view/error404.htm
index bc74226830..a762f6038b 100644
--- a/modules/luci-base/luasrc/view/error404.htm
+++ b/modules/luci-base/luasrc/view/error404.htm
@@ -7,5 +7,5 @@
<%+header%>
<h2 name="content">404 <%:Not Found%></h2>
<p><%:Sorry, the object you requested was not found.%></p>
-<tt><%:Unable to dispatch%>: <%=luci.http.request.env.PATH_INFO%></tt>
+<tt><%:Unable to dispatch%>: <%=url(unpack(luci.dispatcher.context.request))%></tt>
<%+footer%>
diff --git a/modules/luci-base/luasrc/view/sysauth.htm b/modules/luci-base/luasrc/view/sysauth.htm
index f6b0f5706a..b3ec9b7617 100644
--- a/modules/luci-base/luasrc/view/sysauth.htm
+++ b/modules/luci-base/luasrc/view/sysauth.htm
@@ -6,7 +6,7 @@
<%+header%>
-<form method="post" action="<%=pcdata(luci.http.getenv("REQUEST_URI"))%>">
+<form method="post" action="<%=pcdata(FULL_REQUEST_URI)%>">
<%- if fuser then %>
<div class="errorbox"><%:Invalid username and/or password! Please try again.%></div>
<% end -%>
diff --git a/modules/luci-base/po/ca/base.po b/modules/luci-base/po/ca/base.po
index a6a8843a74..c413b7172d 100644
--- a/modules/luci-base/po/ca/base.po
+++ b/modules/luci-base/po/ca/base.po
@@ -744,6 +744,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2154,6 +2159,9 @@ msgstr "Avís"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "D'acord"
@@ -2913,6 +2921,9 @@ msgstr "Mida"
msgid "Size (.ipk)"
msgstr "Mida (.ipk)"
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Salta"
@@ -3305,7 +3316,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/cs/base.po b/modules/luci-base/po/cs/base.po
index c69654f1ed..89714cc818 100644
--- a/modules/luci-base/po/cs/base.po
+++ b/modules/luci-base/po/cs/base.po
@@ -738,6 +738,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2162,6 +2167,9 @@ msgstr "Oznámení"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2939,6 +2947,9 @@ msgstr "Velikost"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Přeskočit"
@@ -3347,7 +3358,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/de/base.po b/modules/luci-base/po/de/base.po
index 47472a37cf..fd495b9507 100644
--- a/modules/luci-base/po/de/base.po
+++ b/modules/luci-base/po/de/base.po
@@ -764,6 +764,11 @@ msgid "Custom feeds"
msgstr "Eigene Repositories"
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr "Passt das Verhalten der Geräte-LEDs an - wenn dies möglich ist."
@@ -2228,6 +2233,9 @@ msgstr "Notiz"
msgid "Nslookup"
msgstr "DNS-Auflösung"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -3039,6 +3047,9 @@ msgstr "Größe"
msgid "Size (.ipk)"
msgstr "Größe (.ipk)"
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Überspringen"
@@ -3480,10 +3491,10 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"Dies ist die lokale, vom Broker zugewiesene IPv6-Adresse, sie endet "
-"üblicherweise mit <code>:2</code>"
+"üblicherweise mit <code>...:2/64</code>"
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/po/el/base.po b/modules/luci-base/po/el/base.po
index d0b9e240f6..ad5ed07fb9 100644
--- a/modules/luci-base/po/el/base.po
+++ b/modules/luci-base/po/el/base.po
@@ -747,6 +747,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2170,6 +2175,9 @@ msgstr "Επισήμανση"
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "Εντάξει"
@@ -2931,6 +2939,9 @@ msgstr "Μέγεθος"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Παράκαμψη"
@@ -3307,7 +3318,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/en/base.po b/modules/luci-base/po/en/base.po
index fbaa03b6f0..f629135950 100644
--- a/modules/luci-base/po/en/base.po
+++ b/modules/luci-base/po/en/base.po
@@ -734,6 +734,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2137,6 +2142,9 @@ msgstr ""
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2895,6 +2903,9 @@ msgstr "Size"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Skip"
@@ -3267,7 +3278,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/es/base.po b/modules/luci-base/po/es/base.po
index a92bb43c1b..776f7fb15c 100644
--- a/modules/luci-base/po/es/base.po
+++ b/modules/luci-base/po/es/base.po
@@ -743,6 +743,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2176,6 +2181,9 @@ msgstr "Aviso"
msgid "Nslookup"
msgstr "NSLookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "Aceptar"
@@ -2952,6 +2960,9 @@ msgstr "Tamaño"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Saltar"
@@ -3372,10 +3383,10 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"Esta es la dirección de punto final asignada por el broker del túnel, suele "
-"terminar con <code>:2</code>"
+"terminar con <code>...:2/64</code>"
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/po/fr/base.po b/modules/luci-base/po/fr/base.po
index cba7caca37..9de1687204 100644
--- a/modules/luci-base/po/fr/base.po
+++ b/modules/luci-base/po/fr/base.po
@@ -750,6 +750,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2190,6 +2195,9 @@ msgstr "Note"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2966,6 +2974,9 @@ msgstr "Taille"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Passer au suivant"
@@ -3387,10 +3398,10 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"Il s'agit de l'adresse de l'extrémité locale attribuée par le fournisseur de "
-"tunnels, elle se termine habituellement avec <code>:2</code>"
+"tunnels, elle se termine habituellement avec <code>...:2/64</code>"
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/po/he/base.po b/modules/luci-base/po/he/base.po
index 6d98134a44..8d5daf3890 100644
--- a/modules/luci-base/po/he/base.po
+++ b/modules/luci-base/po/he/base.po
@@ -727,6 +727,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2110,6 +2115,9 @@ msgstr ""
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr ""
@@ -2862,6 +2870,9 @@ msgstr ""
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr ""
@@ -3228,7 +3239,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/hu/base.po b/modules/luci-base/po/hu/base.po
index e7b3a79bc0..5e2ea2b176 100644
--- a/modules/luci-base/po/hu/base.po
+++ b/modules/luci-base/po/hu/base.po
@@ -745,6 +745,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2179,6 +2184,9 @@ msgstr "Megjegyzés"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2957,6 +2965,9 @@ msgstr "Méret"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Ugrás"
@@ -3375,10 +3386,10 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"Ez az alagút közvetítő (tunnel broker) által megadott helyi végpont címe, "
-"általában így végződik: <code>:2</code>"
+"általában így végződik: <code>...:2/64</code>"
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/po/it/base.po b/modules/luci-base/po/it/base.po
index 414fddf39a..6b55e23e22 100644
--- a/modules/luci-base/po/it/base.po
+++ b/modules/luci-base/po/it/base.po
@@ -750,6 +750,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2179,6 +2184,9 @@ msgstr "Notifica"
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2941,6 +2949,9 @@ msgstr "Dimensione"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Salta"
@@ -3335,7 +3346,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/ja/base.po b/modules/luci-base/po/ja/base.po
index c06994002b..b643e8cf5b 100644
--- a/modules/luci-base/po/ja/base.po
+++ b/modules/luci-base/po/ja/base.po
@@ -3,18 +3,18 @@ msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-06-10 03:40+0200\n"
-"PO-Revision-Date: 2017-10-20 13:54+0900\n"
+"PO-Revision-Date: 2018-04-26 00:23+0900\n"
"Last-Translator: INAGAKI Hiroshi <musashino.open@gmail.com>\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 2.0.4\n"
+"X-Generator: Poedit 2.0.7\n"
"Language-Team: \n"
msgid "%.1f dB"
-msgstr ""
+msgstr "%.1f dB"
msgid "%s is untagged in multiple VLANs!"
msgstr "%s は複数のVLANにUntaggedしています!"
@@ -137,7 +137,7 @@ msgid "<abbr title=\"Media Access Control\">MAC</abbr>-Address"
msgstr "<abbr title=\"Media Access Control\">MAC</abbr>-アドレス"
msgid "<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>"
-msgstr ""
+msgstr "<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>"
msgid ""
"<abbr title=\"maximal\">Max.</abbr> <abbr title=\"Dynamic Host Configuration "
@@ -251,6 +251,8 @@ msgstr "追加"
msgid "Add local domain suffix to names served from hosts files"
msgstr ""
+"hosts ファイルにより解決される名前にローカルドメイン サフィックスを付加しま"
+"す。"
msgid "Add new interface..."
msgstr "インターフェースの新規作成..."
@@ -751,6 +753,13 @@ msgid "Custom feeds"
msgstr "カスタム フィード"
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+"カスタム ファイル(証明書, スクリプト)がシステムに残るかもしれません。これを"
+"防ぐには、まず最初に factory-reset を行います。"
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -1254,7 +1263,7 @@ msgid "Force use of NAT-T"
msgstr "NAT-Tの強制使用"
msgid "Form token mismatch"
-msgstr ""
+msgstr "フォーム トークンの不一致"
msgid "Forward DHCP traffic"
msgstr "DHCPトラフィックを転送する"
@@ -1661,7 +1670,7 @@ msgstr ""
"ユーザー名かパスワード、もしくは両方が不正です!もう一度入力してください。"
msgid "Isolate Clients"
-msgstr ""
+msgstr "クライアント間の分離"
msgid ""
"It appears that you are trying to flash an image that does not fit into the "
@@ -1756,6 +1765,8 @@ msgstr "割り当て数"
msgid "Limit DNS service to subnets interfaces on which we are serving DNS."
msgstr ""
+"DNS サービスを、現在 DNS を提供しているサブネットのインターフェースに限定しま"
+"す。"
msgid "Limit listening to these interfaces, and loopback."
msgstr "待ち受けをこれらのインターフェースとループバックに制限します。"
@@ -1840,7 +1851,7 @@ msgid "Local IPv6 address"
msgstr "ローカル IPv6 アドレス"
msgid "Local Service Only"
-msgstr ""
+msgstr "ローカルサービスのみ"
msgid "Local Startup"
msgstr "ローカル スタートアップ"
@@ -1855,6 +1866,8 @@ msgid ""
"Local domain specification. Names matching this domain are never forwarded "
"and are resolved from DHCP or hosts files only"
msgstr ""
+"ローカル ドメインの定義です。このドメインに一致する名前は転送が行われず、 "
+"DHCP または hosts ファイルのみにより解決されます。"
msgid "Local domain suffix appended to DHCP names and hosts file entries"
msgstr ""
@@ -2178,6 +2191,9 @@ msgstr "注意"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2962,6 +2978,9 @@ msgstr "サイズ"
msgid "Size (.ipk)"
msgstr "サイズ (.ipk)"
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "スキップ"
@@ -3085,10 +3104,10 @@ msgid "Submit"
msgstr "送信"
msgid "Suppress logging"
-msgstr ""
+msgstr "ログの抑制"
msgid "Suppress logging of the routine operation of these protocols"
-msgstr ""
+msgstr "これらのプロトコルのルーチン的操作についてのログを抑制します。"
msgid "Swap"
msgstr "スワップ"
@@ -3110,7 +3129,7 @@ msgid ""
msgstr ""
msgid "Switch Port Mask"
-msgstr ""
+msgstr "スイッチポート マスク"
msgid "Switch VLAN"
msgstr ""
@@ -3338,13 +3357,16 @@ msgstr ""
"サービスを有効にするために、管理者パスワードを設定してください。"
msgid "This IPv4 address of the relay"
-msgstr ""
+msgstr "リレーの IPv4 アドレス"
msgid ""
"This file may contain lines like 'server=/domain/1.2.3.4' or "
"'server=1.2.3.4' fordomain-specific or full upstream <abbr title=\"Domain "
"Name System\">DNS</abbr> servers."
msgstr ""
+"このファイルは、特定ドメイン用、または上位 <abbr title=\"Domain Name System"
+"\">DNS</abbr> サーバーのための 'server=/domain/1.2.3.4' や 'server=1.2.3.4' "
+"というような行を含めることができます。"
msgid ""
"This is a list of shell glob patterns for matching files and directories to "
@@ -3369,17 +3391,17 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"プロバイダからアサインされた、ローカルのエンドポイント アドレスです。通常、"
-"<code>:2</code>が終端に設定されます。"
+"<code>...:2/64</code>が終端に設定されます。"
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
"abbr> in the local network"
msgstr ""
-"ローカル ネットワーク内のみの <abbr title=\"Dynamic Host Configuration "
-"Protocol\">DHCP</abbr>として使用する"
+"これはローカル ネットワーク内のみの <abbr title=\"Dynamic Host Configuration "
+"Protocol\">DHCP</abbr> です。"
msgid "This is the plain username for logging into the account"
msgstr ""
@@ -3946,24 +3968,3 @@ msgstr "はい"
msgid "« Back"
msgstr "« 戻る"
-
-#~ msgid "Action"
-#~ msgstr "動作"
-
-#~ msgid "Buttons"
-#~ msgstr "ボタン"
-
-#~ msgid "Handler"
-#~ msgstr "ハンドラ"
-
-#~ msgid "Maximum hold time"
-#~ msgstr "最大保持時間"
-
-#~ msgid "Minimum hold time"
-#~ msgstr "最短保持時間"
-
-#~ msgid "Path to executable which handles the button event"
-#~ msgstr "ボタンイベントをハンドルする実行ファイルのパス"
-
-#~ msgid "This page allows the configuration of custom button actions"
-#~ msgstr "このページでは、ボタンの動作を変更することができます。"
diff --git a/modules/luci-base/po/ko/base.po b/modules/luci-base/po/ko/base.po
index c56c05e2a2..04d3c6a23a 100644
--- a/modules/luci-base/po/ko/base.po
+++ b/modules/luci-base/po/ko/base.po
@@ -732,6 +732,11 @@ msgid "Custom feeds"
msgstr "Custom feed 들"
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2128,6 +2133,9 @@ msgstr ""
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr ""
@@ -2890,6 +2898,9 @@ msgstr "Size"
msgid "Size (.ipk)"
msgstr "크기 (.ipk)"
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr ""
@@ -3270,7 +3281,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/ms/base.po b/modules/luci-base/po/ms/base.po
index ff33243158..b478bd623b 100644
--- a/modules/luci-base/po/ms/base.po
+++ b/modules/luci-base/po/ms/base.po
@@ -712,6 +712,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr "Mengkustomisasi perilaku peranti LED jika mungkin."
@@ -2108,6 +2113,9 @@ msgstr ""
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "Baik"
@@ -2864,6 +2872,9 @@ msgstr "Saiz"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Skip"
@@ -3238,7 +3249,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/no/base.po b/modules/luci-base/po/no/base.po
index f8b40c1e84..502c3b38a8 100644
--- a/modules/luci-base/po/no/base.po
+++ b/modules/luci-base/po/no/base.po
@@ -734,6 +734,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2153,6 +2158,9 @@ msgstr "Merk"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2930,6 +2938,9 @@ msgstr "Størrelse"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Gå videre"
@@ -3343,10 +3354,10 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"Dette er den lokale endepunkt adressen som ble tildelt av tunnel 'broker', "
-"adressen ender vanligvis med <code>:2</code>"
+"adressen ender vanligvis med <code>...:2/64</code>"
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/po/pl/base.po b/modules/luci-base/po/pl/base.po
index 9bc33a46cc..956e566e91 100644
--- a/modules/luci-base/po/pl/base.po
+++ b/modules/luci-base/po/pl/base.po
@@ -752,6 +752,11 @@ msgstr ""
msgid "Custom feeds"
msgstr ""
+msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
# Spacji zabrało i napisy się skleiły
msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
@@ -2198,6 +2203,9 @@ msgstr "Spostrzeżenie"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2978,6 +2986,9 @@ msgstr "Rozmiar"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Pomiń"
@@ -3400,10 +3411,10 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"To jest lokalny adres końcowy przypisany przez tunnel broker'a, zwykle "
-"kończący się z <code>:2</code>"
+"kończący się z <code>...:2/64</code>"
# w tłumaczeniu pojawiła się spacja po DHCP</abbr> co powoduje niepoprawne wyświetlanie się strony z lang PL
msgid ""
diff --git a/modules/luci-base/po/pt-br/base.po b/modules/luci-base/po/pt-br/base.po
index bf0de75dd4..9c4901f3d4 100644
--- a/modules/luci-base/po/pt-br/base.po
+++ b/modules/luci-base/po/pt-br/base.po
@@ -787,6 +787,11 @@ msgid "Custom feeds"
msgstr "Fontes de pacotes customizadas"
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2279,6 +2284,9 @@ msgstr "Aviso"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -3084,6 +3092,9 @@ msgstr "Tamanho"
msgid "Size (.ipk)"
msgstr "Tamanho (.ipk)"
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Pular"
@@ -3519,10 +3530,10 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"Este é o endereço da ponta local designado pelo agente de túnel. normalmente "
-"ele termina com <code>:2</code>"
+"ele termina com <code>...:2/64</code>"
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/po/pt/base.po b/modules/luci-base/po/pt/base.po
index 3109903896..8f2622c26d 100644
--- a/modules/luci-base/po/pt/base.po
+++ b/modules/luci-base/po/pt/base.po
@@ -747,6 +747,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2177,6 +2182,9 @@ msgstr "Reparo"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2948,6 +2956,9 @@ msgstr "Tamanho"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Saltar"
@@ -3347,7 +3358,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/ro/base.po b/modules/luci-base/po/ro/base.po
index 955cff6500..86eaa6495d 100644
--- a/modules/luci-base/po/ro/base.po
+++ b/modules/luci-base/po/ro/base.po
@@ -722,6 +722,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2107,6 +2112,9 @@ msgstr "Notificare"
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2858,6 +2866,9 @@ msgstr "Marime"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr ""
@@ -3220,7 +3231,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/ru/base.po b/modules/luci-base/po/ru/base.po
index c0b53eb9d9..4ffb7233c2 100644
--- a/modules/luci-base/po/ru/base.po
+++ b/modules/luci-base/po/ru/base.po
@@ -778,6 +778,11 @@ msgid "Custom feeds"
msgstr "Список custom-ных feed-ов"
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2235,6 +2240,9 @@ msgstr "Заметка"
msgid "Nslookup"
msgstr "DNS-запрос"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -3043,6 +3051,9 @@ msgstr "Размер"
msgid "Size (.ipk)"
msgstr "Размер (.ipk)"
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Пропустить"
@@ -3471,10 +3482,10 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"Это локальный адрес, назначенный туннельным брокером, обычно заканчивается "
-"на <code>:2</code>."
+"на <code>...:2/64</code>."
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/po/sk/base.po b/modules/luci-base/po/sk/base.po
index ec72661dd2..a17ac98e20 100644
--- a/modules/luci-base/po/sk/base.po
+++ b/modules/luci-base/po/sk/base.po
@@ -705,6 +705,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2082,6 +2087,9 @@ msgstr ""
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr ""
@@ -2830,6 +2838,9 @@ msgstr ""
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr ""
@@ -3190,7 +3201,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/sv/base.po b/modules/luci-base/po/sv/base.po
index a7f906e819..089546a37d 100644
--- a/modules/luci-base/po/sv/base.po
+++ b/modules/luci-base/po/sv/base.po
@@ -719,6 +719,11 @@ msgid "Custom feeds"
msgstr "Anpassade flöden"
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2103,6 +2108,9 @@ msgstr "Avisering"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2853,6 +2861,9 @@ msgstr "Storlek"
msgid "Size (.ipk)"
msgstr "Storlek (.ipk)"
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Hoppa över"
@@ -3215,7 +3226,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/templates/base.pot b/modules/luci-base/po/templates/base.pot
index a8409213fe..de8b7fb22c 100644
--- a/modules/luci-base/po/templates/base.pot
+++ b/modules/luci-base/po/templates/base.pot
@@ -698,6 +698,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2075,6 +2080,9 @@ msgstr ""
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr ""
@@ -2823,6 +2831,9 @@ msgstr ""
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr ""
@@ -3183,7 +3194,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/tr/base.po b/modules/luci-base/po/tr/base.po
index 496d96f7c3..45f4a7c342 100644
--- a/modules/luci-base/po/tr/base.po
+++ b/modules/luci-base/po/tr/base.po
@@ -718,6 +718,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2095,6 +2100,9 @@ msgstr ""
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr ""
@@ -2843,6 +2851,9 @@ msgstr ""
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr ""
@@ -3203,7 +3214,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/uk/base.po b/modules/luci-base/po/uk/base.po
index 520bff481e..b1feed3d18 100644
--- a/modules/luci-base/po/uk/base.po
+++ b/modules/luci-base/po/uk/base.po
@@ -756,6 +756,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2191,6 +2196,9 @@ msgstr "Попередження"
msgid "Nslookup"
msgstr "DNS-запит"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK"
@@ -2973,6 +2981,9 @@ msgstr "Розмір"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "Пропустити"
@@ -3391,10 +3402,10 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
"Це локальна адреса кінцевої точки, присвоєна тунельним брокером, зазвичай "
-"закінчується на <code>:2</code>"
+"закінчується на <code>...:2/64</code>"
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/po/vi/base.po b/modules/luci-base/po/vi/base.po
index 2287dfba92..ecb369e13e 100644
--- a/modules/luci-base/po/vi/base.po
+++ b/modules/luci-base/po/vi/base.po
@@ -712,6 +712,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2112,6 +2117,9 @@ msgstr ""
msgid "Nslookup"
msgstr ""
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "OK "
@@ -2870,6 +2878,9 @@ msgstr "Dung lượng "
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr ""
@@ -3240,7 +3251,7 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
msgstr ""
msgid ""
diff --git a/modules/luci-base/po/zh-cn/base.po b/modules/luci-base/po/zh-cn/base.po
index c0a5351573..c76511b991 100644
--- a/modules/luci-base/po/zh-cn/base.po
+++ b/modules/luci-base/po/zh-cn/base.po
@@ -721,6 +721,12 @@ msgid "Custom feeds"
msgstr "自定义软件源"
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+"自定义文件(证书、脚本)会保留在系统上。若无需保留,请先执行恢复出厂设置。"
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr "自定义此设备的 <abbr title=\"Light Emitting Diode\">LED</abbr> 行为。"
@@ -2127,6 +2133,9 @@ msgstr "注意"
msgid "Nslookup"
msgstr "Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr "缓存的 DNS 条目数量(最大 10000,0 表示不缓存)"
+
msgid "OK"
msgstr "确认"
@@ -2900,6 +2909,9 @@ msgstr "大小"
msgid "Size (.ipk)"
msgstr "大小(.ipk)"
+msgid "Size of DNS query cache"
+msgstr "DNS 查询缓存的大小"
+
msgid "Skip"
msgstr "跳过"
@@ -3283,8 +3295,8 @@ msgstr "启动脚本插入到 'exit 0' 之前即可随系统启动运行。"
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
-msgstr "隧道代理分配的本地终端地址,通常以 <code>:2</code> 结尾"
+"ends with <code>...:2/64</code>"
+msgstr "隧道代理分配的本地终端地址,通常以 <code>...:2/64</code> 结尾"
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/po/zh-tw/base.po b/modules/luci-base/po/zh-tw/base.po
index d78223f2a5..28a806e839 100644
--- a/modules/luci-base/po/zh-tw/base.po
+++ b/modules/luci-base/po/zh-tw/base.po
@@ -723,6 +723,11 @@ msgid "Custom feeds"
msgstr ""
msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
msgstr ""
@@ -2119,6 +2124,9 @@ msgstr "通知"
msgid "Nslookup"
msgstr "DNS偵錯Nslookup"
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
msgid "OK"
msgstr "行"
@@ -2883,6 +2891,9 @@ msgstr "大小"
msgid "Size (.ipk)"
msgstr ""
+msgid "Size of DNS query cache"
+msgstr ""
+
msgid "Skip"
msgstr "跳過"
@@ -3275,8 +3286,8 @@ msgstr ""
msgid ""
"This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
-msgstr "這是由通道代理人指定的本地終端位址, 通常用 <code>:2</code>結尾."
+"ends with <code>...:2/64</code>"
+msgstr "這是由通道代理人指定的本地終端位址, 通常用 <code>...:2/64</code>結尾."
msgid ""
"This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json
new file mode 100644
index 0000000000..ed7ad8aa8a
--- /dev/null
+++ b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json
@@ -0,0 +1,11 @@
+{
+ "uci-access": {
+ "description": "Grant uci write access to all configurations",
+ "read": {
+ "uci": [ "*" ]
+ },
+ "write": {
+ "uci": [ "*" ]
+ }
+ }
+}
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
index 33f6a67038..ab6db4fefb 100644
--- a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
+++ b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
@@ -82,7 +82,7 @@ function index()
end
- page = entry({"admin", "network", "iface_add"}, cbi("admin_network/iface_add"), nil)
+ page = entry({"admin", "network", "iface_add"}, form("admin_network/iface_add"), nil)
page.leaf = true
page = entry({"admin", "network", "iface_delete"}, post("iface_delete"), nil)
@@ -289,7 +289,8 @@ function iface_reconnect(iface)
local netmd = require "luci.model.network".init()
local net = netmd:get_network(iface)
if net then
- luci.sys.call("env -i /sbin/ifup %q >/dev/null 2>/dev/null" % iface)
+ luci.sys.call("env -i /sbin/ifup %s >/dev/null 2>/dev/null"
+ % luci.util.shellquote(iface))
luci.http.status(200, "Reconnected")
return
end
@@ -301,7 +302,8 @@ function iface_shutdown(iface)
local netmd = require "luci.model.network".init()
local net = netmd:get_network(iface)
if net then
- luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface)
+ luci.sys.call("env -i /sbin/ifdown %s >/dev/null 2>/dev/null"
+ % luci.util.shellquote(iface))
luci.http.status(200, "Shutdown")
return
end
@@ -313,7 +315,8 @@ function iface_delete(iface)
local netmd = require "luci.model.network".init()
local net = netmd:del_network(iface)
if net then
- luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface)
+ luci.sys.call("env -i /sbin/ifdown %s >/dev/null 2>/dev/null"
+ % luci.util.shellquote(iface))
luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
netmd:commit("network")
netmd:commit("wireless")
@@ -389,7 +392,7 @@ function diag_command(cmd, addr)
if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
luci.http.prepare_content("text/plain")
- local util = io.popen(cmd % addr)
+ local util = io.popen(cmd % luci.util.shellquote(addr))
if util then
while true do
local ln = util:read("*l")
@@ -408,21 +411,21 @@ function diag_command(cmd, addr)
end
function diag_ping(addr)
- diag_command("ping -c 5 -W 1 %q 2>&1", addr)
+ diag_command("ping -c 5 -W 1 %s 2>&1", addr)
end
function diag_traceroute(addr)
- diag_command("traceroute -q 1 -w 1 -n %q 2>&1", addr)
+ diag_command("traceroute -q 1 -w 1 -n %s 2>&1", addr)
end
function diag_nslookup(addr)
- diag_command("nslookup %q 2>&1", addr)
+ diag_command("nslookup %s 2>&1", addr)
end
function diag_ping6(addr)
- diag_command("ping6 -c 5 %q 2>&1", addr)
+ diag_command("ping6 -c 5 %s 2>&1", addr)
end
function diag_traceroute6(addr)
- diag_command("traceroute6 -q 1 -w 2 -n %q 2>&1", addr)
+ diag_command("traceroute6 -q 1 -w 2 -n %s 2>&1", addr)
end
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua
index 22e1b7e173..4471fd597a 100644
--- a/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua
+++ b/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua
@@ -14,7 +14,7 @@ function index()
entry({"admin", "status", "routes"}, template("admin_status/routes"), _("Routes"), 3)
entry({"admin", "status", "syslog"}, call("action_syslog"), _("System Log"), 4)
entry({"admin", "status", "dmesg"}, call("action_dmesg"), _("Kernel Log"), 5)
- entry({"admin", "status", "processes"}, cbi("admin_status/processes"), _("Processes"), 6)
+ entry({"admin", "status", "processes"}, form("admin_status/processes"), _("Processes"), 6)
entry({"admin", "status", "realtime"}, alias("admin", "status", "realtime", "load"), _("Realtime Graphs"), 7)
@@ -62,7 +62,9 @@ end
function action_bandwidth(iface)
luci.http.prepare_content("application/json")
- local bwc = io.popen("luci-bwc -i %q 2>/dev/null" % iface)
+ local bwc = io.popen("luci-bwc -i %s 2>/dev/null"
+ % luci.util.shellquote(iface))
+
if bwc then
luci.http.write("[")
@@ -80,7 +82,9 @@ end
function action_wireless(iface)
luci.http.prepare_content("application/json")
- local bwc = io.popen("luci-bwc -r %q 2>/dev/null" % iface)
+ local bwc = io.popen("luci-bwc -r %s 2>/dev/null"
+ % luci.util.shellquote(iface))
+
if bwc then
luci.http.write("[")
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua
index 9c33d9c18b..ba317f9f4f 100644
--- a/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua
+++ b/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua
@@ -5,8 +5,8 @@
module("luci.controller.admin.uci", package.seeall)
function index()
- local redir = luci.http.formvalue("redir", true) or
- luci.dispatcher.build_url(unpack(luci.dispatcher.context.request))
+ local redir = luci.http.formvalue("redir", true)
+ or table.concat(luci.dispatcher.context.request, "/")
entry({"admin", "uci"}, nil, _("Configuration"))
entry({"admin", "uci", "changes"}, call("action_changes"), _("Changes"), 40).query = {redir=redir}
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 66d9942a11..fbde431df8 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
@@ -115,7 +115,7 @@ s:taboption("advanced", Flag, "nonegcache",
s:taboption("advanced", Value, "serversfile",
translate("Additional servers file"),
translate("This file may contain lines like 'server=/domain/1.2.3.4' or 'server=1.2.3.4' for"..
- "domain-specific or full upstream <abbr title=\"Domain Name System\">DNS</abbr> servers."))
+ "domain-specific or full upstream <abbr title=\"Domain Name System\">DNS</abbr> servers."))
s:taboption("advanced", Flag, "strictorder",
translate("Strict order"),
@@ -212,6 +212,12 @@ cq.optional = true
cq.datatype = "uinteger"
cq.placeholder = 150
+cs = s:taboption("advanced", Value, "cachesize",
+ translate("Size of DNS query cache"),
+ translate("Number of cached DNS entries (max is 10000, 0 is no caching)"))
+cs.optional = true
+cs.datatype = "range(0,10000)"
+cs.placeholder = 150
s:taboption("tftp", Flag, "enable_tftp",
translate("Enable TFTP server")).optional = true
@@ -274,7 +280,7 @@ s.anonymous = true
s.template = "cbi/tblsection"
name = s:option(Value, "name", translate("Hostname"))
-name.datatype = "hostname"
+name.datatype = "hostname('strict')"
name.rmempty = true
function name.write(self, section, value)
@@ -295,7 +301,7 @@ ip = s:option(Value, "ip", translate("<abbr title=\"Internet Protocol Version 4\
ip.datatype = "or(ip4addr,'ignore')"
time = s:option(Value, "leasetime", translate("Lease time"))
-time.rmempty = true
+time.rmempty = true
duid = s:option(Value, "duid", translate("<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>"))
duid.datatype = "and(rangelength(20,36),hexstring)"
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua
index 89a73a5ca8..b52dff13ac 100644
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua
+++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua
@@ -5,6 +5,7 @@
m = Map("network", translate("Switch"), translate("The network ports on this device can be combined to several <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s in which computers can communicate directly with each other. <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s are often used to separate different network segments. Often there is by default one Uplink port for a connection to the next greater network like the internet and other ports for a local network."))
local fs = require "nixio.fs"
+local ut = require "luci.util"
local nw = require "luci.model.network"
local switches = { }
@@ -74,7 +75,7 @@ m.uci:foreach("network", "switch",
end
-- Parse some common switch properties from swconfig help output.
- local swc = io.popen("swconfig dev %q help 2>/dev/null" % switch_name)
+ local swc = io.popen("swconfig dev %s help 2>/dev/null" % ut.shellquote(switch_name))
if swc then
local is_port_attr = false
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
index c0bb380307..a574d35979 100644
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
+++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
@@ -63,7 +63,7 @@ function m.parse(map)
Map.parse(map)
if m:get(wdev:name(), "type") == "mac80211" and new_cc and new_cc ~= old_cc then
- luci.sys.call("iw reg set %q" % new_cc)
+ luci.sys.call("iw reg set %s" % ut.shellquote(new_cc))
luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless", arg[1]))
return
end
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm b/modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm
index d5d78289be..88e0fffd9c 100644
--- a/modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm
+++ b/modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm
@@ -69,7 +69,7 @@ end
<% if querypat then %>
<div class="cbi-value">
<%:Displaying only packages containing%> <strong>"<%=pcdata(query)%>"</strong>
- <input type="button" onclick="location.href='?display=<%=pcdata(display)%>'" href="#" class="cbi-button cbi-button-reset" style="margin-left:1em" value="<%:Reset%>" />
+ <input type="button" onclick="location.href='?display=<%=luci.http.urlencode(display)%>'" href="#" class="cbi-button cbi-button-reset" style="margin-left:1em" value="<%:Reset%>" />
<br style="clear:both" />
</div>
<% end %>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm b/modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm
index c3373604f3..6e725c8888 100644
--- a/modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm
+++ b/modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm
@@ -16,9 +16,9 @@
<% end %>
<div class="cbi-page-actions">
- <% local r = luci.http.formvalue("redir"); if r and #r > 0 then %>
+ <% local node, url = luci.dispatcher.lookup(luci.http.formvalue("redir")); if url then %>
<div style="float:left">
- <form class="inline" method="get" action="<%=luci.util.pcdata(r)%>">
+ <form class="inline" method="get" action="<%=luci.util.pcdata(url)%>">
<input class="cbi-button cbi-button-link" style="float:left; margin:0" type="submit" value="<%:Back%>" />
</form>
</div>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm b/modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm
index 5da7281a80..20327adff3 100644
--- a/modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm
+++ b/modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm
@@ -18,10 +18,12 @@
<p><strong><%:There are no pending changes to revert!%></strong></p>
<% end %>
-<div class="cbi-page-actions">
- <form class="inline" method="get" action="<%=luci.util.pcdata(luci.http.formvalue("redir"))%>">
- <input class="cbi-button cbi-button-link" style="margin:0" type="submit" value="<%:Back%>" />
- </form>
-</div>
+<% local node, url = luci.dispatcher.lookup(luci.http.formvalue("redir")); if url then %>
+ <div class="cbi-page-actions">
+ <form class="inline" method="get" action="<%=luci.util.pcdata(url)%>">
+ <input class="cbi-button cbi-button-link" style="margin:0" type="submit" value="<%:Back%>" />
+ </form>
+ </div>
+<% end %>
<%+footer%>
diff --git a/modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm b/modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm
index 18be30be35..9f017c9e72 100644
--- a/modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm
+++ b/modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm
@@ -6,7 +6,7 @@
<script type="text/javascript" src="http://www.openstreetmap.org/openlayers/OpenStreetMap.js"></script>
<script type="text/javascript" src="osm.js"></script>
</head>
-<body onload="init();drawmap();" style="padding:0px; margin:0px">
+<body onload="init();drawmap();" style="padding:0px; margin:0px">
<div id="map"></div>
<div style="position:absolute; bottom:0%; width:100%; background:url('cbi/black_60.png'); font-size:10px; color:#fff;z-index:1000">
Map by <a href="http://www.openstreetmap.org" title="www.openstreetmap.org" style="color:#fff;" >openstreetmap.org</a>, License CC-BY-SA
@@ -16,5 +16,4 @@
Longitude: <input id="osmlon" name="osmlon" type="text" size="20" style="font-size:10px;">
</span>
</div>
-
</body>
diff --git a/modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua b/modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua
index e2291e5ca6..adad7508bc 100644
--- a/modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua
+++ b/modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua
@@ -77,7 +77,7 @@ function index()
page.order = 10
page = node("admin", "freifunk", "basics", "profile_expert")
- page.target = cbi("freifunk/profile_expert")
+ page.target = form("freifunk/profile_expert")
page.title = _("Profile (Expert)")
page.order = 20
diff --git a/modules/luci-mod-rpc/luasrc/controller/rpc.lua b/modules/luci-mod-rpc/luasrc/controller/rpc.lua
index 759bb749cf..3326d57a95 100644
--- a/modules/luci-mod-rpc/luasrc/controller/rpc.lua
+++ b/modules/luci-mod-rpc/luasrc/controller/rpc.lua
@@ -7,23 +7,45 @@ local pairs = pairs
local print = print
local pcall = pcall
local table = table
+local type = type
+local tonumber = tonumber
module "luci.controller.rpc"
-function index()
- local function authenticator(validator, accs)
- local auth = luci.http.formvalue("auth", true)
- if auth then -- if authentication token was given
- local sdat = (luci.util.ubus("session", "get", { ubus_rpc_session = auth }) or { }).values
- if sdat then -- if given token is valid
- if sdat.user and luci.util.contains(accs, sdat.user) then
- return sdat.user, auth
- end
- end
+
+local function session_retrieve(sid, allowed_users)
+ local util = require "luci.util"
+ local sdat = util.ubus("session", "get", {
+ ubus_rpc_session = sid
+ })
+
+ if type(sdat) == "table" and
+ type(sdat.values) == "table" and
+ type(sdat.values.token) == "string" and
+ type(sdat.values.secret) == "string" and
+ type(sdat.values.username) == "string" and
+ util.contains(allowed_users, sdat.values.username)
+ then
+ return sid, sdat.values
+ end
+
+ return nil
+end
+
+local function authenticator(validator, accs)
+ local auth = luci.http.formvalue("auth", true)
+ or luci.http.getcookie("sysauth")
+
+ if auth then -- if authentication token was given
+ local sid, sdat = session_retrieve(auth, accs)
+ if sdat then -- if given token is valid
+ return sdat.username, sid
end
luci.http.status(403, "Forbidden")
end
+end
+function index()
local rpc = node("rpc")
rpc.sysauth = "root"
rpc.sysauth_authenticator = authenticator
@@ -43,39 +65,48 @@ function rpc_auth()
local ltn12 = require "luci.ltn12"
local util = require "luci.util"
- local loginstat
-
local server = {}
server.challenge = function(user, pass)
- local sid, token, secret
-
local config = require "luci.config"
-
- if sys.user.checkpasswd(user, pass) then
- local sdat = util.ubus("session", "create", { timeout = config.sauth.sessiontime })
+ local login = util.ubus("session", "login", {
+ username = user,
+ password = pass,
+ timeout = tonumber(config.sauth.sessiontime)
+ })
+
+ if type(login) == "table" and
+ type(login.ubus_rpc_session) == "string"
+ then
+ util.ubus("session", "set", {
+ ubus_rpc_session = login.ubus_rpc_session,
+ values = {
+ token = sys.uniqueid(16),
+ secret = sys.uniqueid(16)
+ }
+ })
+
+ local sid, sdat = session_retrieve(login.ubus_rpc_session, { user })
if sdat then
- sid = sdat.ubus_rpc_session
- token = sys.uniqueid(16)
- secret = sys.uniqueid(16)
-
- http.header("Set-Cookie", "sysauth="..sid.."; path=/")
- util.ubus("session", "set", {
- ubus_rpc_session = sid,
- values = {
- user = user,
- token = token,
- secret = secret
- }
- })
+ return {
+ sid = sid,
+ token = sdat.token,
+ secret = sdat.secret
+ }
end
end
- return sid and {sid=sid, token=token, secret=secret}
+ return nil
end
server.login = function(...)
local challenge = server.challenge(...)
- return challenge and challenge.sid
+ if challenge then
+ http.header("Set-Cookie", 'sysauth=%s; path=%s' %{
+ challenge.sid,
+ http.getenv("SCRIPT_NAME")
+ })
+ return challenge.sid
+ end
end
http.prepare_content("application/json")