* luci-0.8: backport library fixes

This commit is contained in:
Jo-Philipp Wich 2008-10-29 19:41:33 +00:00
parent 8a690a0614
commit bb63ae4647
16 changed files with 272 additions and 79 deletions

View file

@ -167,3 +167,13 @@ function cbi_combobox_init(id, values, def, man) {
});
cbi_combobox(id, values, def, man);
}
function cbi_filebrowser(id, url, defpath) {
var field = document.getElementById(id);
var browser = window.open(
url + ( field.value || defpath || '' ) + '?field=' + id,
"luci_filebrowser", "width=300,height=400,left=100,top=200,scrollbars=yes"
);
browser.focus();
}

View file

@ -30,6 +30,7 @@ require("luci.template")
require("luci.util")
require("luci.http")
require("luci.uvl")
require("luci.fs")
local uci = require("luci.model.uci")
local class = luci.util.class
@ -38,6 +39,7 @@ local instanceof = luci.util.instanceof
FORM_NODATA = 0
FORM_VALID = 1
FORM_INVALID = -1
FORM_CHANGED = 2
AUTO = true
@ -51,6 +53,7 @@ function load(cbimap, ...)
require("luci.config")
require("luci.util")
local upldir = "/lib/uci/upload/"
local cbidir = luci.util.libpath() .. "/model/cbi/"
local func, err = loadfile(cbimap) or loadfile(cbidir..cbimap..".lua")
assert(func, err)
@ -69,7 +72,9 @@ function load(cbimap, ...)
return rawget(tbl, key) or _M[key] or _G[key]
end}))
local maps = {func()}
local maps = { func() }
local uploads = { }
local has_upload = false
for i, map in ipairs(maps) do
if not instanceof(map, Node) then
@ -77,9 +82,58 @@ function load(cbimap, ...)
return nil
else
map:prepare()
if map.upload_fields then
has_upload = true
for _, field in ipairs(map.upload_fields) do
uploads[
field.config .. '.' ..
field.section.sectiontype .. '.' ..
field.option
] = true
end
end
end
end
if has_upload then
local uci = luci.model.uci.cursor()
local prm = luci.http.context.request.message.params
local fd, cbid
luci.http.setfilehandler(
function( field, chunk, eof )
if not field then return end
if field.name and not cbid then
local c, s, o = field.name:gmatch(
"cbid%.([^%.]+)%.([^%.]+)%.([^%.]+)"
)()
if c and s and o then
local t = uci:get( c, s )
if t and uploads[c.."."..t.."."..o] then
local path = upldir .. field.name
fd = io.open(path, "w")
if fd then
cbid = field.name
prm[cbid] = path
end
end
end
end
if field.name == cbid and fd then
fd:write(chunk)
end
if eof and fd then
fd:close()
fd = nil
cbid = nil
end
end
)
end
return maps
end
@ -251,6 +305,9 @@ function Map.get_scheme(self, sectiontype, option)
end
end
function Map.submitstate(self)
return luci.http.formvalue("cbi.submit")
end
-- Chain foreign config
function Map.chain(self, config)
@ -288,6 +345,19 @@ function Map.parse(self)
for i, config in ipairs(self.parsechain) do
self.uci:unload(config)
end
if type(self.commit_handler) == "function" then
self:commit_handler(self:submitstate())
end
end
if self:submitstate() then
if self.save then
return self.changed and FORM_CHANGED or FORM_VALID
else
return FORM_INVALID
end
else
return FORM_NODATA
end
end
@ -383,11 +453,12 @@ function SimpleForm.parse(self, ...)
end
local state =
not luci.http.formvalue("cbi.submit") and 0
or valid and 1
or -1
not self:submitstate() and FORM_NODATA
or valid and FORM_VALID
or FORM_INVALID
self.dorender = not self.handle or self:handle(state, self.data) ~= false
return state
end
function SimpleForm.render(self, ...)
@ -396,6 +467,10 @@ function SimpleForm.render(self, ...)
end
end
function SimpleForm.submitstate(self)
return luci.http.formvalue("cbi.submit")
end
function SimpleForm.section(self, class, ...)
if instanceof(class, AbstractSection) then
local obj = class(self, ...)
@ -615,6 +690,10 @@ function Table.__init__(self, form, data, ...)
function datasource.get(self, section, option)
return data[section] and data[section][option]
end
function datasource.submitstate(self)
return luci.http.formvalue("cbi.submit")
end
function datasource.del(...)
return true
@ -632,7 +711,7 @@ end
function Table.parse(self)
for i, k in ipairs(self:cfgsections()) do
if luci.http.formvalue("cbi.submit") then
if self.map:submitstate() then
Node.parse(self, k)
end
end
@ -695,7 +774,7 @@ function NamedSection.parse(self, novld)
if active then
AbstractSection.parse_dynamic(self, s)
if luci.http.formvalue("cbi.submit") then
if self.map:submitstate() then
Node.parse(self, s)
if not novld and not self.override_scheme and self.map.scheme then
@ -770,7 +849,7 @@ function TypedSection.parse(self, novld)
local co
for i, k in ipairs(self:cfgsections()) do
AbstractSection.parse_dynamic(self, k)
if luci.http.formvalue("cbi.submit") then
if self.map:submitstate() then
Node.parse(self, k)
if not novld and not self.override_scheme and self.map.scheme then
@ -1325,3 +1404,58 @@ function Button.__init__(self, ...)
self.inputstyle = nil
self.rmempty = true
end
FileUpload = class(AbstractValue)
function FileUpload.__init__(self, ...)
AbstractValue.__init__(self, ...)
self.template = "cbi/upload"
if not self.map.upload_fields then
self.map.upload_fields = { self }
else
self.map.upload_fields[#self.map.upload_fields+1] = self
end
end
function FileUpload.formcreated(self, section)
return AbstractValue.formcreated(self, section) or
luci.http.formvalue("cbi.rlf."..section.."."..self.option) or
luci.http.formvalue("cbi.rlf."..section.."."..self.option..".x")
end
function FileUpload.cfgvalue(self, section)
local val = AbstractValue.cfgvalue(self, section)
if val and luci.fs.access(val) then
return val
end
return nil
end
function FileUpload.formvalue(self, section)
local val = AbstractValue.formvalue(self, section)
if val then
if not luci.http.formvalue("cbi.rlf."..section.."."..self.option) and
not luci.http.formvalue("cbi.rlf."..section.."."..self.option..".x")
then
return val
end
luci.fs.unlink(val)
self.value = nil
end
return nil
end
function FileUpload.remove(self, section)
local val = AbstractValue.formvalue(self, section)
if val and luci.fs.access(val) then luci.fs.unlink(val) end
return AbstractValue.remove(self, section)
end
FileBrowser = class(AbstractValue)
function FileBrowser.__init__(self, ...)
AbstractValue.__init__(self, ...)
self.template = "cbi/browser"
end

View file

@ -14,7 +14,7 @@ $Id$
-%>
<%+cbi/valueheader%>
<% if self:cfgvalue(section) ~= false then %>
<input class="cbi-input-<% self.inputstyle or "button" %>" type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.title)%> />
<input class="cbi-input-<%=self.inputstyle or "button" %>" type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.title)%> />
<% else %>
-
<% end %>

View file

@ -13,7 +13,7 @@ $Id$
-%>
<div>
<div class="cbi-page-actions">
<input class="cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="<%:saveapply%>" />
<input class="cbi-button cbi-button-save" type="submit" value="<%:save%>" />
<input class="cbi-button cbi-button-reset" type="reset" value="<%:reset%>" />

View file

@ -14,7 +14,7 @@ $Id$
-%>
<%+header%>
<form method="post" action="<%=luci.http.getenv("REQUEST_URI")%>">
<form method="post" action="<%=luci.http.getenv("REQUEST_URI")%>" enctype="multipart/form-data">
<div>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<input type="hidden" name="cbi.submit" value="1" />

View file

@ -32,6 +32,7 @@ $Id$
<br />
</fieldset>
<% elseif self.addremove then %>
<% if self.template_addremove then include(self.template_addremove) else -%>
<fieldset class="cbi-section" id="cbi-<%=self.config%>-<%=self.section%>">
<% if self.title and #self.title > 0 then -%>
<legend><%=self.title%></legend>
@ -39,5 +40,6 @@ $Id$
<div class="cbi-section-descr"><%=self.description%></div>
<input type="submit" class="cbi-button-add" name="cbi.cns.<%=self.config%>.<%=self.section%>" value="<%:cbi_add%>" />
</fieldset>
<%- end %>
<% end %>
<!-- /nsection -->

View file

@ -41,6 +41,7 @@ $Id$
<%- end %>
<% if self.addremove then -%>
<% if self.template_addremove then include(self.template_addremove) else -%>
<div class="cbi-section-create">
<% if self.anonymous then -%>
<input type="submit" class="cbi-button cbi-button-add" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>" value="<%:cbi_add%>" />
@ -53,5 +54,6 @@ $Id$
<%- end %>
<%- end %>
</div>
<%- end %>
<%- end %>
</fieldset>

View file

@ -33,7 +33,6 @@ local string = require "string"
local coroutine = require "coroutine"
local getmetatable, setmetatable = getmetatable, setmetatable
local getfenv, setfenv = getfenv, setfenv
local rawget, rawset, unpack = rawget, rawset, unpack
local tostring, type, assert = tostring, type, assert
local ipairs, pairs, loadstring = ipairs, pairs, loadstring

View file

@ -131,7 +131,7 @@ function urlencode_params( tbl )
return enc
end
--- (Internal function)
-- (Internal function)
-- Initialize given parameter and coerce string into table when the parameter
-- already exists.
-- @param tbl Table where parameter should be created
@ -147,7 +147,7 @@ local function __initval( tbl, key )
end
end
--- (Internal function)
-- (Internal function)
-- Append given data to given parameter, either by extending the string value
-- or by appending it to the last string in the parameter's value table.
-- @param tbl Table containing the previously initialized parameter value
@ -163,7 +163,7 @@ local function __appendval( tbl, key, chunk )
end
end
--- (Internal function)
-- (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.
@ -563,12 +563,14 @@ function parse_message_header( src )
-- Populate common environment variables
msg.env = {
CONTENT_LENGTH = msg.headers['Content-Length'];
CONTENT_TYPE = msg.headers['Content-Type'];
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)
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
@ -617,7 +619,7 @@ function parse_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 == "application/x-www-form-urlencoded"
msg.env.CONTENT_TYPE:match("^application/x%-www%-form%-urlencoded")
then
return urldecode_message_body( src, msg, filecb )

View file

@ -118,7 +118,7 @@ function if_none_match( req, stat )
return true
end
-- 14.27 / If-Range
--- 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.
@ -131,7 +131,7 @@ function if_range( req, stat )
return false, 412
end
-- 14.28 / If-Unmodified-Since
--- 14.28 / If-Unmodified-Since
-- Test whether the given message object contains an "If-Unmodified-Since"
-- header and compare it against the given stat object.
-- @param req HTTP request message object

View file

@ -36,7 +36,7 @@ $(BOA_DIR)/.configured: $(BOA_DIR)/.patched
touch $@
boa-compile: $(BOA_DIR)/.configured
$(MAKE) -C $(BOA_DIR)/src CC=$(CC) CFLAGS="$(CFLAGS)"
$(MAKE) -C $(BOA_DIR)/src CC=$(CC) CFLAGS="$(CFLAGS) -DINET6 -DACCEPT_ON -DWHEN_DOES_THIS_APPLY"
%.o: %.c
$(COMPILE) $(LUA_CFLAGS) -I$(BOA_DIR)/src $(FPIC) -c -o $@ $<

View file

@ -59,6 +59,7 @@ function handle_req(context)
env.REMOTE_PORT = context.remote_port
env.SERVER_ADDR = context.server_addr
env.HTTP_COOKIE = context.cookie
env.HTTP_ACCEPT = context.http_accept
env.SCRIPT_NAME = env.REQUEST_URI:sub(1, #env.REQUEST_URI - #env.PATH_INFO)
luci.sgi.webuci.run(env, vars)

View file

@ -267,6 +267,15 @@ config variable
option datatype 'string'
option required false
# Variable default value (schema.@variable.default)
config variable
option name 'default'
option title 'Default value of this variable'
option section 'schema.variable'
option type 'variable'
option datatype 'string'
option required false
# Variable validators (schema.@variable.validator)
config variable
option name 'validator'

View file

@ -82,17 +82,17 @@ end
function authenticator.htmlauth(validator, accs, default)
local user = luci.http.formvalue("username")
local pass = luci.http.formvalue("password")
if user and validator(user, pass) then
return user
end
require("luci.i18n")
require("luci.template")
context.path = {}
luci.template.render("sysauth", {duser=default, fuser=user})
return false
end
--- Dispatch an HTTP request.
@ -110,7 +110,7 @@ function httpdispatch(request)
if not stat then
error500(err)
end
luci.http.close()
--context._disable_memtrace()
@ -122,15 +122,15 @@ function dispatch(request)
--context._disable_memtrace = require "luci.debug".trap_memtrace()
local ctx = context
ctx.path = request
require "luci.i18n".setlanguage(require "luci.config".main.lang)
local c = ctx.tree
local stat
if not c then
c = createtree()
end
local track = {}
local args = {}
context.args = args
@ -144,7 +144,7 @@ function dispatch(request)
end
util.update(track, c)
if c.leaf then
break
end
@ -159,11 +159,11 @@ function dispatch(request)
if track.i18n then
require("luci.i18n").loadc(track.i18n)
end
-- Init template engine
if not track.notemplate then
if (c and c.index) or not track.notemplate then
local tpl = require("luci.template")
local media = luci.config.main.mediaurlbase
local media = track.mediaurlbase or luci.config.main.mediaurlbase
if not pcall(tpl.Template, "themes/%s/header" % fs.basename(media)) then
media = nil
for name, theme in pairs(luci.config.themes) do
@ -183,26 +183,27 @@ function dispatch(request)
viewns.striptags = util.striptags
viewns.controller = luci.http.getenv("SCRIPT_NAME")
viewns.media = media
viewns.theme = fs.basename(media)
viewns.resource = luci.config.main.resourcebase
viewns.REQUEST_URI = (luci.http.getenv("SCRIPT_NAME") or "") .. (luci.http.getenv("PATH_INFO") or "")
end
track.dependent = (track.dependent ~= false)
assert(not track.dependent or not track.auto, "Access Violation")
if track.sysauth then
local sauth = require "luci.sauth"
local authen = type(track.sysauth_authenticator) == "function"
and track.sysauth_authenticator
or authenticator[track.sysauth_authenticator]
local def = (type(track.sysauth) == "string") and track.sysauth
local accs = def and {track.sysauth} or track.sysauth
local sess = ctx.authsession or luci.http.getcookie("sysauth")
sess = sess and sess:match("^[A-F0-9]+$")
local user = sauth.read(sess)
if not util.contains(accs, user) then
if authen then
local user, sess = authen(luci.sys.user.checkpasswd, accs, def)
@ -231,21 +232,32 @@ function dispatch(request)
luci.sys.process.setuser(track.setuser)
end
if c and (c.index or type(c.target) == "function") then
ctx.dispatched = c
ctx.requested = ctx.requested or ctx.dispatched
end
if c and c.index then
local tpl = require "luci.template"
if util.copcall(tpl.render, "indexer", {}) then
return true
end
end
if c and type(c.target) == "function" then
context.dispatched = c
util.copcall(function()
local oldenv = getfenv(c.target)
local module = require(c.module)
local env = setmetatable({}, {__index=
function(tbl, key)
return rawget(tbl, key) or module[key] or oldenv[key]
return rawget(tbl, key) or module[key] or oldenv[key]
end})
setfenv(c.target, env)
end)
c.target(unpack(args))
else
error404()
@ -256,7 +268,7 @@ end
function createindex()
local path = luci.util.libpath() .. "/controller/"
local suff = ".lua"
if luci.util.copcall(require, "luci.fastindex") then
createindex_fastindex(path, suff)
else
@ -269,14 +281,14 @@ end
-- @param suffix Controller file suffix
function createindex_fastindex(path, suffix)
index = {}
if not fi then
fi = luci.fastindex.new("index")
fi.add(path .. "*" .. suffix)
fi.add(path .. "*/*" .. suffix)
end
fi.scan()
for k, v in pairs(fi.indexes) do
index[v[2]] = v[1]
end
@ -298,9 +310,9 @@ function createindex_plain(path, suffix)
index = loadfile(indexcache)()
return index
end
end
end
index = {}
local controllers = util.combine(
@ -312,12 +324,12 @@ function createindex_plain(path, suffix)
local module = "luci.controller." .. c:sub(#path+1, #c-#suffix):gsub("/", ".")
local mod = require(module)
local idx = mod.index
if type(idx) == "function" then
index[module] = idx
end
end
if indexcache then
fs.writefile(indexcache, util.get_bytecode(index))
fs.chmod(indexcache, "a-rwx,u+rw")
@ -330,16 +342,16 @@ function createtree()
if not index then
createindex()
end
local ctx = context
local tree = {nodes={}}
ctx.treecache = setmetatable({}, {__mode="v"})
ctx.tree = tree
-- Load default translation
require "luci.i18n".loadc("default")
local scope = setmetatable({}, {__index = luci.dispatcher})
for k, v in pairs(index) do
@ -347,7 +359,7 @@ function createtree()
setfenv(v, scope)
v()
end
return tree
end
@ -361,24 +373,24 @@ function assign(path, clone, title, order)
local obj = node(unpack(path))
obj.nodes = nil
obj.module = nil
obj.title = title
obj.order = order
setmetatable(obj, {__index = _create_node(clone)})
return obj
end
--- Create a new dispatching node and define common parameters.
-- @param path Virtual path
-- @param target Target function to call when dispatched.
-- @param target Target function to call when dispatched.
-- @param title Destination node title
-- @param order Destination node order value (optional)
-- @return Dispatching tree node
function entry(path, target, title, order)
local c = node(unpack(path))
c.target = target
c.title = title
c.order = order
@ -404,19 +416,19 @@ function _create_node(path, cache)
if #path == 0 then
return context.tree
end
cache = cache or context.treecache
local name = table.concat(path, ".")
local c = cache[name]
if not c then
local last = table.remove(path)
c = _create_node(path, cache)
local new = {nodes={}, auto=true}
c.nodes[last] = new
cache[name] = new
return new
else
return c
@ -440,24 +452,30 @@ end
function rewrite(n, ...)
local req = arg
return function()
for i=1,n do
for i=1,n do
table.remove(context.path, 1)
end
for i,r in ipairs(req) do
table.insert(context.path, i, r)
end
dispatch()
end
end
--- Create a function-call dispatching target.
-- @param name Target function of local controller
-- @param name Target function of local controller
-- @param ... Additional parameters passed to the function
function call(name, ...)
local argv = {...}
return function() return getfenv()[name](unpack(argv)) end
return function(...)
if #argv > 0 then
return getfenv()[name](unpack(argv), ...)
else
return getfenv()[name](...)
end
end
end
--- Create a template render dispatching target.
@ -475,13 +493,20 @@ function cbi(model)
return function(...)
require("luci.cbi")
require("luci.template")
local http = require "luci.http"
maps = luci.cbi.load(model, ...)
local state = nil
for i, res in ipairs(maps) do
res:parse()
local cstate = res:parse()
if not state or cstate < state then
state = cstate
end
end
http.header("X-CBI-State", state or 0)
luci.template.render("cbi/header")
for i, res in ipairs(maps) do
res:render()
@ -496,13 +521,20 @@ function form(model)
return function(...)
require("luci.cbi")
require("luci.template")
local http = require "luci.http"
maps = luci.cbi.load(model, ...)
local state = nil
for i, res in ipairs(maps) do
res:parse()
local cstate = res:parse()
if not state or cstate < state then
state = cstate
end
end
http.header("X-CBI-State", state or 0)
luci.template.render("header")
for i, res in ipairs(maps) do
res:render()

View file

@ -192,14 +192,16 @@ end
--- Set the mime type of following content data.
-- @param mime Mimetype of following content
function prepare_content(mime)
if mime == "application/xhtml+xml" then
if not getenv("HTTP_ACCEPT") or
not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then
mime = "text/html; charset=UTF-8"
if not context.headers or not context.headers["content-type"] then
if mime == "application/xhtml+xml" then
if not getenv("HTTP_ACCEPT") or
not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then
mime = "text/html; charset=UTF-8"
end
header("Vary", "Accept")
end
header("Vary", "Accept")
header("Content-Type", mime)
end
header("Content-Type", mime)
end
--- Get the RAW HTTP input source

View file

@ -12,9 +12,9 @@ Copyright 2008 Steven Barth <steven@midlink.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@ -45,7 +45,7 @@ end
-- @param force Force reload even if already loaded (optional)
-- @return Success status
function load(file, lang, force)
lang = lang or ""
lang = lang and lang:gsub("_", "-") or ""
if force or not loaded[lang] or not loaded[lang][file] then
local f = loadfile(i18ndir .. file .. "." .. lang .. ".lua")
if f then
@ -75,7 +75,7 @@ end
--- Set the context default translation language.
-- @param lang Two-letter language code
function setlanguage(lang)
context.lang = lang
context.lang = lang:gsub("_", "-")
end
--- Return the translated value for a specific translation key.
@ -95,4 +95,4 @@ end
-- @return Translated and formatted string
function translatef(key, default, ...)
return translate(key, default):format(...)
end
end